summaryrefslogtreecommitdiff
path: root/lib/hipe/x86/hipe_x86_assemble.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/x86/hipe_x86_assemble.erl')
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl1004
1 files changed, 0 insertions, 1004 deletions
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
deleted file mode 100644
index 9d2586a14d..0000000000
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ /dev/null
@@ -1,1004 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%
-%%% Licensed under the Apache License, Version 2.0 (the "License");
-%%% you may not use this file except in compliance with the License.
-%%% You may obtain a copy of the License at
-%%%
-%%% http://www.apache.org/licenses/LICENSE-2.0
-%%%
-%%% Unless required by applicable law or agreed to in writing, software
-%%% distributed under the License is distributed on an "AS IS" BASIS,
-%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%%% See the License for the specific language governing permissions and
-%%% limitations under the License.
-%%%
-%%% HiPE/x86 assembler
-%%%
-%%% TODO:
-%%% - Simplify combine_label_maps and mk_data_relocs.
-
--ifdef(HIPE_AMD64).
--define(HIPE_X86_ASSEMBLE, hipe_amd64_assemble).
--define(HIPE_X86_ENCODE, hipe_amd64_encode).
--define(HIPE_X86_REGISTERS, hipe_amd64_registers).
--define(HIPE_X86_PP, hipe_amd64_pp).
--ifdef(AMD64_SIMULATE_NSP).
--define(X86_SIMULATE_NSP, ?AMD64_SIMULATE_NSP).
--endif.
--define(EAX, rax).
--define(REGArch, reg64).
--define(RMArch, rm64).
--define(EA_DISP32_ABSOLUTE, ea_disp32_sindex).
--else.
--define(HIPE_X86_ASSEMBLE, hipe_x86_assemble).
--define(HIPE_X86_ENCODE, hipe_x86_encode).
--define(HIPE_X86_REGISTERS, hipe_x86_registers).
--define(HIPE_X86_PP, hipe_x86_pp).
--define(EAX, eax).
--define(REGArch, reg32).
--define(RMArch, rm32).
--define(EA_DISP32_ABSOLUTE, ea_disp32).
--endif.
-
--module(?HIPE_X86_ASSEMBLE).
--export([assemble/4]).
-
--define(DEBUG,true).
-
--include("../main/hipe.hrl").
--include("../x86/hipe_x86.hrl").
--include("../../kernel/src/hipe_ext_format.hrl").
--include("../rtl/hipe_literals.hrl").
--include("../misc/hipe_sdi.hrl").
--undef(ASSERT).
--define(ASSERT(G), if G -> [] ; true -> exit({assertion_failed,?MODULE,?LINE,??G}) end).
-
-assemble(CompiledCode, Closures, Exports, Options) ->
- ?when_option(time, Options, ?start_timer("x86 assembler")),
- print("****************** Assembling *******************\n", [], Options),
- %%
- Code = [{MFA,
- hipe_x86:defun_code(Defun),
- hipe_x86:defun_data(Defun)}
- || {MFA, Defun} <- CompiledCode],
- %%
- {ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
- hipe_pack_constants:pack_constants(Code),
- %%
- {CodeSize,CodeBinary,AccRefs,LabelMap,ExportMap} =
- encode(translate(Code, ConstMap, Options), Options),
- print("Total num bytes=~w\n", [CodeSize], Options),
- %% put(code_size, CodeSize),
- %% put(const_size, ConstSize),
- %% ?when_option(verbose, Options,
- %% ?debug_msg("Constants are ~w bytes\n",[ConstSize])),
- %%
- SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
- SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
- Bin = term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM},
- ConstAlign, ConstSize,
- SC,
- DataRelocs, % nee LM, LabelMap
- SSE,
- CodeSize,CodeBinary,SlimRefs,
- 0,[] % ColdCodeSize, SlimColdRefs
- ]),
- %%
- %% ?when_option(time, Options, ?stop_timer("x86 assembler")),
- Bin.
-
-%%%
-%%% Assembly Pass 1.
-%%% Process initial {MFA,Code,Data} list.
-%%% Translate each MFA's body, choosing operand & instruction kinds.
-%%%
-%%% Assembly Pass 2.
-%%% Perform short/long form optimisation for jumps.
-%%% Build LabelMap for each MFA.
-%%%
-%%% Result is {MFA,NewCode,CodeSize,LabelMap} list.
-%%%
-
-translate(Code, ConstMap, Options) ->
- translate_mfas(Code, ConstMap, [], Options).
-
-translate_mfas([{MFA,Insns,_Data}|Code], ConstMap, NewCode, Options) ->
- {NewInsns,CodeSize,LabelMap} =
- translate_insns(Insns, {MFA,ConstMap}, hipe_sdi:pass1_init(), 0, [], Options),
- translate_mfas(Code, ConstMap, [{MFA,NewInsns,CodeSize,LabelMap}|NewCode], Options);
-translate_mfas([], _ConstMap, NewCode, _Options) ->
- lists:reverse(NewCode).
-
-translate_insns([I|Insns], Context, SdiPass1, Address, NewInsns, Options) ->
- NewIs = translate_insn(I, Context, Options),
- add_insns(NewIs, Insns, Context, SdiPass1, Address, NewInsns, Options);
-translate_insns([], _Context, SdiPass1, Address, NewInsns, _Options) ->
- {LabelMap,CodeSizeIncr} = hipe_sdi:pass2(SdiPass1),
- {lists:reverse(NewInsns), Address+CodeSizeIncr, LabelMap}.
-
-add_insns([I|Is], Insns, Context, SdiPass1, Address, NewInsns, Options) ->
- NewSdiPass1 =
- case I of
- {'.label',L,_} ->
- hipe_sdi:pass1_add_label(SdiPass1, Address, L);
- {jcc_sdi,{_,{label,L}},_} ->
- SdiInfo = #sdi_info{incr=(6-2),lb=(-128)+2,ub=127+2},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo);
- {jmp_sdi,{{label,L}},_} ->
- SdiInfo = #sdi_info{incr=(5-2),lb=(-128)+2,ub=127+2},
- hipe_sdi:pass1_add_sdi(SdiPass1, Address, L, SdiInfo);
- _ ->
- SdiPass1
- end,
- Address1 = Address + insn_size(I),
- add_insns(Is, Insns, Context, NewSdiPass1, Address1, [I|NewInsns], Options);
-add_insns([], Insns, Context, SdiPass1, Address, NewInsns, Options) ->
- translate_insns(Insns, Context, SdiPass1, Address, NewInsns, Options).
-
-insn_size(I) ->
- case I of
- {'.label',_,_} -> 0;
- {'.sdesc',_,_} -> 0;
- {jcc_sdi,_,_} -> 2;
- {jmp_sdi,_,_} -> 2;
- {Op,Arg,_Orig} -> ?HIPE_X86_ENCODE:insn_sizeof(Op, Arg)
- end.
-
-translate_insn(I, Context, Options) ->
- case I of
- #alu{aluop='xor', src=#x86_temp{reg=Reg}=Src, dst=#x86_temp{reg=Reg}=Dst} ->
- [{'xor', {temp_to_reg32(Dst), temp_to_rm32(Src)}, I}];
- #alu{} ->
- Arg = resolve_alu_args(hipe_x86:alu_src(I), hipe_x86:alu_dst(I), Context),
- [{hipe_x86:alu_op(I), Arg, I}];
- #call{} ->
- translate_call(I);
- #cmovcc{} ->
- {Dst,Src} = resolve_move_args(
- hipe_x86:cmovcc_src(I), hipe_x86:cmovcc_dst(I),
- Context),
- CC = {cc,?HIPE_X86_ENCODE:cc(hipe_x86:cmovcc_cc(I))},
- Arg = {CC,Dst,Src},
- [{cmovcc, Arg, I}];
- #cmp{} ->
- Arg = resolve_alu_args(hipe_x86:cmp_src(I), hipe_x86:cmp_dst(I), Context),
- [{cmp, Arg, I}];
- #comment{} ->
- [];
- #fmove{} ->
- {Op,Arg} = resolve_sse2_fmove_args(hipe_x86:fmove_src(I),
- hipe_x86:fmove_dst(I)),
- [{Op, Arg, I}];
- #fp_binop{} ->
- case proplists:get_bool(x87, Options) of
- true -> % x87
- Arg = resolve_x87_binop_args(hipe_x86:fp_binop_src(I),
- hipe_x86:fp_binop_dst(I)),
- [{hipe_x86:fp_binop_op(I), Arg, I}];
- false -> % sse2
- Arg = resolve_sse2_binop_args(hipe_x86:fp_binop_src(I),
- hipe_x86:fp_binop_dst(I)),
- [{resolve_sse2_op(hipe_x86:fp_binop_op(I)), Arg, I}]
- end;
- #fp_unop{} ->
- case proplists:get_bool(x87, Options) of
- true -> % x87
- Arg = resolve_x87_unop_arg(hipe_x86:fp_unop_arg(I)),
- [{hipe_x86:fp_unop_op(I), Arg, I}];
- false -> % sse2
- case hipe_x86:fp_unop_op(I) of
- 'fchs' ->
- Arg = resolve_sse2_fchs_arg(hipe_x86:fp_unop_arg(I)),
- [{'xorpd', Arg, I}];
- 'fwait' -> % no op on sse2, magic on x87
- []
- end
- end;
- #imul{} ->
- translate_imul(I, Context);
- #jcc{} ->
- Cc = {cc,?HIPE_X86_ENCODE:cc(hipe_x86:jcc_cc(I))},
- Label = translate_label(hipe_x86:jcc_label(I)),
- [{jcc_sdi, {Cc,Label}, I}];
- #jmp_fun{} ->
- %% call and jmp are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case hipe_x86:jmp_fun_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- Arg = translate_fun(hipe_x86:jmp_fun_fun(I), PatchTypeExt),
- [{jmp, {Arg}, I}];
- #jmp_label{} ->
- Arg = translate_label(hipe_x86:jmp_label_label(I)),
- [{jmp_sdi, {Arg}, I}];
- #jmp_switch{} ->
- RM32 = resolve_jmp_switch_arg(I, Context),
- [{jmp, {RM32}, I}];
- #label{} ->
- [{'.label', hipe_x86:label_label(I), I}];
- #lea{} ->
- Arg = resolve_lea_args(hipe_x86:lea_mem(I), hipe_x86:lea_temp(I)),
- [{lea, Arg, I}];
- #move{} ->
- Arg = resolve_move_args(hipe_x86:move_src(I), hipe_x86:move_dst(I),
- Context),
- [{mov, Arg, I}];
- #move64{} ->
- translate_move64(I, Context);
- #movsx{} ->
- Src = resolve_movx_src(hipe_x86:movsx_src(I)),
- [{movsx, {temp_to_regArch(hipe_x86:movsx_dst(I)), Src}, I}];
- #movzx{} ->
- Src = resolve_movx_src(hipe_x86:movzx_src(I)),
- [{movzx, {temp_to_reg32(hipe_x86:movzx_dst(I)), Src}, I}];
- %% pseudo_call: eliminated before assembly
- %% pseudo_jcc: eliminated before assembly
- %% pseudo_tailcall: eliminated before assembly
- %% pseudo_tailcall_prepare: eliminated before assembly
- #pop{} ->
- Arg = translate_dst(hipe_x86:pop_dst(I)),
- [{pop, {Arg}, I}];
- #push{} ->
- Arg = translate_src(hipe_x86:push_src(I), Context),
- [{push, {Arg}, I}];
- #ret{} ->
- translate_ret(I);
- #shift{} ->
- Arg = resolve_shift_args(hipe_x86:shift_src(I), hipe_x86:shift_dst(I), Context),
- [{hipe_x86:shift_op(I), Arg, I}];
- #test{} ->
- Arg = resolve_test_args(hipe_x86:test_src(I), hipe_x86:test_dst(I), Context),
- [{test, Arg, I}]
- end.
-
--ifdef(X86_SIMULATE_NSP).
--ifdef(HIPE_AMD64).
-translate_call(I) ->
- WordSize = hipe_amd64_registers:wordsize(),
- RegSP = 2#100, % esp/rsp
- TempSP = hipe_x86:mk_temp(RegSP, untagged),
- FunOrig = hipe_x86:call_fun(I),
- Fun =
- case FunOrig of
- #x86_mem{base=#x86_temp{reg=4}, off=#x86_imm{value=Off}} ->
- FunOrig#x86_mem{off=#x86_imm{value=Off+WordSize}};
- _ -> FunOrig
- end,
- RegRA =
- begin
- RegTemp0 = hipe_amd64_registers:temp0(),
- RegTemp1 = hipe_amd64_registers:temp1(),
- case Fun of
- #x86_temp{reg=RegTemp0} -> RegTemp1;
- #x86_mem{base=#x86_temp{reg=RegTemp0}} -> RegTemp1;
- _ -> RegTemp0
- end
- end,
- TempRA = hipe_x86:mk_temp(RegRA, untagged),
- PatchTypeExt =
- case hipe_x86:call_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- JmpArg = translate_fun(Fun, PatchTypeExt),
- I4 = {'.sdesc', hipe_x86:call_sdesc(I), #comment{term=sdesc}},
- I3 = {jmp, {JmpArg}, #comment{term=call}},
- Size3 = hipe_amd64_encode:insn_sizeof(jmp, {JmpArg}),
- MovArgs = {mem_to_rmArch(hipe_x86:mk_mem(TempSP,
- hipe_x86:mk_imm(0),
- untagged)),
- temp_to_regArch(TempRA)},
- I2 = {mov, MovArgs, #comment{term=call}},
- Size2 = hipe_amd64_encode:insn_sizeof(mov, MovArgs),
- I1 = {lea, {temp_to_regArch(TempRA),
- {ea, hipe_amd64_encode:ea_disp32_rip(Size2+Size3)}},
- #comment{term=call}},
- I0 = {sub, {temp_to_rmArch(TempSP), {imm8,WordSize}}, I},
- [I0,I1,I2,I3,I4].
--else.
-translate_call(I) ->
- WordSize = ?HIPE_X86_REGISTERS:wordsize(),
- RegSP = 2#100, % esp/rsp
- TempSP = hipe_x86:mk_temp(RegSP, untagged),
- FunOrig = hipe_x86:call_fun(I),
- Fun =
- case FunOrig of
- #x86_mem{base=#x86_temp{reg=4}, off=#x86_imm{value=Off}} ->
- FunOrig#x86_mem{off=#x86_imm{value=Off+WordSize}};
- _ -> FunOrig
- end,
- PatchTypeExt =
- case hipe_x86:call_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- JmpArg = translate_fun(Fun, PatchTypeExt),
- I3 = {'.sdesc', hipe_x86:call_sdesc(I), #comment{term=sdesc}},
- I2 = {jmp, {JmpArg}, #comment{term=call}},
- Size2 = ?HIPE_X86_ENCODE:insn_sizeof(jmp, {JmpArg}),
- I1 = {mov, {mem_to_rmArch(hipe_x86:mk_mem(TempSP,
- hipe_x86:mk_imm(0),
- untagged)),
- {imm32,{?X86ABSPCREL,4+Size2}}},
- #comment{term=call}},
- I0 = {sub, {temp_to_rmArch(TempSP), {imm8,WordSize}}, I},
- [I0,I1,I2,I3].
--endif.
-
-translate_ret(I) ->
- NPOP = hipe_x86:ret_npop(I) + ?HIPE_X86_REGISTERS:wordsize(),
- RegSP = 2#100, % esp/rsp
- TempSP = hipe_x86:mk_temp(RegSP, untagged),
- RegRA = 2#011, % ebx/rbx
- TempRA = hipe_x86:mk_temp(RegRA, untagged),
- [{mov,
- {temp_to_regArch(TempRA),
- mem_to_rmArch(hipe_x86:mk_mem(TempSP,
- hipe_x86:mk_imm(0),
- untagged))},
- I},
- {add,
- {temp_to_rmArch(TempSP),
- case NPOP < 128 of
- true -> {imm8,NPOP};
- false -> {imm32,NPOP}
- end},
- #comment{term=ret}},
- {jmp,
- {temp_to_rmArch(TempRA)},
- #comment{term=ret}}].
-
--else. % not X86_SIMULATE_NSP
-
-translate_call(I) ->
- %% call and jmp are patched the same, so no need to distinguish
- %% call from tailcall
- PatchTypeExt =
- case hipe_x86:call_linkage(I) of
- remote -> ?CALL_REMOTE;
- not_remote -> ?CALL_LOCAL
- end,
- Arg = translate_fun(hipe_x86:call_fun(I), PatchTypeExt),
- SDesc = hipe_x86:call_sdesc(I),
- [{call, {Arg}, I}, {'.sdesc', SDesc, #comment{term=sdesc}}].
-
-translate_ret(I) ->
- Arg =
- case hipe_x86:ret_npop(I) of
- 0 -> {};
- N -> {{imm16,N}}
- end,
- [{ret, Arg, I}].
-
--endif. % X86_SIMULATE_NSP
-
-translate_imul(I, Context) ->
- Temp = temp_to_regArch(hipe_x86:imul_temp(I)),
- Src = temp_or_mem_to_rmArch(hipe_x86:imul_src(I)),
- Args =
- case hipe_x86:imul_imm_opt(I) of
- [] -> {Temp,Src};
- Imm -> {Temp,Src,translate_imm(Imm, Context, true)}
- end,
- [{'imul', Args, I}].
-
-temp_or_mem_to_rmArch(Src) ->
- case Src of
- #x86_temp{} -> temp_to_rmArch(Src);
- #x86_mem{} -> mem_to_rmArch(Src)
- end.
-
-translate_label(Label) when is_integer(Label) ->
- {label,Label}. % symbolic, since offset is not yet computable
-
-translate_fun(Arg, PatchTypeExt) ->
- case Arg of
- #x86_temp{} ->
- temp_to_rmArch(Arg);
- #x86_mem{} ->
- mem_to_rmArch(Arg);
- #x86_mfa{m=M,f=F,a=A} ->
- {rel32,{PatchTypeExt,{M,F,A}}};
- #x86_prim{prim=Prim} ->
- {rel32,{PatchTypeExt,Prim}}
- end.
-
-translate_src(Src, Context) ->
- case Src of
- #x86_imm{} ->
- translate_imm(Src, Context, true);
- _ ->
- translate_dst(Src)
- end.
-
-%%% MayTrunc8 controls whether negative Imm8s should be truncated
-%%% to 8 bits or not. Truncation should always be done, except when
-%%% the caller will widen the Imm8 to an Imm32 or Imm64.
-translate_imm(#x86_imm{value=Imm}, Context, MayTrunc8) ->
- if is_atom(Imm) ->
- {imm32,{?LOAD_ATOM,Imm}};
- is_integer(Imm) ->
- case (Imm =< 127) and (Imm >= -128) of
- true ->
- Imm8 =
- case MayTrunc8 of
- true -> Imm band 16#FF;
- false -> Imm
- end,
- {imm8,Imm8};
- false ->
- {imm32,Imm}
- end;
- true ->
- Val =
- case Imm of
- {Label,constant} ->
- {MFA,ConstMap} = Context,
- ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
- {constant,ConstNo};
- {Label,closure} ->
- {closure,Label};
- {Label,c_const} ->
- {c_const,Label}
- end,
- {imm32,{?LOAD_ADDRESS,Val}}
- end.
-
-translate_dst(Dst) ->
- case Dst of
- #x86_temp{} ->
- temp_to_regArch(Dst);
- #x86_mem{type='double'} ->
- mem_to_rm64fp(Dst);
- #x86_mem{} ->
- mem_to_rmArch(Dst);
- #x86_fpreg{} ->
- fpreg_to_stack(Dst)
- end.
-
-%%%
-%%% Assembly Pass 3.
-%%% Process final {MFA,Code,CodeSize,LabelMap} list from pass 2.
-%%% Translate to a single binary code segment.
-%%% Collect relocation patches.
-%%% Build ExportMap (MFA-to-address mapping).
-%%% Combine LabelMaps to a single one (for mk_data_relocs/2 compatibility).
-%%% Return {CombinedCodeSize,BinaryCode,Relocs,CombinedLabelMap,ExportMap}.
-%%%
-
-encode(Code, Options) ->
- CodeSize = compute_code_size(Code, 0),
- ExportMap = build_export_map(Code, 0, []),
- {AccCode,Relocs} = encode_mfas(Code, 0, [], [], Options),
- CodeBinary = list_to_binary(lists:reverse(AccCode)),
- ?ASSERT(CodeSize =:= byte_size(CodeBinary)),
- CombinedLabelMap = combine_label_maps(Code, 0, gb_trees:empty()),
- {CodeSize,CodeBinary,Relocs,CombinedLabelMap,ExportMap}.
-
-nr_pad_bytes(Address) -> (4 - (Address rem 4)) rem 4. % XXX: 16 or 32 instead?
-
-align_entry(Address) -> Address + nr_pad_bytes(Address).
-
-compute_code_size([{_MFA,_Insns,CodeSize,_LabelMap}|Code], Size) ->
- compute_code_size(Code, align_entry(Size+CodeSize));
-compute_code_size([], Size) -> Size.
-
-build_export_map([{{M,F,A},_Insns,CodeSize,_LabelMap}|Code], Address, ExportMap) ->
- build_export_map(Code, align_entry(Address+CodeSize), [{Address,M,F,A}|ExportMap]);
-build_export_map([], _Address, ExportMap) -> ExportMap.
-
-combine_label_maps([{MFA,_Insns,CodeSize,LabelMap}|Code], Address, CLM) ->
- NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
- combine_label_maps(Code, align_entry(Address+CodeSize), NewCLM);
-combine_label_maps([], _Address, CLM) -> CLM.
-
-merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
- NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
- merge_label_map(Rest, MFA, Address, NewCLM);
-merge_label_map([], _MFA, _Address, CLM) -> CLM.
-
-encode_mfas([{MFA,Insns,CodeSize,LabelMap}|Code], Address, AccCode, Relocs, Options) ->
- print("Generating code for:~w\n", [MFA], Options),
- print("Offset | Opcode | Instruction\n", [], Options),
- {Address1,Relocs1,AccCode1} =
- encode_insns(Insns, Address, Address, LabelMap, Relocs, AccCode, Options),
- ExpectedAddress = align_entry(Address + CodeSize),
- ?ASSERT(Address1 =:= ExpectedAddress),
- print("Finished.\n\n", [], Options),
- encode_mfas(Code, Address1, AccCode1, Relocs1, Options);
-encode_mfas([], _Address, AccCode, Relocs, _Options) ->
- {AccCode, Relocs}.
-
-encode_insns([I|Insns], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case I of
- {'.label',L,_} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ?ASSERT(Address =:= LabelAddress), % sanity check
- print_insn(Address, [], I, Options),
- encode_insns(Insns, Address, FunAddress, LabelMap, Relocs, AccCode, Options);
- {'.sdesc',SDesc,_} ->
- #x86_sdesc{exnlab=ExnLab,fsize=FSize,arity=Arity,live=Live} = SDesc,
- ExnRA =
- case ExnLab of
- [] -> []; % don't cons up a new one
- ExnLab -> gb_trees:get(ExnLab, LabelMap) + FunAddress
- end,
- Reloc = {?SDESC, Address,
- ?STACK_DESC(ExnRA, FSize, Arity, Live)},
- encode_insns(Insns, Address, FunAddress, LabelMap, [Reloc|Relocs], AccCode, Options);
- _ ->
- {Op,Arg,_} = fix_jumps(I, Address, FunAddress, LabelMap),
- {Bytes, NewRelocs} = ?HIPE_X86_ENCODE:insn_encode(Op, Arg, Address),
- print_insn(Address, Bytes, I, Options),
- Segment = list_to_binary(Bytes),
- Size = byte_size(Segment),
- NewAccCode = [Segment|AccCode],
- encode_insns(Insns, Address+Size, FunAddress, LabelMap, NewRelocs++Relocs, NewAccCode, Options)
- end;
-encode_insns([], Address, FunAddress, LabelMap, Relocs, AccCode, Options) ->
- case nr_pad_bytes(Address) of
- 0 ->
- {Address,Relocs,AccCode};
- NrPadBytes -> % triggers at most once per function body
- Padding = lists:duplicate(NrPadBytes, {nop,{},#comment{term=padding}}),
- encode_insns(Padding, Address, FunAddress, LabelMap, Relocs, AccCode, Options)
- end.
-
-fix_jumps(I, InsnAddress, FunAddress, LabelMap) ->
- case I of
- {jcc_sdi,{CC,{label,L}},OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ShortOffset = LabelAddress - (InsnAddress + 2),
- if is_integer(ShortOffset), ShortOffset >= -128, ShortOffset =< 127 ->
- {jcc,{CC,{rel8,ShortOffset band 16#FF}},OrigI};
- true ->
- LongOffset = LabelAddress - (InsnAddress + 6),
- {jcc,{CC,{rel32,LongOffset}},OrigI}
- end;
- {jmp_sdi,{{label,L}},OrigI} ->
- LabelAddress = gb_trees:get(L, LabelMap) + FunAddress,
- ShortOffset = LabelAddress - (InsnAddress + 2),
- if is_integer(ShortOffset), ShortOffset >= -128, ShortOffset =< 127 ->
- {jmp,{{rel8,ShortOffset band 16#FF}},OrigI};
- true ->
- LongOffset = LabelAddress - (InsnAddress + 5),
- {jmp,{{rel32,LongOffset}},OrigI}
- end;
- _ -> I
- end.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-fpreg_to_stack(#x86_fpreg{reg=Reg}) ->
- {fpst, Reg}.
-
-temp_to_regArch(#x86_temp{reg=Reg}) ->
- {?REGArch, Reg}.
-
--ifdef(HIPE_AMD64).
-temp_to_reg64(#x86_temp{reg=Reg}) ->
- {reg64, Reg}.
--endif.
-
-temp_to_reg32(#x86_temp{reg=Reg}) ->
- {reg32, Reg}.
-temp_to_reg16(#x86_temp{reg=Reg}) ->
- {reg16, Reg}.
-temp_to_reg8(#x86_temp{reg=Reg}) ->
- {reg8, Reg}.
-
-temp_to_xmm(#x86_temp{reg=Reg}) ->
- {xmm, Reg}.
-
--ifdef(HIPE_AMD64).
-temp_to_rm8(#x86_temp{reg=Reg}) ->
- {rm8, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rm64(#x86_temp{reg=Reg}) ->
- {rm64, hipe_amd64_encode:rm_reg(Reg)}.
--else.
-temp_to_rm8(#x86_temp{reg=Reg}) ->
- true = ?HIPE_X86_ENCODE:reg_has_8bit(Reg),
- {rm8, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rm16(#x86_temp{reg=Reg}) ->
- {rm16, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
--endif.
-
-temp_to_rm32(#x86_temp{reg=Reg}) ->
- {rm32, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rmArch(#x86_temp{reg=Reg}) ->
- {?RMArch, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-temp_to_rm64fp(#x86_temp{reg=Reg}) ->
- {rm64fp, ?HIPE_X86_ENCODE:rm_reg(Reg)}.
-
-mem_to_ea(Mem) ->
- EA = mem_to_ea_common(Mem),
- {ea, EA}.
-
-mem_to_rm32(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm32, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-mem_to_rmArch(Mem) ->
- EA = mem_to_ea_common(Mem),
- {?RMArch, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-mem_to_rm64fp(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm64fp, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-%%%%%%%%%%%%%%%%%
-mem_to_rm8(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm8, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-
-mem_to_rm16(Mem) ->
- EA = mem_to_ea_common(Mem),
- {rm16, ?HIPE_X86_ENCODE:rm_mem(EA)}.
-%%%%%%%%%%%%%%%%%
-
-mem_to_ea_common(#x86_mem{base=[], off=#x86_imm{value=Off}}) ->
- ?HIPE_X86_ENCODE:?EA_DISP32_ABSOLUTE(Off);
-mem_to_ea_common(#x86_mem{base=#x86_temp{reg=Base}, off=#x86_temp{reg=Index}}) ->
- case Base band 2#111 of
- 5 -> % ebp/rbp or r13
- case Index band 2#111 of
- 5 -> % ebp/rbp or r13
- SINDEX = ?HIPE_X86_ENCODE:sindex(0, Index),
- SIB = ?HIPE_X86_ENCODE:sib(Base, SINDEX),
- ?HIPE_X86_ENCODE:ea_disp8_sib(0, SIB);
- _ ->
- SINDEX = ?HIPE_X86_ENCODE:sindex(0, Base),
- SIB = ?HIPE_X86_ENCODE:sib(Index, SINDEX),
- ?HIPE_X86_ENCODE:ea_sib(SIB)
- end;
- _ ->
- SINDEX = ?HIPE_X86_ENCODE:sindex(0, Index),
- SIB = ?HIPE_X86_ENCODE:sib(Base, SINDEX),
- ?HIPE_X86_ENCODE:ea_sib(SIB)
- end;
-mem_to_ea_common(#x86_mem{base=#x86_temp{reg=Base}, off=#x86_imm{value=Off}}) ->
- if
- Off =:= 0 ->
- case Base of
- 4 -> %esp, use SIB w/o disp8
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_sib(SIB);
- 5 -> %ebp, use disp8 w/o SIB
- ?HIPE_X86_ENCODE:ea_disp8_base(Off, Base);
- 12 -> %r12, use SIB w/o disp8
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_sib(SIB);
- 13 -> %r13, use disp8 w/o SIB
- ?HIPE_X86_ENCODE:ea_disp8_base(Off, Base);
- _ -> %neither SIB nor disp8 needed
- ?HIPE_X86_ENCODE:ea_base(Base)
- end;
- Off >= -128, Off =< 127 ->
- Disp8 = Off band 16#FF,
- case Base of
- 4 -> %esp, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp8_sib(Disp8, SIB);
- 12 -> %r12, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp8_sib(Disp8, SIB);
- _ -> %use disp8 w/o SIB
- ?HIPE_X86_ENCODE:ea_disp8_base(Disp8, Base)
- end;
- true ->
- case Base of
- 4 -> %esp, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp32_sib(Off, SIB);
- 12 -> %r12, must use SIB
- SIB = ?HIPE_X86_ENCODE:sib(Base),
- ?HIPE_X86_ENCODE:ea_disp32_sib(Off, SIB);
- _ ->
- ?HIPE_X86_ENCODE:ea_disp32_base(Off, Base)
- end
- end.
-
-%% jmp_switch
--ifdef(HIPE_AMD64).
-resolve_jmp_switch_arg(I, _Context) ->
- Base = hipe_x86:temp_reg(hipe_x86:jmp_switch_jtab(I)),
- Index = hipe_x86:temp_reg(hipe_x86:jmp_switch_temp(I)),
- SINDEX = hipe_amd64_encode:sindex(3, Index),
- SIB = hipe_amd64_encode:sib(Base, SINDEX),
- EA =
- if (Base =:= 5) or (Base =:= 13) ->
- hipe_amd64_encode:ea_disp8_sib(0, SIB);
- true ->
- hipe_amd64_encode:ea_sib(SIB)
- end,
- {rm64,hipe_amd64_encode:rm_mem(EA)}.
--else.
-resolve_jmp_switch_arg(I, {MFA,ConstMap}) ->
- ConstNo = hipe_pack_constants:find_const({MFA,hipe_x86:jmp_switch_jtab(I)}, ConstMap),
- Disp32 = {?LOAD_ADDRESS,{constant,ConstNo}},
- SINDEX = ?HIPE_X86_ENCODE:sindex(2, hipe_x86:temp_reg(hipe_x86:jmp_switch_temp(I))),
- EA = ?HIPE_X86_ENCODE:ea_disp32_sindex(Disp32, SINDEX), % this creates a SIB implicitly
- {rm32,?HIPE_X86_ENCODE:rm_mem(EA)}.
--endif.
-
-%% lea reg, mem
-resolve_lea_args(Src=#x86_mem{}, Dst=#x86_temp{}) ->
- {temp_to_regArch(Dst),mem_to_ea(Src)}.
-
-resolve_sse2_op(Op) ->
- case Op of
- fadd -> addsd;
- fdiv -> divsd;
- fmul -> mulsd;
- fsub -> subsd;
- xorpd -> xorpd;
- _ -> exit({?MODULE, unknown_sse2_operator, Op})
- end.
-
-%% OP xmm, mem
-resolve_sse2_binop_args(Src=#x86_mem{type=double},
- Dst=#x86_temp{type=double}) ->
- {temp_to_xmm(Dst),mem_to_rm64fp(Src)};
-%% movsd mem, xmm
-resolve_sse2_binop_args(Src=#x86_temp{type=double},
- Dst=#x86_mem{type=double}) ->
- {mem_to_rm64fp(Dst),temp_to_xmm(Src)};
-%% OP xmm, xmm
-resolve_sse2_binop_args(Src=#x86_temp{type=double},
- Dst=#x86_temp{type=double}) ->
- {temp_to_xmm(Dst),temp_to_rm64fp(Src)}.
-
-%%% fmove -> cvtsi2sd or movsd
-resolve_sse2_fmove_args(Src, Dst) ->
- case {Src,Dst} of
- {#x86_temp{type=untagged}, #x86_temp{type=double}} -> % cvtsi2sd xmm, reg
- {cvtsi2sd, {temp_to_xmm(Dst),temp_to_rmArch(Src)}};
- {#x86_mem{type=untagged}, #x86_temp{type=double}} -> % cvtsi2sd xmm, mem
- {cvtsi2sd, {temp_to_xmm(Dst),mem_to_rmArch(Src)}};
- _ -> % movsd
- {movsd, resolve_sse2_binop_args(Src, Dst)}
- end.
-
-%%% xorpd xmm, mem
-resolve_sse2_fchs_arg(Dst=#x86_temp{type=double}) ->
- {temp_to_xmm(Dst),
- {rm64fp, {rm_mem, ?HIPE_X86_ENCODE:?EA_DISP32_ABSOLUTE(
- {?LOAD_ADDRESS,
- {c_const, sse2_fnegate_mask}})}}}.
-
-%% mov mem, imm
-resolve_move_args(#x86_imm{value=ImmSrc}, Dst=#x86_mem{type=Type}, Context) ->
- case Type of % to support byte, int16 and int32 stores
- byte ->
- ByteImm = ImmSrc band 255, %to ensure that it is a bytesized imm
- {mem_to_rm8(Dst),{imm8,ByteImm}};
- int16 ->
- {mem_to_rm16(Dst),{imm16,ImmSrc band 16#FFFF}};
- int32 ->
- {_,Imm} = translate_imm(#x86_imm{value=ImmSrc}, Context, false),
- {mem_to_rm32(Dst),{imm32,Imm}};
- _ ->
- RMArch = mem_to_rmArch(Dst),
- {_,Imm} = translate_imm(#x86_imm{value=ImmSrc}, Context, false),
- {RMArch,{imm32,Imm}}
- end;
-
-%% mov reg,mem
-resolve_move_args(Src=#x86_mem{type=Type}, Dst=#x86_temp{}, _Context) ->
- case Type of
- int32 -> % must be unsigned
- {temp_to_reg32(Dst),mem_to_rm32(Src)};
- _ ->
- {temp_to_regArch(Dst),mem_to_rmArch(Src)}
- end;
-
-%% mov mem,reg
-resolve_move_args(Src=#x86_temp{}, Dst=#x86_mem{type=Type}, _Context) ->
- case Type of % to support byte, int16 and int32 stores
- byte ->
- {mem_to_rm8(Dst),temp_to_reg8(Src)};
- int16 ->
- {mem_to_rm16(Dst),temp_to_reg16(Src)};
- int32 ->
- {mem_to_rm32(Dst),temp_to_reg32(Src)};
- tagged -> % tagged, untagged
- {mem_to_rmArch(Dst),temp_to_regArch(Src)};
- untagged -> % tagged, untagged
- {mem_to_rmArch(Dst),temp_to_regArch(Src)}
- end;
-
-%% mov reg,reg
-resolve_move_args(Src=#x86_temp{}, Dst=#x86_temp{}, _Context) ->
- {temp_to_regArch(Dst),temp_to_rmArch(Src)};
-
-%% mov reg,imm
-resolve_move_args(Src=#x86_imm{value=_ImmSrc}, Dst=#x86_temp{}, Context) ->
- {_,Imm} = translate_imm(Src, Context, false),
- imm_move_args(Dst, Imm).
-
--ifdef(HIPE_AMD64).
-imm_move_args(Dst, Imm) ->
- if is_number(Imm), Imm >= 0 ->
- {temp_to_reg32(Dst),{imm32,Imm}};
- true ->
- {temp_to_rm64(Dst),{imm32,Imm}}
- end.
--else.
-imm_move_args(Dst, Imm) ->
- {temp_to_reg32(Dst),{imm32,Imm}}.
--endif.
-
--ifdef(HIPE_AMD64).
-translate_move64(I, Context) ->
- Arg = resolve_move64_args(hipe_x86:move64_src(I),
- hipe_x86:move64_dst(I),
- Context),
- [{mov, Arg, I}].
-
-%% mov reg,imm64
-resolve_move64_args(Src=#x86_imm{}, Dst=#x86_temp{}, Context) ->
- {_,Imm} = translate_imm(Src, Context, false),
- {temp_to_reg64(Dst),{imm64,Imm}}.
--else.
-translate_move64(I, _Context) -> exit({?MODULE, I}).
--endif.
-
-%%% mov{s,z}x
-resolve_movx_src(Src=#x86_mem{type=Type}) ->
- case Type of
- byte ->
- mem_to_rm8(Src);
- int16 ->
- mem_to_rm16(Src);
- int32 ->
- mem_to_rm32(Src)
- end.
-
-%%% alu/cmp (_not_ test)
-resolve_alu_args(Src, Dst, Context) ->
- case {Src,Dst} of
- {#x86_imm{}, #x86_mem{}} ->
- {mem_to_rmArch(Dst), translate_imm(Src, Context, true)};
- {#x86_mem{}, #x86_temp{}} ->
- {temp_to_regArch(Dst), mem_to_rmArch(Src)};
- {#x86_temp{}, #x86_mem{}} ->
- {mem_to_rmArch(Dst), temp_to_regArch(Src)};
- {#x86_temp{}, #x86_temp{}} ->
- {temp_to_regArch(Dst), temp_to_rmArch(Src)};
- {#x86_imm{}, #x86_temp{reg=0}} -> % eax,imm
- NewSrc = translate_imm(Src, Context, true),
- NewDst =
- case NewSrc of
- {imm8,_} -> temp_to_rmArch(Dst);
- {imm32,_} -> ?EAX
- end,
- {NewDst, NewSrc};
- {#x86_imm{}, #x86_temp{}} ->
- {temp_to_rmArch(Dst), translate_imm(Src, Context, true)}
- end.
-
-%%% test
-resolve_test_args(Src, Dst, Context) ->
- case Src of
- %% Since we're using an 8-bit instruction, the immediate is not sign
- %% extended. Thus, we can use immediates up to 255.
- #x86_imm{value=ImmVal}
- when is_integer(ImmVal), ImmVal >= 0, ImmVal =< 255 ->
- Imm = {imm8, ImmVal},
- case Dst of
- #x86_temp{reg=0} -> {al, Imm};
- #x86_temp{} -> resolve_test_imm8_reg(Imm, Dst);
- #x86_mem{} -> {mem_to_rm8(Dst), Imm}
- end;
- #x86_imm{value=ImmVal} when is_integer(ImmVal), ImmVal >= 0 ->
- {case Dst of
- #x86_temp{reg=0} -> eax;
- #x86_temp{} -> temp_to_rm32(Dst);
- #x86_mem{} -> mem_to_rm32(Dst)
- end, {imm32, ImmVal}};
- #x86_imm{} -> % Negative ImmVal; use word-sized instr, imm32
- {_, ImmVal} = translate_imm(Src, Context, false),
- {case Dst of
- #x86_temp{reg=0} -> ?EAX;
- #x86_temp{} -> temp_to_rmArch(Dst);
- #x86_mem{} -> mem_to_rmArch(Dst)
- end, {imm32, ImmVal}};
- #x86_temp{} ->
- NewDst =
- case Dst of
- #x86_temp{} -> temp_to_rmArch(Dst);
- #x86_mem{} -> mem_to_rmArch(Dst)
- end,
- {NewDst, temp_to_regArch(Src)}
- end.
-
--ifdef(HIPE_AMD64).
-resolve_test_imm8_reg(Imm, Dst) -> {temp_to_rm8(Dst), Imm}.
--else.
-resolve_test_imm8_reg(Imm = {imm8, ImmVal}, Dst = #x86_temp{reg=Reg}) ->
- case ?HIPE_X86_ENCODE:reg_has_8bit(Reg) of
- true -> {temp_to_rm8(Dst), Imm};
- false ->
- %% Register does not exist in 8-bit version; use 16-bit instead
- {temp_to_rm16(Dst), {imm16, ImmVal}}
- end.
--endif.
-
-%%% shifts
-resolve_shift_args(Src, Dst, Context) ->
- RM32 =
- case Dst of
- #x86_temp{} -> temp_to_rmArch(Dst);
- #x86_mem{} -> mem_to_rmArch(Dst)
- end,
- Count =
- case Src of
- #x86_imm{value=1} -> 1;
- #x86_imm{} -> translate_imm(Src, Context, true); % must be imm8
- #x86_temp{reg=1} -> cl % temp must be ecx
- end,
- {RM32, Count}.
-
-%% x87_binop mem
-resolve_x87_unop_arg(Arg=#x86_mem{type=Type})->
- case Type of
- 'double' -> {mem_to_rm64fp(Arg)};
- 'untagged' -> {mem_to_rmArch(Arg)};
- _ -> ?EXIT({fmovArgNotSupported,{Arg}})
- end;
-resolve_x87_unop_arg(Arg=#x86_fpreg{}) ->
- {fpreg_to_stack(Arg)};
-resolve_x87_unop_arg([]) ->
- [].
-
-%% x87_binop mem, st(i)
-resolve_x87_binop_args(Src=#x86_fpreg{}, Dst=#x86_mem{})->
- {mem_to_rm64fp(Dst),fpreg_to_stack(Src)};
-%% x87_binop st(0), st(i)
-resolve_x87_binop_args(Src=#x86_fpreg{}, Dst=#x86_fpreg{})->
- {fpreg_to_stack(Dst),fpreg_to_stack(Src)}.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%
-%%% Assembly listing support (pp_asm option).
-%%%
-
-print(String, Arglist, Options) ->
- ?when_option(pp_asm, Options, io:format(String, Arglist)).
-
-print_insn(Address, Bytes, I, Options) ->
- ?when_option(pp_asm, Options, print_insn_2(Address, Bytes, I)),
- ?when_option(pp_cxmon, Options, print_code_list_2(Bytes)).
-
-print_code_list_2([H | Tail]) ->
- print_byte(H),
- io:format(","),
- print_code_list_2(Tail);
-print_code_list_2([]) ->
- io:format("").
-
-print_insn_2(Address, Bytes, {_,_,OrigI}) ->
- io:format("~8.16b | ", [Address]),
- print_code_list(Bytes, 0),
- ?HIPE_X86_PP:pp_insn(OrigI).
-
-print_code_list([Byte|Rest], Len) ->
- print_byte(Byte),
- print_code_list(Rest, Len+1);
-print_code_list([], Len) ->
- fill_spaces(24-(Len*2)),
- io:format(" | ").
-
-print_byte(Byte) ->
- io:format("~2.16.0b", [Byte band 16#FF]).
-
-fill_spaces(N) when N > 0 ->
- io:format(" "),
- fill_spaces(N-1);
-fill_spaces(0) ->
- [].