1%%% -*- erlang-indent-level: 2 -*- 2-module(hipe_llvm_merge). 3 4-export([finalize/3]). 5 6-include("hipe_llvm_arch.hrl"). 7-include("../../kernel/src/hipe_ext_format.hrl"). 8-include("../rtl/hipe_literals.hrl"). 9-include("../main/hipe.hrl"). 10 11finalize(CompiledCode, Closures, Exports) -> 12 CompiledCode1 = [CodePack || {_, CodePack} <- CompiledCode], 13 Code = [{MFA, [], ConstTab} 14 || {MFA, _, _ , ConstTab, _, _} <- CompiledCode1], 15 {ConstAlign, ConstSize, ConstMap, RefsFromConsts} = 16 hipe_pack_constants:pack_constants(Code), 17 %% Compute total code size separately as a sanity check for alignment 18 CodeSize = compute_code_size(CompiledCode1, 0), 19 %% io:format("Code Size (pre-computed): ~w~n", [CodeSize]), 20 {CodeBinary, ExportMap} = merge_mfas(CompiledCode1, 0, <<>>, []), 21 %% io:format("Code Size (post-computed): ~w~n", [byte_size(CodeBinary)]), 22 ?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)), 23 AccRefs = merge_refs(CompiledCode1, ConstMap, 0, []), 24 %% Bring CompiledCode to a combine_label_maps-acceptable form. 25 LabelMap = combine_label_maps(CompiledCode1, 0, gb_trees:empty()), 26 SC = hipe_pack_constants:slim_constmap(ConstMap), 27 DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap), 28 SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap, Closures, Exports), 29 SlimRefs = hipe_pack_constants:slim_refs(AccRefs), 30 term_to_binary([{?VERSION_STRING(),?HIPE_ERTS_CHECKSUM}, 31 ConstAlign, ConstSize, 32 SC, % ConstMap 33 DataRelocs, % LabelMap 34 SSE, % ExportMap 35 CodeSize, CodeBinary, SlimRefs, 36 0,[] % ColdCodeSize, SlimColdRefs 37 ]). 38 39%% Copied from hipe_x86_assemble.erl 40nr_pad_bytes(Address) -> 41 (4 - (Address rem 4)) rem 4. % XXX: 16 or 32 instead? 42 43align_entry(Address) -> 44 Address + nr_pad_bytes(Address). 45 46compute_code_size([{_MFA, _BinaryCode, CodeSize, _, _, _}|Code], Size) -> 47 compute_code_size(Code, align_entry(Size+CodeSize)); 48compute_code_size([], Size) -> Size. 49 50combine_label_maps([{MFA, _, CodeSize, _, _, LabelMap}|Code], Address, CLM) -> 51 NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM), 52 combine_label_maps(Code, align_entry(Address+CodeSize), NewCLM); 53combine_label_maps([], _Address, CLM) -> CLM. 54 55merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) -> 56 NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM), 57 merge_label_map(Rest, MFA, Address, NewCLM); 58merge_label_map([], _MFA, _Address, CLM) -> CLM. 59 60%% @doc Merge the MFAs' binary code to one continuous binary and compute the 61%% size of this binary. At the same time create an exportmap in a form 62%% of {Address, M, F, A}. 63%% XXX: Is alignment correct/optimal for X86/AMD64? 64merge_mfas([{{M,F,A}, CodeBinary, CodeSize, _, _, _}|Code], 65 Address, AccCode, AccExportMap) -> 66 ?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)), 67 {Address1, Code1} = 68 case nr_pad_bytes(Address + CodeSize) of 69 0 -> %% Retains alignment: 70 {Address + CodeSize, CodeBinary}; 71 NrPadBytes -> %% Needs padding! 72 Padding = list_to_binary(lists:duplicate(NrPadBytes, 0)), 73 {Address + CodeSize + NrPadBytes, % =:= align_entry(Address+CodeSize) 74 <<CodeBinary/binary, Padding/binary>>} 75 end, 76 ?VERBOSE_ASSERT(Address1 =:= 77 align_entry(Address + CodeSize)), %XXX: Should address be aligned? 78 AccCode1 = <<AccCode/binary, Code1/binary>>, 79 merge_mfas(Code, Address1, AccCode1, [{Address, M, F, A}|AccExportMap]); 80merge_mfas([], _Address, AccCode, AccExportMap) -> 81 {AccCode, AccExportMap}. 82 83%% @doc Merge the references of relocatable symbols in the binary code. The 84%% offsets must be updated because of the merging of the code binaries! 85merge_refs([], _ConstMap, _Addr, AccRefs) -> AccRefs; 86merge_refs([{MFA, _, CodeSize, _, Refs, _}|Rest], ConstMap, Address, AccRefs) -> 87 %% Important!: The hipe_pack_constants:pack_constants/2 function assignes 88 %% unique numbers to constants (ConstNo). This numbers are used from now on, 89 %% instead of labels that were used before. So, in order to be compatible, we 90 %% must change all the constant labels in the Refs to the corresponding 91 %% ConstNo, that can be found in the ConstMap (#pcm_entry{}). 92 UpdatedRefs = [update_ref(label_to_constno(Ref, MFA, ConstMap), Address) 93 || Ref <- Refs], 94 merge_refs(Rest, ConstMap, align_entry(Address+CodeSize), 95 UpdatedRefs++AccRefs). 96 97label_to_constno({Type, Offset, {constant, Label}}, MFA, ConstMap) -> 98 ConstNo = hipe_pack_constants:find_const({MFA, Label}, ConstMap), 99 {Type, Offset, {constant, ConstNo}}; 100label_to_constno(Other, _MFA, _ConstMap) -> 101 Other. 102 103%% @doc Update offset to a reference. In case of stack descriptors we must check 104%% if there exists an exception handler, because it must also be updated. 105update_ref({?SDESC, Offset, SDesc}, CodeAddr) -> 106 NewRefAddr = Offset+CodeAddr, 107 case SDesc of 108 {[], _, _, _} -> % No handler; only update offset 109 {?SDESC, NewRefAddr, SDesc}; 110 {ExnHandler, FrameSize, StackArity, Roots} -> % Update exception handler 111 {?SDESC, NewRefAddr, {ExnHandler+CodeAddr, FrameSize, StackArity, Roots}} 112 end; 113update_ref({Type, Offset, Term}, CodeAddr) -> 114 {Type, Offset+CodeAddr, Term}. 115