Skip to content

Commit

Permalink
Trying to incorporate llvm backend to hipe
Browse files Browse the repository at this point in the history
Changed the way llvm backend is triggered, in order to run independently
from the amd64 backend. Also changed backend to be more compatible with
hipe_unified_loader.
  • Loading branch information
cstavr authored and yiannist committed Mar 5, 2014
1 parent 2e786a2 commit d8d26bc
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 125 deletions.
25 changes: 21 additions & 4 deletions lib/hipe/llvm/hipe_llvm_main.erl
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
-module(hipe_llvm_main).
-export([rtl_to_native/2]).

-include("../main/hipe.hrl").
-include("../rtl/hipe_literals.hrl").

rtl_to_native(RTL, _Options) ->
%% Get LLVM Instruction List
{LLVMCode, RefDict} = hipe_rtl2llvm:translate(RTL),
{LLVMCode, RefDict, ConstMap} = hipe_rtl2llvm:translate(RTL),
%% Write LLVM Assembly to intermediate file
Fun = hipe_rtl:rtl_fun(RTL),
IsClosure = hipe_rtl:rtl_is_closure(RTL),
IsLeaf = hipe_rtl:rtl_is_leaf(RTL),
{Mod_Name, Fun_Name, Arity} = Fun,
Filename = atom_to_list(Fun_Name) ++ "_" ++ integer_to_list(Arity),
{ok, File_llvm} = file:open(Filename ++ ".ll", [write]),
Expand All @@ -21,7 +25,6 @@ rtl_to_native(RTL, _Options) ->
ObjBin = elf64_format:open_object_file(Object_filename),
%% Get relocation info and write to file for loader
Relocs = elf64_format:get_call_list(ObjBin),
io:format("Relocs are ~w", [Relocs]),
%% Temporary code for creating references needed by the loader
_Relocs = lists:filter(fun({A,B}) -> case A of [] -> false; _ -> true end end,
Relocs),
Expand Down Expand Up @@ -53,11 +56,25 @@ rtl_to_native(RTL, _Options) ->
{Atoms1, BIFs} = lists:partition(Is_atom, Rest1),
Atoms = lists:map(fun ({{'atom', Name}, X}) -> {Name,X} end, Atoms1),
FinalRelocs = [{2, MFAs},{3, BIFs}, {1, Constants}, {0, Atoms}],
ok = file:write_file(Filename ++ "_relocs.o", erlang:term_to_binary(FinalRelocs), [binary]),
%% Get binary code and write to file for loader
BinCode = elf64_format:extract_text(ObjBin),
ok = file:write_file(Filename ++ "_code.o", BinCode, [binary]),
{BinCode, FinalRelocs}.
%%--------------------------------------------------------------------------
%% Create All Information needed by the hipe_unified_loader
%% Stadar Values for amd64 ??
ConstAlign = 8,
ConstSize = 0,
%% No Labelmap Used yet..
LabelMap = [],
ExportMap = {0, Mod_Name, Fun_Name, Arity, IsClosure, IsLeaf},
CodeSize = byte_size(BinCode),
CodeBinary = BinCode,
Refs = FinalRelocs,
[{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap,
CodeSize, CodeBinary, Refs,
0,[] % ColdSize, CRrefs
].


fix_opts(Opts) ->
Expand Down
4 changes: 1 addition & 3 deletions lib/hipe/llvm/hipe_rtl2llvm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ translate(RTL) ->
{ConstAlign,ConstSize,ConstMap,RefsFromConsts} =
hipe_pack_constants:pack_constants([{Fun, [], Data}], ?HIPE_X86_REGISTERS:alignment()),
SC = hipe_pack_constants:slim_constmap(ConstMap),
file:write_file(atom_to_list(Fun_Name) ++ "_" ++ integer_to_list(Arity) ++
"_constmap.o", erlang:term_to_binary(SC), [binary]),
%% Extract constant labels from Constant Map (remove duplicates)
ConstLabels = lists:ukeysort(1, find_constants(SC)),
%% io:format("--> RTL2LLVM: Constant Labels Found: ~w~n", [ConstLabels]),
Expand Down Expand Up @@ -76,7 +74,7 @@ translate(RTL) ->
CallDict4 = lists:foldl(fun atom_to_dict/2, CallDict3, Atoms),
%% Temporary Store inc_stack to Dictionary
CallDict5 = dict:store("@inc_stack_0", {inc_stack_0}, CallDict4),
{LLVM_Code3, CallDict5}.
{LLVM_Code3, CallDict5, SC}.

%%-----------------------------------------------------------------------------

Expand Down
152 changes: 122 additions & 30 deletions lib/hipe/main/hipe.erl
Original file line number Diff line number Diff line change
Expand Up @@ -726,9 +726,98 @@ compiler_return(Res, Client) ->
Client ! {self(), Res}.

compile_finish({Mod, Exports, Icode}, WholeModule, Options) ->
Res = finalize(Icode, Mod, Exports, WholeModule, Options),
%% LLVM:
case proplists:get_bool(to_llvm, Options) of
true -> Res = llvm_finalize(Icode, Mod, Exports, WholeModule, Options);
false -> Res = finalize(Icode, Mod, Exports, WholeModule, Options)
end,
post(Res, Icode, Options).

%%% LLVM:
%%%
%%% Finalize Compilation Using LLVM
%%%
llvm_finalize(OrigList, Mod, Exports, WholeModule, Opts) ->
List = icode_multret(OrigList, Mod, Opts, Exports),
Closures =
[MFA || {MFA, Icode} <- List,
hipe_icode:icode_is_closure(Icode)],
Bin =
case proplists:get_value(use_callgraph, Opts) of
true ->
%% Compiling the functions bottom-up by using a call graph
CallGraph = hipe_icode_callgraph:construct(List),
OrdList = hipe_icode_callgraph:to_list(CallGraph),
finalize_fun(OrdList, Exports, Opts);
_ ->
%% Compiling the functions bottom-up by reversing the list
OrdList = lists:reverse(List),
finalize_fun(OrdList, Exports, Opts)
end,
{_, Bin1} = lists:unzip(Bin),
FinalBin = fix_llvm_binary(Bin1),
{module,Mod} = maybe_load(Mod, FinalBin, WholeModule, Opts),
TargetArch = get(hipe_target_arch),
{ok, {TargetArch, FinalBin}}.

%% Convert term to binary as expected by the the hipe_unified_loader.
%% Also In a case where more than one functions are compiled(whole module
%% compilation or closures), we must pack them all to one term.
fix_llvm_binary(Bin) ->
{CodeSize, ExportMap, Refs, CodeBinary, ConstMap} = merge(Bin),
[FirstMFA| _] = Bin,
[{Version, CheckSum}, ConstAlign, ConstSize, _, LabelMap, _, _, _, _, _, _] =
FirstMFA,
term_to_binary(
[{Version, CheckSum}, ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap,
CodeSize, CodeBinary, Refs, 0, []]
).

merge(Bin) -> merge(Bin, 0 ,[], [], <<>>, [], 0).
merge([
[_, _, _, MFAConstMap, _, {0, M, F, A, IC, IL}, CodeSize, Code1, Refs1, _, _]
| Rest],
Size, ExportMap, Refs, Code, ConstMap, Base) ->
NewRefs = add_offset_to_relocs(Refs1, Size),
{NewConstmap, NewRefs2, NewBase} = fix_constmap(MFAConstMap, NewRefs, Base,
[]),
merge(Rest, Size+CodeSize, [[Size, M, F, A, IC, IL]|ExportMap],
NewRefs2++Refs, <<Code/binary, Code1/binary>>, NewConstmap++ConstMap,
NewBase);
merge([], Size, ExportMap, Refs, Code, ConstMap, Base) -> {Size, lists:flatten(ExportMap),
Refs, Code, ConstMap}.


fix_constmap([Label, A, B, Const | Rest], Refs, Base, ConstMap) ->
NewRefs = substitute_const_label(Refs, Label, Base),
fix_constmap(Rest, NewRefs, Base+1, [Base, A, B, Const|ConstMap]);
fix_constmap([], Refs, Base, ConstMap) ->
{ConstMap, Refs, Base}.

add_offset_to_relocs(Refs, Size) ->
Update_reloc = fun (X) -> X+Size end,
Update_relocs = fun({X, Relocs}) -> {X, lists:map(Update_reloc, Relocs)} end,
Update_all = fun ({Type, Relocs}) -> {Type, lists:map(Update_relocs, Relocs)} end,
lists:map(Update_all, Refs).

substitute_const_label(Refs, Label, Base) ->
Check_Const =
fun ({X, List}) ->
case X of
{constant, Label} -> {{constant, Base}, List};
_ -> {X,List}
end
end,
Check_Type =
fun ({X, List}) ->
case X of
1 -> {X, lists:map(Check_Const, List)};
_ -> {X, List}
end
end,
lists:map(Check_Type, Refs).



%% -------------------------------------------------------------------------
%% finalize/5
Expand All @@ -739,44 +828,44 @@ finalize(OrigList, Mod, Exports, WholeModule, Opts) ->
List = icode_multret(OrigList, Mod, Opts, Exports),
{T1Compile,_} = erlang:statistics(runtime),
CompiledCode =
case proplists:get_value(use_callgraph, Opts) of
true ->
%% Compiling the functions bottom-up by using a call graph
CallGraph = hipe_icode_callgraph:construct(List),
OrdList = hipe_icode_callgraph:to_list(CallGraph),
finalize_fun(OrdList, Exports, Opts);
_ ->
%% Compiling the functions bottom-up by reversing the list
OrdList = lists:reverse(List),
finalize_fun(OrdList, Exports, Opts)
end,
case proplists:get_value(use_callgraph, Opts) of
true ->
%% Compiling the functions bottom-up by using a call graph
CallGraph = hipe_icode_callgraph:construct(List),
OrdList = hipe_icode_callgraph:to_list(CallGraph),
finalize_fun(OrdList, Exports, Opts);
_ ->
%% Compiling the functions bottom-up by reversing the list
OrdList = lists:reverse(List),
finalize_fun(OrdList, Exports, Opts)
end,
{T2Compile,_} = erlang:statistics(runtime),
?when_option(verbose, Opts,
?debug_msg("Compiled ~p in ~.2f s\n",
[Mod,(T2Compile-T1Compile)/1000])),
?debug_msg("Compiled ~p in ~.2f s\n",
[Mod,(T2Compile-T1Compile)/1000])),
case proplists:get_bool(to_rtl, Opts) of
true ->
{ok, CompiledCode};
false ->
Closures =
[MFA || {MFA, Icode} <- List,
hipe_icode:icode_is_closure(Icode)],
[MFA || {MFA, Icode} <- List,
hipe_icode:icode_is_closure(Icode)],
{T1,_} = erlang:statistics(runtime),
?when_option(verbose, Opts, ?debug_msg("Assembling ~w",[Mod])),
try assemble(CompiledCode, Closures, Exports, Opts) of
Bin ->
{T2,_} = erlang:statistics(runtime),
?when_option(verbose, Opts,
?debug_untagged_msg(" in ~.2f s\n",
[(T2-T1)/1000])),
{module,Mod} = maybe_load(Mod, Bin, WholeModule, Opts),
TargetArch = get(hipe_target_arch),
{ok, {TargetArch,Bin}}
catch
error:Error ->
{error,Error,erlang:get_stacktrace()}
end
end.
Bin ->
{T2,_} = erlang:statistics(runtime),
?when_option(verbose, Opts,
?debug_untagged_msg(" in ~.2f s\n",
[(T2-T1)/1000])),
{module,Mod} = maybe_load(Mod, Bin, WholeModule, Opts),
TargetArch = get(hipe_target_arch),
{ok, {TargetArch,Bin}}
catch
error:Error ->
{error,Error,erlang:get_stacktrace()}
end
end.

finalize_fun(MfaIcodeList, Exports, Opts) ->
case proplists:get_value(concurrent_comp, Opts) of
Expand Down Expand Up @@ -826,7 +915,7 @@ finalize_fun_concurrent(MfaIcodeList, Exports, Opts) ->
set_architecture(Opts),
pre_init(Opts),
init(Opts),
Self ! finalize_fun_sequential(IcodeFun, Opts, Servers)
Self ! finalize_fun_sequential(IcodeFun, Opts, Servers)
end || IcodeFun <- MfaIcodeList],
lists:foreach(fun (F) -> spawn_link(F) end, CompFuns),
Final = [receive Res when element(1, Res) =:= MFA -> Res end
Expand All @@ -853,6 +942,9 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
?when_option(verbose, Opts,
?debug_msg("Compiled ~w in ~.2f s\n", [MFA,(T2-T1)/1000])),
{MFA, Code};
%% LLVM:
{llvm_binary, Binary} ->
{MFA, Binary};
{rtl, LinearRtl} ->
{MFA, LinearRtl}
catch
Expand Down
66 changes: 46 additions & 20 deletions lib/hipe/main/hipe_main.erl
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,17 @@ compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) ->
end,
case proplists:get_bool(to_rtl, Options) of
false ->
rtl_to_native(MFA, LinearRTL, Options, DebugState);
LinearRTL = ?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);
true ->
put(hipe_debug, DebugState),
{rtl, LinearRTL}
end;
true ->
put(hipe_debug, DebugState),
{rtl, LinearRTL}
icode_to_llvm(MFA, FinalIcode, Options, Servers)
end.

%%----------------------------------------------------------------
Expand Down Expand Up @@ -344,6 +351,30 @@ icode_ssa_unconvert(IcodeSSA, Options) ->
?option_time(hipe_icode_ssa:unconvert(IcodeSSA),
"Icode SSA unconversion", Options).

%% LLVM:
%% ---------------------------------------------------------------------------
%% Translate Icode to Binary using LLVM
%% ---------------------------------------------------------------------------
icode_to_llvm(MFA, Icode, Options, Servers) ->
debug("ICODE -> LLVM: ~w, ~w~n", [MFA, hash(Icode)], Options),
LinearRTL = translate_to_rtl(Icode, Options),
pp(LinearRTL, MFA, rtl_linear, pp_rtl_linear, Options, Servers),
RtlCfg = initialize_rtl_cfg(LinearRTL, Options),
%% hipe_rtl_cfg:pp(RtlCfg),
RtlCfg0 = hipe_rtl_cfg:remove_unreachable_code(RtlCfg),
RtlCfg1 = hipe_rtl_cfg:remove_trivial_bbs(RtlCfg0),
%% hipe_rtl_cfg:pp(RtlCfg1),
%% RtlCfg2 = rtl_ssa(RtlCfg1, Options),
RtlCfg2 = rtl_symbolic(RtlCfg1, Options),
%% hipe_rtl_cfg:pp(RtlCfg2),
%%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),
%%LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
%% hipe_rtl:pp(standard_io, LinearRTL2),
%% LLVM:
rtl_to_llvm(RtlCfg1, Options). %STUB: parse RTL in SSA form

%%=====================================================================
%%
Expand Down Expand Up @@ -394,7 +425,6 @@ icode_to_rtl(MFA, Icode, Options, Servers) ->
LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg4),
LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
%% hipe_rtl:pp(standard_io, LinearRTL2),
rtl_llvm(RtlCfg1, Options), %STUB: parse RTL in SSA form
LinearRTL2.

translate_to_rtl(Icode, Options) ->
Expand All @@ -417,22 +447,18 @@ rtl_symbolic(RtlCfg, Options) ->
%% We want naive (no-optimized) code to check LLVM optimizations.
%%
%%----------------------------------------------------------------------
rtl_llvm(RtlCfg0, Options) ->
case proplists:get_bool(to_llvm, Options) of
true ->
RtlCfg1 = rtl_symbolic(RtlCfg0, Options),
RtlSSA0 = rtl_ssa_convert(RtlCfg1, Options),
LinearRtl = hipe_rtl_cfg:linearize(RtlSSA0),
%% RtlSSA1 = rtl_ssa_const_prop(RtlSSA0, Options),
%% RtlSSA1a = rtl_ssa_copy_prop(RtlSSA1, Options),
%% RtlSSA2 = rtl_ssa_dead_code_elimination(RtlSSA1, Options),
%% RtlSSA3 = rtl_ssa_avail_expr(RtlSSA2, Options),
%% RtlSSA4 = rtl_ssapre(RtlSSA3, Options),
%% rtl_ssa_check(RtlSSA4, Options), %% just for sanity
{_Code, _Relocs} = hipe_llvm_main:rtl_to_native(LinearRtl, Options);
false ->
ok
end.
rtl_to_llvm(RtlCfg0, Options) ->
RtlCfg1 = rtl_symbolic(RtlCfg0, Options),
RtlSSA0 = rtl_ssa_convert(RtlCfg1, Options),
LinearRtl = hipe_rtl_cfg:linearize(RtlSSA0),
%% RtlSSA1 = rtl_ssa_const_prop(RtlSSA0, Options),
%% RtlSSA1a = rtl_ssa_copy_prop(RtlSSA1, Options),
%% RtlSSA2 = rtl_ssa_dead_code_elimination(RtlSSA1, Options),
%% RtlSSA3 = rtl_ssa_avail_expr(RtlSSA2, Options),
%% RtlSSA4 = rtl_ssapre(RtlSSA3, Options),
%% rtl_ssa_check(RtlSSA4, Options), %% just for sanity
Binary = hipe_llvm_main:rtl_to_native(LinearRtl, Options),
{llvm_binary, Binary}.


%%----------------------------------------------------------------------
Expand Down
Loading

0 comments on commit d8d26bc

Please sign in to comment.