View

Large diffs are not rendered by default.

Oops, something went wrong.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,11 @@
-ifdef(BIT32).
-define(NR_PINNED_REGS, 2).
-define(NR_ARG_REGS, 3).
-define(ARCH_REGISTERS, hipe_x86_registers).
-define(FLOAT_OFFSET, 2).
-else.
-define(NR_PINNED_REGS, 2).
-define(NR_ARG_REGS, 4).
-define(ARCH_REGISTERS, hipe_amd64_registers).
-define(FLOAT_OFFSET, 6).
-endif.
View
@@ -0,0 +1,112 @@
-module(hipe_llvm_liveness).
-export([analyze/1]).
%% @doc Find gc roots and explicitly mark when they go out of scope, based
%% on the liveness analyzis performed by the hipe_rtl_liveness:analyze/1.
analyze(RtlCfg) ->
Liveness = hipe_rtl_liveness:analyze(RtlCfg),
Roots = find_roots(RtlCfg, Liveness),
%% erlang:display(Roots),
NewRtlCfg = mark_dead_roots(RtlCfg, Liveness, Roots),
{NewRtlCfg, Roots}.
%% @doc Determine which are the GC Roots.Possible roots are all
%% RTL variables (rtl_var). However, since safe points are function calls, we
%% consider as possible GC roots only RTL variables that are live around
%% function calls.
find_roots(Cfg, Liveness) ->
Labels = hipe_rtl_cfg:postorder(Cfg),
Roots = find_roots_bb(Labels, Cfg, Liveness, []),
lists:usort(lists:flatten(Roots)).
find_roots_bb([], _Cfg, _Liveness, RootAcc) ->
RootAcc;
find_roots_bb([L|Ls], Cfg, Liveness, RootAcc) ->
Block = hipe_rtl_cfg:bb(Cfg, L),
BlockCode = hipe_bb:code(Block),
LiveIn = ordsets:from_list(strip(hipe_rtl_liveness:livein(Liveness, L))),
LiveOut = ordsets:from_list(strip(hipe_rtl_liveness:liveout(Liveness, L))),
Roots = do_find_roots_bb(BlockCode, L, LiveOut, LiveIn, []),
find_roots_bb(Ls, Cfg, Liveness, Roots++RootAcc).
%% For each call inside a BB the GC roots are those RTL variables that
%% are live before and after the call.
%% --> Live Before Call: These are the RTL variables that belong to the
%% LiveIn list or are initialized inside the BB before the call
%% --> Live After Call: These are the RTL variables that belong to the
%% LiveOut list or are used after the call inside the BB (they die
%% inside the BB and so do not belong to the LiveOut list)
do_find_roots_bb([], _Label, _LiveOut, _LiveBefore, RootAcc) ->
RootAcc;
do_find_roots_bb([I|Is], L, LiveOut, LiveBefore, RootAcc) ->
case hipe_rtl:is_call(I) of
true ->
%% Used inside the BB after the call
UsedAfterCall_ = strip(lists:flatten([hipe_rtl:uses(V) || V <- Is])),
UsedAfterCall = ordsets:from_list(UsedAfterCall_),
LiveAfter = ordsets:union(UsedAfterCall, LiveOut),
%% The Actual Roots
Roots = ordsets:intersection(LiveBefore, LiveAfter),
%% The result of the instruction
Defines = ordsets:from_list(strip(hipe_rtl:defines(I))),
LiveBefore1 = ordsets:union(LiveBefore, Defines),
do_find_roots_bb(Is, L, LiveOut, LiveBefore1, [Roots|RootAcc]);
false ->
%% The result of the instruction
Defines = ordsets:from_list(strip(hipe_rtl:defines(I))),
LiveBefore1 = ordsets:union(LiveBefore, Defines),
do_find_roots_bb(Is, L, LiveOut, LiveBefore1, RootAcc)
end.
%% @doc This function is responsible for marking when GC Roots, which can be
%% only RTL variables go out of scope (dead). This pass is needed for the LLVM
%% back end because the LLVM framework forces us to explicit mark when gc roots
%% are no longer live.
mark_dead_roots(CFG, Liveness, Roots) ->
Labels = hipe_rtl_cfg:postorder(CFG),
mark_dead_bb(Labels, CFG, Liveness, Roots).
mark_dead_bb([], Cfg, _Liveness, _Roots) ->
Cfg;
mark_dead_bb([L|Ls], Cfg, Liveness, Roots) ->
Block = hipe_rtl_cfg:bb(Cfg, L),
BlockCode = hipe_bb:code(Block),
LiveOut = ordsets:from_list(strip(hipe_rtl_liveness:liveout(Liveness, L))),
NewBlockCode = do_mark_dead_bb(BlockCode, LiveOut, Roots, []),
%% Update the CFG
NewBB = hipe_bb:code_update(Block, NewBlockCode),
NewCFG = hipe_rtl_cfg:bb_add(Cfg, L, NewBB),
mark_dead_bb(Ls, NewCFG, Liveness, Roots).
do_mark_dead_bb([], _LiveOut, _Roots, NewBlockCode) ->
lists:reverse(NewBlockCode);
do_mark_dead_bb([I|Is], LiveOut ,Roots, NewBlockCode) ->
Uses = ordsets:from_list(strip(hipe_rtl:uses(I))),
%% GC roots that are used in this instruction
RootsUsed = ordsets:intersection(Roots, Uses),
UsedAfter_ = strip(lists:flatten([hipe_rtl:uses(V) || V <- Is])),
UsedAfter = ordsets:from_list(UsedAfter_),
%% GC roots that are live after this instruction
LiveAfter = ordsets:union(LiveOut, UsedAfter),
%% GC roots that their last use is in this instruction
DeadRoots = ordsets:subtract(RootsUsed, LiveAfter),
%% Recreate the RTL variable from the corresponding Index
OldVars = [hipe_rtl:mk_var(V1) || V1 <- DeadRoots],
%% Mark the RTL variable as DEAD (last use)
NewVars = [kill_var(V2) || V2 <- OldVars],
%% Create a list with the substitution of the old vars with the new
%% ones which are marked with the dead keyword
Subtitution = lists:zip(OldVars, NewVars),
NewI = case Subtitution of
[] -> I;
_ -> hipe_rtl:subst_uses_llvm(Subtitution, I)
end,
do_mark_dead_bb(Is, LiveOut, Roots, [NewI|NewBlockCode]).
%% Update the liveness of a var,in order to mark that this is the last use.
kill_var(Var) -> hipe_rtl:var_liveness_update(Var, dead).
%% We are only interested for rtl_vars, since only rtl_vars are possible gc
%% roots.
strip(L) -> [Y || {rtl_var, Y, _} <- L].
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,114 @@
%%% -*- erlang-indent-level: 2 -*-
-module(hipe_llvm_merge).
-export([finalize/3]).
-include("hipe_llvm_arch.hrl").
-include("../../kernel/src/hipe_ext_format.hrl").
-include("../rtl/hipe_literals.hrl").
-include("../main/hipe.hrl").
finalize(CompiledCode, Closures, Exports) ->
CompiledCode1 = [CodePack || {_, CodePack} <- CompiledCode],
Code = [{MFA, [], ConstTab}
|| {MFA, _, _ , ConstTab, _, _} <- CompiledCode1],
{ConstAlign, ConstSize, ConstMap, RefsFromConsts} =
hipe_pack_constants:pack_constants(Code, ?ARCH_REGISTERS:alignment()),
%% Compute total code size separately as a sanity check for alignment
CodeSize = compute_code_size(CompiledCode1, 0),
%% io:format("Code Size (pre-computed): ~w~n", [CodeSize]),
{CodeBinary, ExportMap} = merge_mfas(CompiledCode1, 0, <<>>, []),
%% io:format("Code Size (post-computed): ~w~n", [byte_size(CodeBinary)]),
?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)),
AccRefs = merge_refs(CompiledCode1, ConstMap, 0, []),
%% Bring CompiledCode to a combine_label_maps-acceptable form.
LabelMap = combine_label_maps(CompiledCode1, 0, gb_trees:empty()),
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),
term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
ConstAlign, ConstSize,
SC, % ConstMap
DataRelocs, % LabelMap
SSE, % ExportMap
CodeSize, CodeBinary, SlimRefs,
0,[] % ColdCodeSize, SlimColdRefs
]).
%% Copied from hipe_x86_assemble.erl
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, _BinaryCode, CodeSize, _, _, _}|Code], Size) ->
compute_code_size(Code, align_entry(Size+CodeSize));
compute_code_size([], Size) -> Size.
combine_label_maps([{MFA, _, 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.
%% @doc Merge the MFAs' binary code to one continuous binary and compute the
%% size of this binary. At the same time create an exportmap in a form
%% of {Address, M, F, A}.
%% XXX: Is alignment correct/optimal for X86/AMD64?
merge_mfas([{{M,F,A}, CodeBinary, CodeSize, _, _, _}|Code],
Address, AccCode, AccExportMap) ->
?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)),
{Address1, Code1} =
case nr_pad_bytes(Address + CodeSize) of
0 -> %% Retains alignment:
{Address + CodeSize, CodeBinary};
NrPadBytes -> %% Needs padding!
Padding = list_to_binary(lists:duplicate(NrPadBytes, 0)),
{Address + CodeSize + NrPadBytes, % =:= align_entry(Address+CodeSize)
<<CodeBinary/binary, Padding/binary>>}
end,
?VERBOSE_ASSERT(Address1 =:=
align_entry(Address + CodeSize)), %XXX: Should address be aligned?
AccCode1 = <<AccCode/binary, Code1/binary>>,
merge_mfas(Code, Address1, AccCode1, [{Address, M, F, A}|AccExportMap]);
merge_mfas([], _Address, AccCode, AccExportMap) ->
{AccCode, AccExportMap}.
%% @doc Merge the references of relocatable symbols in the binary code. The
%% offsets must be updated because of the merging of the code binaries!
merge_refs([], _ConstMap, _Addr, AccRefs) -> AccRefs;
merge_refs([{MFA, _, CodeSize, _, Refs, _}|Rest], ConstMap, Address, AccRefs) ->
%% Important!: The hipe_pack_constants:pack_constants/2 function assignes
%% unique numbers to constants (ConstNo). This numbers are used from now on,
%% instead of labels that were used before. So, in order to be compatible, we
%% must change all the constant labels in the Refs to the corresponding
%% ConstNo, that can be found in the ConstMap (#pcm_entry{}).
UpdatedRefs = [update_ref(label_to_constno(Ref, MFA, ConstMap), Address)
|| Ref <- Refs],
merge_refs(Rest, ConstMap, align_entry(Address+CodeSize),
UpdatedRefs++AccRefs).
label_to_constno({Type, Offset, {constant, Label}}, MFA, ConstMap) ->
ConstNo = hipe_pack_constants:find_const({MFA, Label}, ConstMap),
{Type, Offset, {constant, ConstNo}};
label_to_constno(Other, _MFA, _ConstMap) ->
Other.
%% @doc Update offset to a reference. In case of stack descriptors we must check
%% if there exists an exception handler, because it must also be updated.
update_ref({?SDESC, Offset, SDesc}, CodeAddr) ->
NewRefAddr = Offset+CodeAddr,
case SDesc of
{[], _, _, _} -> % No handler; only update offset
{?SDESC, NewRefAddr, SDesc};
{ExnHandler, FrameSize, StackArity, Roots} -> % Update exception handler
{?SDESC, NewRefAddr, {ExnHandler+CodeAddr, FrameSize, StackArity, Roots}}
end;
update_ref({Type, Offset, Term}, CodeAddr) ->
{Type, Offset+CodeAddr, Term}.
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -30,6 +30,7 @@
cerl_prettypr,
cerl_to_icode,
cerl_typean,
elf_format,
erl_bif_types,
erl_types,
hipe,
@@ -108,6 +109,10 @@
hipe_ig,
hipe_ig_moves,
hipe_jit,
hipe_llvm,
hipe_llvm_liveness,
hipe_llvm_main,
hipe_llvm_merge,
hipe_ls_regalloc,
hipe_main,
hipe_moves,
@@ -159,6 +164,7 @@
hipe_rtl_symbolic,
hipe_rtl_to_amd64,
hipe_rtl_to_arm,
hipe_rtl_to_llvm,
hipe_rtl_to_ppc,
hipe_rtl_to_sparc,
hipe_rtl_to_x86,
View
@@ -821,7 +821,9 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
?debug_msg("Compiled ~w in ~.2f s\n", [MFA,(T2-T1)/1000])),
{MFA, Code};
{rtl, LinearRtl} ->
{MFA, LinearRtl}
{MFA, LinearRtl};
{llvm_binary, Binary} ->
{MFA, Binary}
catch
error:Error ->
?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
@@ -890,21 +892,27 @@ do_load(Mod, Bin, BeamBinOrPath) when is_binary(BeamBinOrPath);
end.
assemble(CompiledCode, Closures, Exports, Options) ->
case get(hipe_target_arch) of
ultrasparc ->
hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
powerpc ->
hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
ppc64 ->
hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
arm ->
hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
x86 ->
hipe_x86_assemble:assemble(CompiledCode, Closures, Exports, Options);
amd64 ->
hipe_amd64_assemble:assemble(CompiledCode, Closures, Exports, Options);
Arch ->
?EXIT({executing_on_an_unsupported_architecture, Arch})
case proplists:get_bool(to_llvm, Options) of
false ->
case get(hipe_target_arch) of
ultrasparc ->
hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
powerpc ->
hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
ppc64 ->
hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
arm ->
hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
x86 ->
hipe_x86_assemble:assemble(CompiledCode, Closures, Exports, Options);
amd64 ->
hipe_amd64_assemble:assemble(CompiledCode, Closures, Exports, Options);
Arch ->
?EXIT({executing_on_an_unsupported_architecture, Arch})
end;
true ->
%% Merge already compiled code (per MFA) to a single binary.
hipe_llvm_merge:finalize(CompiledCode, Closures, Exports)
end.
%% --------------------------------------------------------------------
@@ -1330,6 +1338,11 @@ opt_keys() ->
timeregalloc,
timers,
to_rtl,
to_llvm, % Use the LLVM backend for compilation.
llvm_save_temps, % Save the LLVM intermediate files in the current
% directory; useful for debugging.
llvm_llc, % Specify llc optimization-level: o1, o2, o3, undefined.
llvm_opt, % Specify opt optimization-level: o1, o2, o3, undefined.
use_indexing,
use_inline_atom_search,
use_callgraph,
@@ -1468,11 +1481,19 @@ opt_expansions() ->
[{o1, o1_opts()},
{o2, o2_opts()},
{o3, o3_opts()},
{to_llvm, llvm_opts(o3)},
{{to_llvm, o0}, llvm_opts(o0)},
{{to_llvm, o1}, llvm_opts(o1)},
{{to_llvm, o2}, llvm_opts(o2)},
{{to_llvm, o3}, llvm_opts(o3)},
{x87, [x87, inline_fp]},
{inline_fp, case get(hipe_target_arch) of %% XXX: Temporary until x86
x86 -> [x87, inline_fp]; %% has sse2
_ -> [inline_fp] end}].
llvm_opts(O) ->
[to_llvm, {llvm_opt, O}, {llvm_llc, O}].
%% This expands "basic" options, which may be tested early and cannot be
%% in conflict with options found in the source code.
View
@@ -49,7 +49,7 @@
%%=====================================================================
-type comp_icode_ret() :: {'native',hipe_architecture(),{'unprofiled',_}}
| {'rtl',tuple()}.
| {'rtl',tuple()} | {'llvm_binary',term()}.
%%=====================================================================
@@ -115,11 +115,18 @@ compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) ->
pp(IcodeCfg7, MFA, icode_liveness, pp_icode_liveness, Options, Servers),
FinalIcode = hipe_icode_cfg:cfg_to_linear(IcodeCfg7),
?opt_stop_timer("Icode"),
LinearRTL = ?option_time(icode_to_rtl(MFA,FinalIcode,Options, Servers),
"RTL", Options),
{LinearRTL, Roots} = ?option_time(icode_to_rtl(MFA, FinalIcode, Options, Servers),
"RTL", Options),
case proplists:get_bool(to_rtl, Options) of
false ->
rtl_to_native(MFA, LinearRTL, Options, DebugState);
case proplists:get_bool(to_llvm, Options) of
false ->
rtl_to_native(MFA, LinearRTL, Options, DebugState);
true ->
%% The LLVM backend returns binary code, unlike the rest of the HiPE
%% backends which return native assembly.
rtl_to_llvm_to_binary(MFA, LinearRTL, Roots, Options, DebugState)
end;
true ->
put(hipe_debug, DebugState),
{rtl, LinearRTL}
@@ -385,11 +392,21 @@ icode_to_rtl(MFA, Icode, Options, Servers) ->
%% hipe_rtl_cfg:pp(RtlCfg3),
pp(RtlCfg3, MFA, rtl_liveness, pp_rtl_liveness, Options, Servers),
RtlCfg4 = rtl_lcm(RtlCfg3, Options),
pp(RtlCfg4, MFA, rtl, pp_rtl, Options, Servers),
LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg4),
%% LLVM: A liveness analysis on RTL must be performed in order to find the GC
%% roots and explicitly mark them (in RTL) when they go out of scope (only
%% when the LLVM backend is used).
{RtlCfg5, Roots} =
case proplists:get_bool(to_llvm, Options) of
false ->
{RtlCfg4, []};
true ->
hipe_llvm_liveness:analyze(RtlCfg4)
end,
pp(RtlCfg5, MFA, rtl, pp_rtl, Options, Servers),
LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg5),
LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
%% hipe_rtl:pp(standard_io, LinearRTL2),
LinearRTL2.
{LinearRTL2, Roots}.
translate_to_rtl(Icode, Options) ->
%% GC tests should have been added in the conversion to Icode.
@@ -540,6 +557,17 @@ rtl_to_native(MFA, LinearRTL, Options, DebugState) ->
put(hipe_debug, DebugState),
LinearNativeCode.
%% Translate Linear RTL to binary code using LLVM.
rtl_to_llvm_to_binary(MFA, LinearRTL, Roots, Options, DebugState) ->
?opt_start_timer("LLVM native code"),
%% BinaryCode is a tuple, as defined in llvm/hipe_llvm_main module, which
%% contains the binary code together with info needed by the loader, e.g.
%% ConstTab, Refs, LabelMap, etc.
BinaryCode = hipe_llvm_main:rtl_to_native(MFA, LinearRTL, Roots, Options),
?opt_stop_timer("LLVM native code"),
put(hipe_debug, DebugState),
{llvm_binary, BinaryCode}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Debugging stuff ...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
View
@@ -44,7 +44,7 @@
%% Types of allowable entities to set global variables for
%%-----------------------------------------------------------------------
-type gvarname() :: 'icode' | 'rtl' | 'arm' | 'ppc' | 'sparc' | 'x86'.
-type gvarname() :: 'icode' | 'rtl' | 'arm' | 'ppc' | 'sparc' | 'x86' | 'llvm'.
%%-----------------------------------------------------------------------
View
@@ -20,30 +20,48 @@
%%
-module(hipe_pack_constants).
-export([pack_constants/2, slim_refs/1, slim_constmap/1]).
-export([pack_constants/2, slim_refs/1, slim_constmap/1,
find_const/2, mk_data_relocs/2, slim_sorted_exportmap/3]).
-include("hipe_consttab.hrl").
-include("../../kernel/src/hipe_ext_format.hrl").
-include("../main/hipe.hrl"). % Needed for the EXIT macro in find_const/2.
%%-----------------------------------------------------------------------------
-type raw_data() :: binary() | number() | list() | tuple().
-type tbl_ref() :: {hipe_constlbl(), non_neg_integer()}.
-type const_num() :: non_neg_integer().
-type raw_data() :: binary() | number() | list() | tuple().
-type addr() :: non_neg_integer().
-type ref_p() :: {DataPos :: hipe_constlbl(), CodeOffset :: addr()}.
-type ref() :: ref_p() | {'sorted', Base :: addr(), [ref_p()]}.
-type mfa_refs() :: {mfa(), [ref()]}.
%% XXX: these types may not belong here: FIX!
-type fa() :: {atom(), arity()}.
-type export_map() :: [{addr(), module(), atom(), arity()}].
-record(pcm_entry, {mfa :: mfa(),
label :: hipe_constlbl(),
const_num :: non_neg_integer(),
start :: non_neg_integer(),
const_num :: const_num(),
start :: addr(),
type :: 0 | 1 | 2,
raw_data :: raw_data()}).
-type pcm_entry() :: #pcm_entry{}.
-type label_map() :: gb_trees:tree({mfa(), hipe_constlbl()}, addr()).
%% Some of the following types may possibly need to be exported
-type data_relocs() :: [ref()].
-type packed_const_map() :: [pcm_entry()].
-type mfa_refs_map() :: [mfa_refs()].
-type slim_export_map() :: [addr() | module() | atom() | arity() | boolean()].
%%-----------------------------------------------------------------------------
-spec pack_constants([{mfa(),[_],hipe_consttab()}], ct_alignment()) ->
{ct_alignment(),
non_neg_integer(),
[#pcm_entry{}],
[{mfa(),[tbl_ref() | {'sorted',non_neg_integer(),[tbl_ref()]}]}]}.
{ct_alignment(), non_neg_integer(), packed_const_map(), mfa_refs_map()}.
pack_constants(Data, Align) ->
pack_constants(Data, 0, Align, 0, [], []).
@@ -194,13 +212,12 @@ compact_dests([], Dest, AccofDest, Acc) ->
%% to the slimmed and flattened format ConstMap which is put in object
%% files.
%%
-spec slim_constmap([#pcm_entry{}]) -> [raw_data()].
-spec slim_constmap(packed_const_map()) -> [raw_data()].
slim_constmap(Map) ->
slim_constmap(Map, gb_sets:new(), []).
-spec slim_constmap([#pcm_entry{}], gb_sets:set(), [raw_data()]) -> [raw_data()].
slim_constmap([#pcm_entry{const_num=ConstNo, start=Offset,
type=Type, raw_data=Term}|Rest], Inserted, Acc) ->
slim_constmap([#pcm_entry{const_num = ConstNo, start = Offset,
type = Type, raw_data = Term}|Rest], Inserted, Acc) ->
case gb_sets:is_member(ConstNo, Inserted) of
true ->
slim_constmap(Rest, Inserted, Acc);
@@ -209,3 +226,60 @@ slim_constmap([#pcm_entry{const_num=ConstNo, start=Offset,
slim_constmap(Rest, NewInserted, [ConstNo, Offset, Type, Term|Acc])
end;
slim_constmap([], _Inserted, Acc) -> Acc.
%%
%% Lookup a constant in a ConstMap.
%%
-spec find_const({mfa(), hipe_constlbl()}, packed_const_map()) -> const_num().
find_const({MFA, Label}, [E = #pcm_entry{mfa = MFA, label = Label}|_]) ->
E#pcm_entry.const_num;
find_const(N, [_|R]) ->
find_const(N, R);
find_const(C, []) ->
?EXIT({constant_not_found, C}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Functions to build and handle Refs, ExportMap and LabelMap.
%% Note: Moved here because they are used by all backends in
%% hipe_{arm,sparc,ppc,x86}_assemble.erl
%% XXX: Is this the right place for them?
%%
-spec mk_data_relocs(mfa_refs_map(), label_map()) -> data_relocs().
mk_data_relocs(RefsFromConsts, LabelMap) ->
lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
mk_data_relocs([{MFA, Labels} | Rest], LabelMap, Acc) ->
Map = [case Label of
{L,Pos} ->
Offset = find({MFA,L}, LabelMap),
{Pos,Offset};
{sorted,Base,OrderedLabels} ->
{sorted, Base, [begin
Offset = find({MFA,L}, LabelMap),
{Order, Offset}
end
|| {L,Order} <- OrderedLabels]}
end
|| Label <- Labels],
%% msg("Map: ~w Map\n", [Map]),
mk_data_relocs(Rest, LabelMap, [Map,Acc]);
mk_data_relocs([], _, Acc) -> Acc.
find({MFA,L}, LabelMap) ->
gb_trees:get({MFA,L}, LabelMap).
-spec slim_sorted_exportmap(export_map(), [mfa()], [fa()]) -> slim_export_map().
slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
IsClosure = lists:member({M,F,A}, Closures),
IsExported = is_exported(F, A, Exports),
[Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
slim_sorted_exportmap([], _, _) -> [].
is_exported(F, A, Exports) ->
lists:member({F,A}, Exports).
View
@@ -46,8 +46,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
print("Total num bytes=~w\n", [CodeSize], Options),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
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_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -288,7 +288,7 @@ do_pseudo_li(I, MFA, ConstMap) ->
%%% end,
%%% {load_address, {Tag,untag_mfa_or_prim(MFAorPrim)}};
{Label,constant} ->
ConstNo = find_const({MFA,Label}, ConstMap),
ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{load_address, {constant,ConstNo}};
{Label,closure} ->
{load_address, {closure,Label}};
@@ -574,37 +574,6 @@ mk_y(Pred, BD) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
mk_data_relocs(RefsFromConsts, LabelMap) ->
lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
Map = [case Label of
{L,Pos} ->
Offset = find({MFA,L}, LabelMap),
{Pos,Offset};
{sorted,Base,OrderedLabels} ->
{sorted, Base, [begin
Offset = find({MFA,L}, LabelMap),
{Order, Offset}
end
|| {L,Order} <- OrderedLabels]}
end
|| Label <- Labels],
%% msg("Map: ~w Map\n",[Map]),
mk_data_relocs(Rest, LabelMap, [Map,Acc]);
mk_data_relocs([],_,Acc) -> Acc.
find({_MFA,_L} = MFAL,LabelMap) ->
gb_trees:get(MFAL, LabelMap).
slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
IsClosure = lists:member({M,F,A}, Closures),
IsExported = is_exported(F, A, Exports),
[Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
slim_sorted_exportmap([],_,_) -> [].
is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -642,14 +611,3 @@ fill_spaces(N) when N > 0 ->
fill_spaces(N-1);
fill_spaces(0) ->
[].
%%%
%%% Lookup a constant in a ConstMap.
%%%
find_const({MFA,Label}, [{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
ConstNo;
find_const(N, [_|R]) ->
find_const(N, R);
find_const(C, []) ->
?EXIT({constant_not_found,C}).
View
@@ -29,7 +29,7 @@
%% <li> {alu, Dst, Src1, Op, Src2} </li>
%% <li> {alub, Dst, Src1, Op, Src2, RelOp, TrueLabel, FalseLabel, P} </li>
%% <li> {branch, Src1, Src2, RelOp, TrueLabel, FalseLabel, P} </li>
%% <li> {call, DsListt, Fun, ArgList, Type, Continuation, FailContinuation}
%% <li> {call, DsListt, Fun, ArgList, Type, Continuation, FailContinuation, NormalContinuation}
%% Type is one of {local, remote, primop, closure} </li>
%% <li> {comment, Text} </li>
%% <li> {enter, Fun, ArgList, Type}
@@ -106,7 +106,7 @@
%% rtl_data_update/2,
%% rtl_var_range/1,
%% rtl_var_range_update/2,
%% rtl_label_range/1,
rtl_label_range/1,
%% rtl_label_range_update/2,
rtl_info/1,
rtl_info_update/2]).
@@ -226,15 +226,18 @@
%% goto_label_update/2,
mk_call/6,
mk_call/7,
call_fun/1,
call_dstlist/1,
call_dstlist_update/2,
call_arglist/1,
call_continuation/1,
call_fail/1,
call_type/1,
call_normal/1,
call_normal_update/2,
%% call_continuation_update/2,
%% call_fail_update/2,
call_fail_update/2,
is_call/1,
mk_enter/3,
@@ -290,10 +293,13 @@
%% fconv_src_update/2,
%% is_fconv/1,
%% mk_var/1,
mk_var/1,
mk_var/2,
mk_new_var/0,
is_var/1,
var_index/1,
var_liveness/1,
var_liveness_update/2,
%% change_vars_to_regs/1,
@@ -350,10 +356,15 @@
%% move_dst_update/2,
fixnumop_dst_update/2,
pp_instr/2,
%% pp_arg/2,
%% Uber hack!
pp_var/2,
pp_reg/2,
pp_arg/2,
phi_arglist_update/2,
phi_redirect_pred/3]).
-export([subst_uses_llvm/2]).
-export_type([alub_cond/0]).
%%
@@ -387,7 +398,7 @@ rtl_data(#rtl{data=Data}) -> Data.
%% rtl_data_update(Rtl, Data) -> Rtl#rtl{data=Data}.
%% rtl_var_range(#rtl{var_range=VarRange}) -> VarRange.
%% rtl_var_range_update(Rtl, VarRange) -> Rtl#rtl{var_range=VarRange}.
%% rtl_label_range(#rtl{label_range=LabelRange}) -> LabelRange.
rtl_label_range(#rtl{label_range=LabelRange}) -> LabelRange.
%% rtl_label_range_update(Rtl, LabelRange) -> Rtl#rtl{label_range=LabelRange}.
rtl_info(#rtl{info=Info}) -> Info.
rtl_info_update(Rtl, Info) -> Rtl#rtl{info=Info}.
@@ -643,6 +654,17 @@ is_goto(_) -> false.
%% call
%%
%% LLVM: Call with normal continuation
mk_call(DstList, Fun, ArgList, Continuation, FailContinuation,
NormalContinuation, Type) ->
case Type of
remote -> ok;
not_remote -> ok
end,
#call{dstlist=DstList, 'fun'=Fun, arglist=ArgList, type=Type,
continuation=Continuation, failcontinuation=FailContinuation,
normalcontinuation=NormalContinuation}.
mk_call(DstList, Fun, ArgList, Continuation, FailContinuation, Type) ->
case Type of
remote -> ok;
@@ -651,6 +673,10 @@ mk_call(DstList, Fun, ArgList, Continuation, FailContinuation, Type) ->
#call{dstlist=DstList, 'fun'=Fun, arglist=ArgList, type=Type,
continuation=Continuation,
failcontinuation=FailContinuation}.
call_normal(#call{normalcontinuation=NormalContinuation}) -> NormalContinuation.
call_normal_update(C, NewNormalContinuation) ->
C#call{normalcontinuation=NewNormalContinuation}.
call_dstlist(#call{dstlist=DstList}) -> DstList.
call_dstlist_update(C, NewDstList) -> C#call{dstlist=NewDstList}.
call_fun(#call{'fun'=Fun}) -> Fun.
@@ -853,11 +879,14 @@ reg_is_gcsafe(#rtl_reg{is_gc_safe=IsGcSafe}) -> IsGcSafe.
is_reg(#rtl_reg{}) -> true;
is_reg(_) -> false.
-record(rtl_var, {index :: non_neg_integer()}).
-record(rtl_var, {index :: non_neg_integer(), liveness=live :: dead | live}).
mk_var(Num) when is_integer(Num), Num >= 0 -> #rtl_var{index=Num}.
mk_var(Num, Liveness) when is_integer(Num), Num>=0 -> #rtl_var{index=Num, liveness=Liveness}.
mk_new_var() -> mk_var(hipe_gensym:get_next_var(rtl)).
var_index(#rtl_var{index=Index}) -> Index.
var_liveness(#rtl_var{liveness=Liveness}) -> Liveness.
var_liveness_update(RtlVar, Liveness) -> RtlVar#rtl_var{liveness=Liveness}.
is_var(#rtl_var{}) -> true;
is_var(_) -> false.
@@ -1077,6 +1106,131 @@ subst_uses(Subst, I) ->
switch_src_update(I, subst1(Subst, switch_src(I)))
end.
subst_uses_llvm(Subst, I) ->
case I of
#alu{} ->
{NewSrc2, Subst1} = subst1_llvm(Subst, alu_src2(I)),
{NewSrc1, _ } = subst1_llvm(Subst1, alu_src1(I)),
I0 = alu_src1_update(I, NewSrc1),
alu_src2_update(I0, NewSrc2);
#alub{} ->
{NewSrc2, Subst1} = subst1_llvm(Subst, alub_src2(I)),
{NewSrc1, _ } = subst1_llvm(Subst1, alub_src1(I)),
I0 = alub_src1_update(I, NewSrc1),
alub_src2_update(I0, NewSrc2);
#branch{} ->
{NewSrc2, Subst1} = subst1_llvm(Subst, branch_src2(I)),
{NewSrc1, _ } = subst1_llvm(Subst1, branch_src1(I)),
I0 = branch_src1_update(I, NewSrc1),
branch_src2_update(I0, NewSrc2);
#call{} ->
case call_is_known(I) of
false ->
{NewFun, Subst1} = subst1_llvm(Subst, call_fun(I)),
{NewArgList, _} = subst_list_llvm(Subst1, call_arglist(I)),
I0 = call_fun_update(I, NewFun),
call_arglist_update(I0, NewArgList);
true ->
{NewArgList, _} = subst_list_llvm(Subst, call_arglist(I)),
call_arglist_update(I, NewArgList)
end;
#comment{} ->
I;
#enter{} ->
case enter_is_known(I) of
false ->
{NewFun, Subst1} = subst1_llvm(Subst, enter_fun(I)),
{NewArgList, _} = subst_list_llvm(Subst1, enter_arglist(I)),
I0 = enter_fun_update(I, NewFun),
enter_arglist_update(I0, NewArgList);
true ->
{NewArgList, _} = subst_list_llvm(Subst, enter_arglist(I)),
enter_arglist_update(I, NewArgList)
end;
#fconv{} ->
{NewSrc, _ } = subst1_llvm(Subst, fconv_src(I)),
fconv_src_update(I, NewSrc);
#fixnumop{} ->
{NewSrc, _ } = subst1_llvm(Subst, fixnumop_src(I)),
fixnumop_src_update(I, NewSrc);
#fload{} ->
{NewSrc, Subst1} = subst1_llvm(Subst, fload_src(I)),
{NewOffset, _ } = subst1_llvm(Subst1, fload_offset(I)),
I0 = fload_src_update(I, NewSrc),
fload_offset_update(I0, NewOffset);
#fmove{} ->
{NewSrc, _ } = subst1_llvm(Subst, fmove_src(I)),
fmove_src_update(I, NewSrc);
#fp{} ->
{NewSrc2, Subst1} = subst1_llvm(Subst, fp_src2(I)),
{NewSrc1, _ } = subst1_llvm(Subst1, fp_src1(I)),
I0 = fp_src1_update(I, NewSrc1),
fp_src2_update(I0, NewSrc2);
#fp_unop{} ->
{NewSrc, _ } = subst1_llvm(Subst, fp_unop_src(I)),
fp_unop_src_update(I, NewSrc);
#fstore{} ->
{NewSrc, Subst1} = subst1_llvm(Subst, fstore_src(I)),
{NewBase, Subst2} = subst1_llvm(Subst1, fstore_base(I)),
{NewOffset, _ } = subst1_llvm(Subst2, fstore_offset(I)),
I0 = fstore_src_update(I, NewSrc),
I1 = fstore_base_update(I0, NewBase),
fstore_offset_update(I1, NewOffset);
#goto{} ->
I;
#goto_index{} ->
I;
#gctest{} ->
{NewWords, _ } = subst1_llvm(Subst, gctest_words(I)),
gctest_words_update(I, NewWords);
#label{} ->
I;
#load{} ->
{NewSrc, Subst1} = subst1_llvm(Subst, load_src(I)),
{NewOffset, _ } = subst1_llvm(Subst1, load_offset(I)),
I0 = load_src_update(I, NewSrc),
load_offset_update(I0, NewOffset);
#load_address{} ->
I;
#load_atom{} ->
I;
#load_word_index{} ->
I;
#move{} ->
{NewSrc, _ } = subst1_llvm(Subst, move_src(I)),
move_src_update(I, NewSrc);
#multimove{} ->
{NewSrcList, _} = subst_list_llvm(Subst, multimove_srclist(I)),
multimove_srclist_update(I, NewSrcList);
#phi{} ->
phi_argvar_subst(I, Subst);
#return{} ->
{NewVarList, _} = subst_list_llvm(Subst, return_varlist(I)),
return_varlist_update(I, NewVarList);
#store{} ->
{NewSrc, Subst1} = subst1_llvm(Subst, store_src(I)),
{NewBase, Subst2} = subst1_llvm(Subst1, store_base(I)),
{NewOffset, _ } = subst1_llvm(Subst2, store_offset(I)),
I0 = store_src_update(I, NewSrc),
I1 = store_base_update(I0, NewBase),
store_offset_update(I1, NewOffset);
#switch{} ->
{NewSrc, _ } = subst1_llvm(Subst, switch_src(I)),
switch_src_update(I, NewSrc)
end.
subst_list_llvm(S,X) -> subst_list_llvm(S, lists:reverse(X), []).
subst_list_llvm(S, [], Acc) -> {Acc, S};
subst_list_llvm(S, [X|Xs], Acc) ->
{NewX, RestS} = subst1_llvm(S, X),
subst_list_llvm(RestS, Xs, [NewX|Acc]).
subst1_llvm(A,B) -> subst1_llvm(A,B,[]).
subst1_llvm([], X, Acc) -> {X, Acc};
subst1_llvm([{X,Y}|Rs], X, Acc) -> {Y, Acc++Rs};
subst1_llvm([R|Xs], X, Acc) -> subst1_llvm(Xs,X,[R|Acc]).
subst_defines(Subst, I)->
case I of
#alu{} ->
@@ -1614,7 +1768,11 @@ pp_var(Dev, Arg) ->
true ->
pp_hard_reg(Dev, var_index(Arg));
false ->
io:format(Dev, "v~w", [var_index(Arg)])
io:format(Dev, "v~w", [var_index(Arg)]),
case var_liveness(Arg) of
dead -> io:format(Dev, "(dead)", []);
_ -> ok
end
end.
pp_arg(Dev, A) ->
View
@@ -28,7 +28,8 @@
-record(alu, {dst, src1, op, src2}).
-record(alub, {dst, src1, op, src2, 'cond', true_label, false_label, p}).
-record(branch, {src1, src2, 'cond', true_label, false_label, p}).
-record(call, {dstlist, 'fun', arglist, type, continuation, failcontinuation}).
-record(call, {dstlist, 'fun', arglist, type, continuation,
failcontinuation, normalcontinuation = []}).
-record(comment, {text}).
-record(enter, {'fun', arglist, type}).
-record(fconv, {dst, src}).
View
@@ -34,7 +34,8 @@
-module(hipe_rtl_liveness).
%% -define(LIVEOUT_NEEDED,true). % needed for liveness.inc below.
%% -define(DEBUG_LIVENESS,true).
-define(LIVEOUT_NEEDED,true). % needed for liveness.inc below.
-define(PRETTY_PRINT,false).
-include("hipe_rtl.hrl").
View
@@ -45,8 +45,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
print("Total num bytes=~w\n", [CodeSize], Options),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
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_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -222,7 +222,7 @@ do_pseudo_set(I, MFA, ConstMap) ->
%%% end,
%%% {load_address, {Tag,untag_mfa_or_prim(MFAorPrim)}};
{Label,constant} ->
ConstNo = find_const({MFA,Label}, ConstMap),
ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{load_address, {constant,ConstNo}};
{Label,closure} ->
{load_address, {closure,Label}};
@@ -507,37 +507,6 @@ px({pred,Pred}) -> % XXX: use pt/pn throughout entire backend
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
mk_data_relocs(RefsFromConsts, LabelMap) ->
lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
Map = [case Label of
{L,Pos} ->
Offset = find({MFA,L}, LabelMap),
{Pos,Offset};
{sorted,Base,OrderedLabels} ->
{sorted, Base, [begin
Offset = find({MFA,L}, LabelMap),
{Order, Offset}
end
|| {L,Order} <- OrderedLabels]}
end
|| Label <- Labels],
%% msg("Map: ~w Map\n",[Map]),
mk_data_relocs(Rest, LabelMap, [Map,Acc]);
mk_data_relocs([],_,Acc) -> Acc.
find({_MFA,_L} = MFAL, LabelMap) ->
gb_trees:get(MFAL, LabelMap).
slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
IsClosure = lists:member({M,F,A}, Closures),
IsExported = is_exported(F, A, Exports),
[Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
slim_sorted_exportmap([],_,_) -> [].
is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -575,14 +544,3 @@ fill_spaces(N) when N > 0 ->
fill_spaces(N-1);
fill_spaces(0) ->
[].
%%%
%%% Lookup a constant in a ConstMap.
%%%
find_const({MFA,Label},[{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
ConstNo;
find_const(N,[_|R]) ->
find_const(N,R);
find_const(C,[]) ->
?EXIT({constant_not_found,C}).
View
@@ -21,7 +21,6 @@
%%%
%%% TODO:
%%% - Simplify combine_label_maps and mk_data_relocs.
%%% - Move find_const to hipe_pack_constants?
-ifdef(HIPE_AMD64).
-define(HIPE_X86_ASSEMBLE, hipe_amd64_assemble).
@@ -80,8 +79,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
%% ?debug_msg("Constants are ~w bytes\n",[ConstSize])),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
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_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -442,7 +441,7 @@ translate_imm(#x86_imm{value=Imm}, Context, MayTrunc8) ->
case Imm of
{Label,constant} ->
{MFA,ConstMap} = Context,
ConstNo = find_const({MFA,Label}, ConstMap),
ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{constant,ConstNo};
{Label,closure} ->
{closure,Label};
@@ -712,7 +711,7 @@ resolve_jmp_switch_arg(I, _Context) ->
{rm64,hipe_amd64_encode:rm_mem(EA)}.
-else.
resolve_jmp_switch_arg(I, {MFA,ConstMap}) ->
ConstNo = find_const({MFA,hipe_x86:jmp_switch_jtab(I)}, 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
@@ -932,37 +931,6 @@ resolve_x87_binop_args(Src=#x86_fpreg{}, Dst=#x86_fpreg{})->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
mk_data_relocs(RefsFromConsts, LabelMap) ->
lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
Map = [case Label of
{L,Pos} ->
Offset = find({MFA,L}, LabelMap),
{Pos,Offset};
{sorted,Base,OrderedLabels} ->
{sorted, Base, [begin
Offset = find({MFA,L}, LabelMap),
{Order, Offset}
end
|| {L,Order} <- OrderedLabels]}
end
|| Label <- Labels],
%% msg("Map: ~w Map\n",[Map]),
mk_data_relocs(Rest, LabelMap, [Map,Acc]);
mk_data_relocs([],_,Acc) -> Acc.
find({MFA,L},LabelMap) ->
gb_trees:get({MFA,L}, LabelMap).
slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
IsClosure = lists:member({M,F,A}, Closures),
IsExported = is_exported(F, A, Exports),
[Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
slim_sorted_exportmap([],_,_) -> [].
is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -1001,14 +969,3 @@ fill_spaces(N) when N > 0 ->
fill_spaces(N-1);
fill_spaces(0) ->
[].
%%%
%%% Lookup a constant in a ConstMap.
%%%
find_const({MFA,Label},[{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
ConstNo;
find_const(N,[_|R]) ->
find_const(N,R);
find_const(C,[]) ->
?EXIT({constant_not_found,C}).
View
@@ -194,6 +194,13 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
CodeSize, CodeBinary, Refs,
0,[] % ColdSize, CRrefs
] = binary_to_term(Bin),
?debug_msg("***** ErLLVM *****~nVersion: ~s~nCheckSum: ~w~nConstAlign: ~w~n" ++
"ConstSize: ~w~nConstMap: ~w~nLabelMap: ~w~nExportMap ~w~nRefs ~w~n",
[Version, CheckSum, ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap,
Refs]),
%% Write HiPE binary code to a file in the current directory in order to
%% debug by disassembling.
%% file:write_file("erl.o", CodeBinary, [binary]),
%% Check that we are loading up-to-date code.
version_check(Version, Mod),
case hipe_bifs:check_crc(CheckSum) of
@@ -221,6 +228,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
{MFAs,Addresses} = exports(ExportMap, CodeAddress),
%% Remove references to old versions of the module.
ReferencesToPatch = get_refs_from(MFAs, []),
%% io:format("References to patch: ~w~n", [ReferencesToPatch]),
ok = remove_refs_from(MFAs),
%% Patch all dynamic references in the code.
%% Function calls, Atoms, Constants, System calls
@@ -246,8 +254,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
AddressesOfClosuresToPatch =
calculate_addresses(ClosurePatches, CodeAddress, Addresses),
export_funs(Addresses),
export_funs(Mod, BeamBinary, Addresses, AddressesOfClosuresToPatch),
ok
export_funs(Mod, BeamBinary, Addresses, AddressesOfClosuresToPatch)
end,
%% Redirect references to the old module to the new module's BEAM stub.
patch_to_emu_step2(OldReferencesToPatch),