1%% -*- erlang-indent-level: 2 -*- 2 3-module(hipe_rtl_to_llvm). 4-author("Chris Stavrakakis, Yiannis Tsiouris"). 5 6-export([translate/2]). % the main function of this module 7-export([fix_mfa_name/1]). % a help function used in hipe_llvm_main 8 9-include("../rtl/hipe_rtl.hrl"). 10-include("../rtl/hipe_literals.hrl"). 11-include("hipe_llvm_arch.hrl"). 12 13-define(BITS_IN_WORD, (?bytes_to_bits(hipe_rtl_arch:word_size()))). 14-define(BITS_IN_BYTE, (?bytes_to_bits(1))). 15-define(BRANCH_META_TAKEN, "0"). 16-define(BRANCH_META_NOT_TAKEN, "1"). 17-define(FIRST_FREE_META_NO, 2). 18-define(HIPE_LITERALS_META, "hipe.literals"). 19 20%%------------------------------------------------------------------------------ 21%% @doc Main function for translating an RTL function to LLVM Assembly. Takes as 22%% input the RTL code and the variable indexes of possible garbage 23%% collection roots and returns the corresponing LLVM, a dictionary with 24%% all the relocations in the code and a hipe_consttab() with informaton 25%% about data. 26%%------------------------------------------------------------------------------ 27translate(RTL, Roots) -> 28 Fun = hipe_rtl:rtl_fun(RTL), 29 Params = hipe_rtl:rtl_params(RTL), 30 Data = hipe_rtl:rtl_data(RTL), 31 Code = hipe_rtl:rtl_code(RTL), 32 %% Init unique symbol generator and initialize the label counter to the last 33 %% RTL label. 34 hipe_gensym:init(llvm), 35 {_, MaxLabel} = hipe_rtl:rtl_label_range(RTL), 36 put({llvm,label_count}, MaxLabel + 1), 37 %% Put first label of RTL code in process dictionary 38 find_code_entry_label(Code), 39 %% Initialize relocations symbol dictionary 40 Relocs = dict:new(), 41 %% Print RTL to file 42 %% {ok, File_rtl} = file:open("rtl_" ++integer_to_list(random:uniform(2000)) 43 %% ++ ".rtl", [write]), 44 %% hipe_rtl:pp(File_rtl, RTL), 45 %% file:close(File_rtl), 46 47 %% Pass on RTL code to handle exception handling and identify labels of Fail 48 %% Blocks 49 {Code1, FailLabels} = fix_code(Code), 50 %% Allocate stack slots for each virtual register and declare gc roots 51 AllocaStackCode = alloca_stack(Code1, Params, Roots), 52 %% Translate Code 53 {LLVM_Code1, Relocs1, NewData} = 54 translate_instr_list(Code1, [], Relocs, Data), 55 %% Create LLVM code to declare relocation symbols as external symbols along 56 %% with local variables in order to use them as just any other variable 57 {FinalRelocs, ExternalDecl0, LocalVars} = 58 handle_relocations(Relocs1, Data, Fun), 59 ExternalDecl = add_literals_metadata(ExternalDecl0), 60 %% Pass on LLVM code in order to create Fail blocks and a landingpad 61 %% instruction to each one 62 LLVM_Code2 = add_landingpads(LLVM_Code1, FailLabels), 63 %% Create LLVM Code for the compiled function 64 LLVM_Code3 = create_function_definition(Fun, Params, LLVM_Code2, 65 AllocaStackCode ++ LocalVars), 66 %% Final Code = CompiledFunction + External Declarations 67 FinalLLVMCode = [LLVM_Code3 | ExternalDecl], 68 {FinalLLVMCode, FinalRelocs, NewData}. 69 70find_code_entry_label([]) -> 71 exit({?MODULE, find_code_entry_label, "Empty code"}); 72find_code_entry_label([I|_]) -> 73 case hipe_rtl:is_label(I) of 74 true -> 75 put(first_label, hipe_rtl:label_name(I)); 76 false -> 77 exit({?MODULE, find_code_entry_label, "First instruction is not a label"}) 78 end. 79 80%% @doc Create a stack slot for each virtual register. The stack slots 81%% that correspond to possible garbage collection roots must be 82%% marked as such. 83alloca_stack(Code, Params, Roots) -> 84 %% Find all assigned virtual registers 85 Destinations = collect_destinations(Code), 86 %% Declare virtual registers, and declare garbage collection roots 87 do_alloca_stack(Destinations++Params, Params, Roots). 88 89collect_destinations(Code) -> 90 lists:usort(lists:flatmap(fun insn_dst/1, Code)). 91 92do_alloca_stack(Destinations, Params, Roots) -> 93 do_alloca_stack(Destinations, Params, Roots, []). 94 95do_alloca_stack([], _, _, Acc) -> 96 Acc; 97do_alloca_stack([D|Ds], Params, Roots, Acc) -> 98 {Name, _I} = trans_dst(D), 99 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 100 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 101 ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)), 102 case hipe_rtl:is_var(D) of 103 true -> 104 Num = hipe_rtl:var_index(D), 105 I1 = hipe_llvm:mk_alloca(Name, WordTy, [], []), 106 case lists:member(Num, Roots) of 107 true -> %% Variable is a possible Root 108 T1 = mk_temp(), 109 BYTE_TYPE_PP = hipe_llvm:mk_pointer(ByteTyPtr), 110 I2 = 111 hipe_llvm:mk_conversion(T1, bitcast, WordTyPtr, Name, BYTE_TYPE_PP), 112 GcRootArgs = [{BYTE_TYPE_PP, T1}, {ByteTyPtr, "@gc_metadata"}], 113 I3 = hipe_llvm:mk_call([], false, [], [], hipe_llvm:mk_void(), 114 "@llvm.gcroot", GcRootArgs, []), 115 I4 = case lists:member(D, Params) of 116 false -> 117 hipe_llvm:mk_store(WordTy, "-5", WordTyPtr, Name, 118 [], [], false); 119 true -> [] 120 end, 121 do_alloca_stack(Ds, Params, Roots, [I1, I2, I3, I4 | Acc]); 122 false -> 123 do_alloca_stack(Ds, Params, Roots, [I1|Acc]) 124 end; 125 false -> 126 case hipe_rtl:is_reg(D) andalso isPrecoloured(D) of 127 true -> %% Precoloured registers are mapped to "special" stack slots 128 do_alloca_stack(Ds, Params, Roots, Acc); 129 false -> 130 I1 = case hipe_rtl:is_fpreg(D) of 131 true -> 132 FloatTy = hipe_llvm:mk_double(), 133 hipe_llvm:mk_alloca(Name, FloatTy, [], []); 134 false -> hipe_llvm:mk_alloca(Name, WordTy, [], []) 135 end, 136 do_alloca_stack(Ds, Params, Roots, [I1|Acc]) 137 end 138 end. 139 140%%------------------------------------------------------------------------------ 141%% @doc Translation of the linearized RTL Code. Each RTL instruction is 142%% translated to a list of LLVM Assembly instructions. The relocation 143%% dictionary is updated when needed. 144%%------------------------------------------------------------------------------ 145translate_instr_list([], Acc, Relocs, Data) -> 146 {lists:reverse(lists:flatten(Acc)), Relocs, Data}; 147translate_instr_list([I | Is], Acc, Relocs, Data) -> 148 {Acc1, NewRelocs, NewData} = translate_instr(I, Relocs, Data), 149 translate_instr_list(Is, [Acc1 | Acc], NewRelocs, NewData). 150 151translate_instr(I, Relocs, Data) -> 152 case I of 153 #alu{} -> 154 {I2, Relocs2} = trans_alu(I, Relocs), 155 {I2, Relocs2, Data}; 156 #alub{} -> 157 {I2, Relocs2} = trans_alub(I, Relocs), 158 {I2, Relocs2, Data}; 159 #call{} -> 160 {I2, Relocs2} = 161 case hipe_rtl:call_fun(I) of 162 %% In AMD64 this instruction does nothing! 163 %% TODO: chech use of fwait in other architectures! 164 fwait -> 165 {[], Relocs}; 166 _ -> 167 trans_call(I, Relocs) 168 end, 169 {I2, Relocs2, Data}; 170 #comment{} -> 171 {I2, Relocs2} = trans_comment(I, Relocs), 172 {I2, Relocs2, Data}; 173 #enter{} -> 174 {I2, Relocs2} = trans_enter(I, Relocs), 175 {I2, Relocs2, Data}; 176 #fconv{} -> 177 {I2, Relocs2} = trans_fconv(I, Relocs), 178 {I2, Relocs2, Data}; 179 #fload{} -> 180 {I2, Relocs2} = trans_fload(I, Relocs), 181 {I2, Relocs2, Data}; 182 #fmove{} -> 183 {I2, Relocs2} = trans_fmove(I, Relocs), 184 {I2, Relocs2, Data}; 185 #fp{} -> 186 {I2, Relocs2} = trans_fp(I, Relocs), 187 {I2, Relocs2, Data}; 188 #fp_unop{} -> 189 {I2, Relocs2} = trans_fp_unop(I, Relocs), 190 {I2, Relocs2, Data}; 191 #fstore{} -> 192 {I2, Relocs2} = trans_fstore(I, Relocs), 193 {I2, Relocs2, Data}; 194 #goto{} -> 195 {I2, Relocs2} = trans_goto(I, Relocs), 196 {I2, Relocs2, Data}; 197 #label{} -> 198 {I2, Relocs2} = trans_label(I, Relocs), 199 {I2, Relocs2, Data}; 200 #load{} -> 201 {I2, Relocs2} = trans_load(I, Relocs), 202 {I2, Relocs2, Data}; 203 #load_address{} -> 204 {I2, Relocs2} = trans_load_address(I, Relocs), 205 {I2, Relocs2, Data}; 206 #load_atom{} -> 207 {I2, Relocs2} = trans_load_atom(I, Relocs), 208 {I2, Relocs2, Data}; 209 #move{} -> 210 {I2, Relocs2} = trans_move(I, Relocs), 211 {I2, Relocs2, Data}; 212 #return{} -> 213 {I2, Relocs2} = trans_return(I, Relocs), 214 {I2, Relocs2, Data}; 215 #store{} -> 216 {I2, Relocs2} = trans_store(I, Relocs), 217 {I2, Relocs2, Data}; 218 #switch{} -> %% Only switch instruction updates Data 219 {I2, Relocs2, NewData} = trans_switch(I, Relocs, Data), 220 {I2, Relocs2, NewData}; 221 Other -> 222 exit({?MODULE, translate_instr, {"Unknown RTL instruction", Other}}) 223 end. 224 225%% 226%% alu 227%% 228trans_alu(I, Relocs) -> 229 RtlDst = hipe_rtl:alu_dst(I), 230 TmpDst = mk_temp(), 231 {Src1, I1} = trans_src(hipe_rtl:alu_src1(I)), 232 {Src2, I2} = trans_src(hipe_rtl:alu_src2(I)), 233 Op = trans_op(hipe_rtl:alu_op(I)), 234 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 235 I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []), 236 I4 = store_stack_dst(TmpDst, RtlDst), 237 {[I4, I3, I2, I1], Relocs}. 238 239%% 240%% alub 241%% 242trans_alub(I, Relocs) -> 243 case hipe_rtl:alub_cond(I) of 244 Op when Op =:= overflow orelse Op =:= not_overflow -> 245 trans_alub_overflow(I, signed, Relocs); 246 ltu -> %% ltu means unsigned overflow 247 trans_alub_overflow(I, unsigned, Relocs); 248 _ -> 249 trans_alub_no_overflow(I, Relocs) 250 end. 251 252trans_alub_overflow(I, Sign, Relocs) -> 253 {Src1, I1} = trans_src(hipe_rtl:alub_src1(I)), 254 {Src2, I2} = trans_src(hipe_rtl:alub_src2(I)), 255 TmpDst = mk_temp(), 256 Name = trans_alub_op(I, Sign), 257 NewRelocs = relocs_store(Name, {call, remote, {llvm, Name, 2}}, Relocs), 258 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 259 ReturnType = hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]), 260 T1 = mk_temp(), 261 I3 = hipe_llvm:mk_call(T1, false, [], [], ReturnType, "@" ++ Name, 262 [{WordTy, Src1}, {WordTy, Src2}], []), 263 %% T1{0}: result of the operation 264 I4 = hipe_llvm:mk_extractvalue(TmpDst, ReturnType, T1 , "0", []), 265 I5 = case hipe_rtl:alub_has_dst(I) of 266 false -> []; 267 true -> store_stack_dst(TmpDst, hipe_rtl:alub_dst(I)) 268 end, 269 T2 = mk_temp(), 270 %% T1{1}: Boolean variable indicating overflow 271 I6 = hipe_llvm:mk_extractvalue(T2, ReturnType, T1, "1", []), 272 {TrueLabel, FalseLabel, MetaData} = 273 case hipe_rtl:alub_cond(I) of 274 Op when Op =:= overflow orelse Op =:= ltu -> 275 {mk_jump_label(hipe_rtl:alub_true_label(I)), 276 mk_jump_label(hipe_rtl:alub_false_label(I)), 277 branch_metadata(hipe_rtl:alub_pred(I))}; 278 not_overflow -> 279 {mk_jump_label(hipe_rtl:alub_false_label(I)), 280 mk_jump_label(hipe_rtl:alub_true_label(I)), 281 branch_metadata(1 - hipe_rtl:alub_pred(I))} 282 end, 283 I7 = hipe_llvm:mk_br_cond(T2, TrueLabel, FalseLabel, MetaData), 284 {[I7, I6, I5, I4, I3, I2, I1], NewRelocs}. 285 286trans_alub_op(I, Sign) -> 287 Name = 288 case Sign of 289 signed -> 290 case hipe_rtl:alub_op(I) of 291 add -> "llvm.sadd.with.overflow."; 292 mul -> "llvm.smul.with.overflow."; 293 sub -> "llvm.ssub.with.overflow."; 294 Op -> exit({?MODULE, trans_alub_op, {"Unknown alub operator", Op}}) 295 end; 296 unsigned -> 297 case hipe_rtl:alub_op(I) of 298 add -> "llvm.uadd.with.overflow."; 299 mul -> "llvm.umul.with.overflow."; 300 sub -> "llvm.usub.with.overflow."; 301 Op -> exit({?MODULE, trans_alub_op, {"Unknown alub operator", Op}}) 302 end 303 end, 304 Type = 305 case hipe_rtl_arch:word_size() of 306 4 -> "i32"; 307 8 -> "i64" 308 %% Other -> exit({?MODULE, trans_alub_op, {"Unknown type", Other}}) 309 end, 310 Name ++ Type. 311 312trans_alub_no_overflow(I, Relocs) -> 313 {Src1, I1} = trans_src(hipe_rtl:alub_src1(I)), 314 {Src2, I2} = trans_src(hipe_rtl:alub_src2(I)), 315 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 316 %% alu 317 {CmpLhs, CmpRhs, I5, Cond} = 318 case {hipe_rtl:alub_has_dst(I), hipe_rtl:alub_op(I)} of 319 {false, 'sub'} -> 320 Cond0 = trans_branch_rel_op(hipe_rtl:alub_cond(I)), 321 {Src1, Src2, [], Cond0}; 322 {HasDst, AlubOp} -> 323 TmpDst = mk_temp(), 324 Op = trans_op(AlubOp), 325 I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []), 326 I4 = case HasDst of 327 false -> []; 328 true -> store_stack_dst(TmpDst, hipe_rtl:alub_dst(I)) 329 end, 330 Cond0 = trans_alub_rel_op(hipe_rtl:alub_cond(I)), 331 {TmpDst, "0", [I4, I3], Cond0} 332 end, 333 %% icmp 334 T3 = mk_temp(), 335 I6 = hipe_llvm:mk_icmp(T3, Cond, WordTy, CmpLhs, CmpRhs), 336 %% br 337 Metadata = branch_metadata(hipe_rtl:alub_pred(I)), 338 True_label = mk_jump_label(hipe_rtl:alub_true_label(I)), 339 False_label = mk_jump_label(hipe_rtl:alub_false_label(I)), 340 I7 = hipe_llvm:mk_br_cond(T3, True_label, False_label, Metadata), 341 {[I7, I6, I5, I2, I1], Relocs}. 342 343branch_metadata(X) when X =:= 0.5 -> []; 344branch_metadata(X) when X > 0.5 -> ?BRANCH_META_TAKEN; 345branch_metadata(X) when X < 0.5 -> ?BRANCH_META_NOT_TAKEN. 346 347%% 348%% call 349%% 350trans_call(I, Relocs) -> 351 RtlCallArgList= hipe_rtl:call_arglist(I), 352 RtlCallName = hipe_rtl:call_fun(I), 353 {I0, Relocs1} = expose_closure(RtlCallName, RtlCallArgList, Relocs), 354 TmpDst = mk_temp(), 355 {CallArgs, I1} = trans_call_args(RtlCallArgList), 356 FixedRegs = fixed_registers(), 357 {LoadedFixedRegs, I2} = load_fixed_regs(FixedRegs), 358 FinalArgs = fix_reg_args(LoadedFixedRegs) ++ CallArgs, 359 {Name, I3, Relocs2} = 360 trans_call_name(RtlCallName, hipe_rtl:call_type(I), Relocs1, CallArgs, FinalArgs), 361 T1 = mk_temp(), 362 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 363 FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 364 I4 = 365 case hipe_rtl:call_fail(I) of 366 %% Normal Call 367 [] -> 368 hipe_llvm:mk_call(T1, false, "cc 11", [], FunRetTy, Name, FinalArgs, 369 []); 370 %% Call With Exception 371 FailLabelNum -> 372 TrueLabel = "L" ++ integer_to_list(hipe_rtl:call_normal(I)), 373 FailLabel = "%FL" ++ integer_to_list(FailLabelNum), 374 II1 = 375 hipe_llvm:mk_invoke(T1, "cc 11", [], FunRetTy, Name, FinalArgs, [], 376 "%" ++ TrueLabel, FailLabel), 377 II2 = hipe_llvm:mk_label(TrueLabel), 378 [II2, II1] 379 end, 380 I5 = store_fixed_regs(FixedRegs, T1), 381 I6 = 382 case hipe_rtl:call_dstlist(I) of 383 [] -> []; %% No return value 384 [Destination] -> 385 II3 = 386 hipe_llvm:mk_extractvalue(TmpDst, FunRetTy, T1, 387 integer_to_list(?NR_PINNED_REGS), []), 388 II4 = store_stack_dst(TmpDst, Destination), 389 [II4, II3] 390 end, 391 I7 = 392 case hipe_rtl:call_continuation(I) of 393 [] -> []; %% No continuation 394 CC -> 395 {II5, _} = trans_goto(hipe_rtl:mk_goto(CC), Relocs2), 396 II5 397 end, 398 {[I7, I6, I5, I4, I3, I2, I1, I0], Relocs2}. 399 400%% In case of call to a register (closure call) with more than ?NR_ARG_REGS 401%% arguments we must track the offset this call in the code, in order to 402%% to correct the stack descriptor. So, we insert a new Label and add this label 403%% to the "table_closures" 404%% --------------------------------|-------------------------------------------- 405%% Old Code | New Code 406%% --------------------------------|-------------------------------------------- 407%% | br %ClosureLabel 408%% call %reg(Args) | ClosureLabel: 409%% | call %reg(Args) 410expose_closure(CallName, CallArgs, Relocs) -> 411 CallArgsNr = length(CallArgs), 412 case hipe_rtl:is_reg(CallName) andalso CallArgsNr > ?NR_ARG_REGS of 413 true -> 414 LabelNum = hipe_gensym:new_label(llvm), 415 ClosureLabel = hipe_llvm:mk_label(mk_label(LabelNum)), 416 JumpIns = hipe_llvm:mk_br(mk_jump_label(LabelNum)), 417 Relocs1 = 418 relocs_store({CallName, LabelNum}, 419 {closure_label, LabelNum, CallArgsNr - ?NR_ARG_REGS}, 420 Relocs), 421 {[ClosureLabel, JumpIns], Relocs1}; 422 false -> 423 {[], Relocs} 424 end. 425 426trans_call_name(RtlCallName, RtlCallType, Relocs, CallArgs, FinalArgs) -> 427 case RtlCallName of 428 PrimOp when is_atom(PrimOp) -> 429 LlvmName = trans_prim_op(PrimOp), 430 Relocs1 = 431 relocs_store(LlvmName, {call, not_remote, {bif, PrimOp, length(CallArgs)}}, Relocs), 432 {"@" ++ LlvmName, [], Relocs1}; 433 {M, F, A} when is_atom(M), is_atom(F), is_integer(A) -> 434 LlvmName = trans_mfa_name({M, F, A}, RtlCallType), 435 Relocs1 = 436 relocs_store(LlvmName, {call, RtlCallType, {M, F, length(CallArgs)}}, Relocs), 437 {"@" ++ LlvmName, [], Relocs1}; 438 Reg -> 439 case hipe_rtl:is_reg(Reg) of 440 true -> 441 %% In case of a closure call, the register holding the address 442 %% of the closure must be converted to function type in 443 %% order to make the call 444 TT1 = mk_temp(), 445 {RegName, II1} = trans_src(Reg), 446 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 447 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 448 II2 = 449 hipe_llvm:mk_conversion(TT1, inttoptr, WordTy, RegName, WordTyPtr), 450 TT2 = mk_temp(), 451 ArgsTypeList = lists:duplicate(length(FinalArgs), WordTy), 452 FunRetTy = 453 hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 454 FunType = hipe_llvm:mk_fun(FunRetTy, ArgsTypeList), 455 FunTypeP = hipe_llvm:mk_pointer(FunType), 456 II3 = hipe_llvm:mk_conversion(TT2, bitcast, WordTyPtr, TT1, FunTypeP), 457 {TT2, [II3, II2, II1], Relocs}; 458 false -> 459 exit({?MODULE, trans_call, {"Unimplemented call to", RtlCallName}}) 460 end 461 end. 462 463%% 464trans_call_args(ArgList) -> 465 {Args, I} = lists:unzip(trans_args(ArgList)), 466 %% Reverse arguments that are passed to stack to match with the Erlang 467 %% calling convention. (Propably not needed in prim calls.) 468 ReversedArgs = 469 case erlang:length(Args) > ?NR_ARG_REGS of 470 false -> 471 Args; 472 true -> 473 {ArgsInRegs, ArgsInStack} = lists:split(?NR_ARG_REGS, Args), 474 ArgsInRegs ++ lists:reverse(ArgsInStack) 475 end, 476 %% Reverse I, because some of the arguments may go out of scope and 477 %% should be killed(store -5). When two or more arguments are they 478 %% same, then order matters! 479 {ReversedArgs, lists:reverse(I)}. 480 481%% 482%% trans_comment 483%% 484trans_comment(I, Relocs) -> 485 I1 = hipe_llvm:mk_comment(hipe_rtl:comment_text(I)), 486 {I1, Relocs}. 487 488%% 489%% enter 490%% 491trans_enter(I, Relocs) -> 492 {CallArgs, I0} = trans_call_args(hipe_rtl:enter_arglist(I)), 493 FixedRegs = fixed_registers(), 494 {LoadedFixedRegs, I1} = load_fixed_regs(FixedRegs), 495 FinalArgs = fix_reg_args(LoadedFixedRegs) ++ CallArgs, 496 {Name, I2, NewRelocs} = 497 trans_call_name(hipe_rtl:enter_fun(I), hipe_rtl:enter_type(I), Relocs, CallArgs, FinalArgs), 498 T1 = mk_temp(), 499 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 500 FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 501 I3 = hipe_llvm:mk_call(T1, true, "cc 11", [], FunRetTy, Name, FinalArgs, []), 502 I4 = hipe_llvm:mk_ret([{FunRetTy, T1}]), 503 {[I4, I3, I2, I1, I0], NewRelocs}. 504 505%% 506%% fconv 507%% 508trans_fconv(I, Relocs) -> 509 %% XXX: Can a fconv destination be a precoloured reg? 510 RtlDst = hipe_rtl:fconv_dst(I), 511 TmpDst = mk_temp(), 512 {Src, I1} = trans_float_src(hipe_rtl:fconv_src(I)), 513 FloatTy = hipe_llvm:mk_double(), 514 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 515 I2 = hipe_llvm:mk_conversion(TmpDst, sitofp, WordTy, Src, FloatTy), 516 I3 = store_float_stack(TmpDst, RtlDst), 517 {[I3, I2, I1], Relocs}. 518 519 520%% TODO: fload, fstore, fmove, and fp are almost the same with load, store, move 521%% and alu. Maybe we should join them. 522 523%% 524%% fload 525%% 526trans_fload(I, Relocs) -> 527 RtlDst = hipe_rtl:fload_dst(I), 528 RtlSrc = hipe_rtl:fload_src(I), 529 _Offset = hipe_rtl:fload_offset(I), 530 TmpDst = mk_temp(), 531 {Src, I1} = trans_float_src(RtlSrc), 532 {Offset, I2} = trans_float_src(_Offset), 533 T1 = mk_temp(), 534 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 535 FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()), 536 I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []), 537 T2 = mk_temp(), 538 I4 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, FloatTyPtr), 539 I5 = hipe_llvm:mk_load(TmpDst, FloatTyPtr, T2, [], [], false), 540 I6 = store_float_stack(TmpDst, RtlDst), 541 {[I6, I5, I4, I3, I2, I1], Relocs}. 542 543%% 544%% fmove 545%% 546trans_fmove(I, Relocs) -> 547 RtlDst = hipe_rtl:fmove_dst(I), 548 RtlSrc = hipe_rtl:fmove_src(I), 549 {Src, I1} = trans_float_src(RtlSrc), 550 I2 = store_float_stack(Src, RtlDst), 551 {[I2, I1], Relocs}. 552 553%% 554%% fp 555%% 556trans_fp(I, Relocs) -> 557 %% XXX: Just copied trans_alu...think again.. 558 RtlDst = hipe_rtl:fp_dst(I), 559 RtlSrc1 = hipe_rtl:fp_src1(I), 560 RtlSrc2 = hipe_rtl:fp_src2(I), 561 %% Destination cannot be a precoloured register 562 FloatTy = hipe_llvm:mk_double(), 563 FloatTyPtr = hipe_llvm:mk_pointer(FloatTy), 564 TmpDst = mk_temp(), 565 {Src1, I1} = trans_float_src(RtlSrc1), 566 {Src2, I2} = trans_float_src(RtlSrc2), 567 Op = trans_fp_op(hipe_rtl:fp_op(I)), 568 I3 = hipe_llvm:mk_operation(TmpDst, Op, FloatTy, Src1, Src2, []), 569 I4 = store_float_stack(TmpDst, RtlDst), 570 %% Synchronization for floating point exceptions 571 I5 = hipe_llvm:mk_store(FloatTy, TmpDst, FloatTyPtr, "%exception_sync", [], 572 [], true), 573 T1 = mk_temp(), 574 I6 = hipe_llvm:mk_load(T1, FloatTyPtr, "%exception_sync", [], [], true), 575 {[I6, I5, I4, I3, I2, I1], Relocs}. 576 577%% 578%% fp_unop 579%% 580trans_fp_unop(I, Relocs) -> 581 RtlDst = hipe_rtl:fp_unop_dst(I), 582 RtlSrc = hipe_rtl:fp_unop_src(I), 583 %% Destination cannot be a precoloured register 584 TmpDst = mk_temp(), 585 {Src, I1} = trans_float_src(RtlSrc), 586 Op = trans_fp_op(hipe_rtl:fp_unop_op(I)), 587 FloatTy = hipe_llvm:mk_double(), 588 I2 = hipe_llvm:mk_operation(TmpDst, Op, FloatTy, "0.0", Src, []), 589 I3 = store_float_stack(TmpDst, RtlDst), 590 {[I3, I2, I1], Relocs}. 591%% TODO: Fix fp_unop in a way like the following. You must change trans_dest, 592%% in order to call float_to_list in a case of float constant. Maybe the type 593%% check is expensive... 594%% Dst = hipe_rtl:fp_unop_dst(I), 595%% Src = hipe_rtl:fp_unop_src(I), 596%% Op = hipe_rtl:fp_unop_op(I), 597%% Zero = hipe_rtl:mk_imm(0.0), 598%% I1 = hipe_rtl:mk_fp(Dst, Zero, Op, Src), 599%% trans_fp(I, Relocs1). 600 601%% 602%% fstore 603%% 604trans_fstore(I, Relocs) -> 605 Base = hipe_rtl:fstore_base(I), 606 case isPrecoloured(Base) of 607 true -> 608 trans_fstore_reg(I, Relocs); 609 false -> 610 exit({?MODULE, trans_fstore ,{"Not implemented yet", false}}) 611 end. 612 613trans_fstore_reg(I, Relocs) -> 614 {Base, I0} = trans_reg(hipe_rtl:fstore_base(I), dst), 615 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 616 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 617 FloatTy = hipe_llvm:mk_double(), 618 FloatTyPtr = hipe_llvm:mk_pointer(FloatTy), 619 T1 = mk_temp(), 620 I1 = hipe_llvm:mk_load(T1, WordTyPtr, Base, [], [], false), 621 {Offset, I2} = trans_src(hipe_rtl:fstore_offset(I)), 622 T2 = mk_temp(), 623 I3 = hipe_llvm:mk_operation(T2, add, WordTy, T1, Offset, []), 624 T3 = mk_temp(), 625 I4 = hipe_llvm:mk_conversion(T3, inttoptr, WordTy, T2, FloatTyPtr), 626 {Value, I5} = trans_src(hipe_rtl:fstore_src(I)), 627 I6 = hipe_llvm:mk_store(FloatTy, Value, FloatTyPtr, T3, [], [], false), 628 {[I6, I5, I4, I3, I2, I1, I0], Relocs}. 629 630%% 631%% goto 632%% 633trans_goto(I, Relocs) -> 634 I1 = hipe_llvm:mk_br(mk_jump_label(hipe_rtl:goto_label(I))), 635 {I1, Relocs}. 636 637%% 638%% label 639%% 640trans_label(I, Relocs) -> 641 Label = mk_label(hipe_rtl:label_name(I)), 642 I1 = hipe_llvm:mk_label(Label), 643 {I1, Relocs}. 644 645%% 646%% load 647%% 648trans_load(I, Relocs) -> 649 RtlDst = hipe_rtl:load_dst(I), 650 TmpDst = mk_temp(), 651 %% XXX: Why translate them independently? ------------------------ 652 {Src, I1} = trans_src(hipe_rtl:load_src(I)), 653 {Offset, I2} = trans_src(hipe_rtl:load_offset(I)), 654 T1 = mk_temp(), 655 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 656 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 657 I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []), 658 %%---------------------------------------------------------------- 659 I4 = case hipe_rtl:load_size(I) of 660 word -> 661 T2 = mk_temp(), 662 II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, WordTyPtr), 663 II2 = hipe_llvm:mk_load(TmpDst, WordTyPtr, T2, [], [], false), 664 [II2, II1]; 665 Size -> 666 LoadType = llvm_type_from_size(Size), 667 LoadTypeP = hipe_llvm:mk_pointer(LoadType), 668 T2 = mk_temp(), 669 II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, LoadTypeP), 670 T3 = mk_temp(), 671 LoadTypePointer = hipe_llvm:mk_pointer(LoadType), 672 II2 = hipe_llvm:mk_load(T3, LoadTypePointer, T2, [], [], false), 673 Conversion = 674 case hipe_rtl:load_sign(I) of 675 signed -> sext; 676 unsigned -> zext 677 end, 678 II3 = 679 hipe_llvm:mk_conversion(TmpDst, Conversion, LoadType, T3, WordTy), 680 [II3, II2, II1] 681 end, 682 I5 = store_stack_dst(TmpDst, RtlDst), 683 {[I5, I4, I3, I2, I1], Relocs}. 684 685%% 686%% load_address 687%% 688trans_load_address(I, Relocs) -> 689 RtlDst = hipe_rtl:load_address_dst(I), 690 RtlAddr = hipe_rtl:load_address_addr(I), 691 {Addr, NewRelocs} = 692 case hipe_rtl:load_address_type(I) of 693 constant -> 694 {"%DL" ++ integer_to_list(RtlAddr) ++ "_var", Relocs}; 695 closure -> 696 {{_, ClosureName, _}, _, _} = RtlAddr, 697 FixedClosureName = fix_closure_name(ClosureName), 698 Relocs1 = relocs_store(FixedClosureName, {closure, RtlAddr}, Relocs), 699 {"%" ++ FixedClosureName ++ "_var", Relocs1}; 700 type -> 701 exit({?MODULE, trans_load_address, 702 {"Type not implemented in load_address", RtlAddr}}) 703 end, 704 I1 = store_stack_dst(Addr, RtlDst), 705 {[I1], NewRelocs}. 706 707%% 708%% load_atom 709%% 710trans_load_atom(I, Relocs) -> 711 RtlDst = hipe_rtl:load_atom_dst(I), 712 RtlAtom = hipe_rtl:load_atom_atom(I), 713 AtomName = "atom_" ++ make_llvm_id(atom_to_list(RtlAtom)), 714 AtomVar = "%" ++ AtomName ++ "_var", 715 NewRelocs = relocs_store(AtomName, {atom, RtlAtom}, Relocs), 716 I1 = store_stack_dst(AtomVar, RtlDst), 717 {[I1], NewRelocs}. 718 719%% 720%% move 721%% 722trans_move(I, Relocs) -> 723 RtlDst = hipe_rtl:move_dst(I), 724 RtlSrc = hipe_rtl:move_src(I), 725 {Src, I1} = trans_src(RtlSrc), 726 I2 = store_stack_dst(Src, RtlDst), 727 {[I2, I1], Relocs}. 728 729%% 730%% return 731%% 732trans_return(I, Relocs) -> 733 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 734 {VarRet, I1} = 735 case hipe_rtl:return_varlist(I) of 736 [] -> 737 {[], []}; 738 [A] -> 739 {Name, II1} = trans_src(A), 740 {[{WordTy, Name}], II1} 741 end, 742 FixedRegs = fixed_registers(), 743 {LoadedFixedRegs, I2} = load_fixed_regs(FixedRegs), 744 FixedRet = [{WordTy, X} || X <- LoadedFixedRegs], 745 Ret = FixedRet ++ VarRet, 746 {RetTypes, _RetNames} = lists:unzip(Ret), 747 Type = hipe_llvm:mk_struct(RetTypes), 748 {RetStruct, I3} = mk_return_struct(Ret, Type), 749 I4 = hipe_llvm:mk_ret([{Type, RetStruct}]), 750 {[I4, I3, I2, I1], Relocs}. 751 752%% @doc Create a structure to hold the return value and the precoloured 753%% registers. 754mk_return_struct(RetValues, Type) -> 755 mk_return_struct(RetValues, Type, [], "undef", 0). 756 757mk_return_struct([], _, Acc, StructName, _) -> 758 {StructName, Acc}; 759mk_return_struct([{ElemType, ElemName}|Rest], Type, Acc, StructName, Index) -> 760 T1 = mk_temp(), 761 I1 = hipe_llvm:mk_insertvalue(T1, Type, StructName, ElemType, ElemName, 762 integer_to_list(Index), []), 763 mk_return_struct(Rest, Type, [I1 | Acc], T1, Index+1). 764 765%% 766%% store 767%% 768trans_store(I, Relocs) -> 769 {Base, I1} = trans_src(hipe_rtl:store_base(I)), 770 {Offset, I2} = trans_src(hipe_rtl:store_offset(I)), 771 {Value, I3} = trans_src(hipe_rtl:store_src(I)), 772 T1 = mk_temp(), 773 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 774 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 775 I4 = hipe_llvm:mk_operation(T1, add, WordTy, Base, Offset, []), 776 I5 = 777 case hipe_rtl:store_size(I) of 778 word -> 779 T2 = mk_temp(), 780 II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, WordTyPtr), 781 II2 = hipe_llvm:mk_store(WordTy, Value, WordTyPtr, T2, [], [], 782 false), 783 [II2, II1]; 784 Size -> 785 %% XXX: Is always trunc correct ? 786 LoadType = llvm_type_from_size(Size), 787 LoadTypePointer = hipe_llvm:mk_pointer(LoadType), 788 T2 = mk_temp(), 789 II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, LoadTypePointer), 790 T3 = mk_temp(), 791 II2 = hipe_llvm:mk_conversion(T3, 'trunc', WordTy, Value, LoadType), 792 II3 = hipe_llvm:mk_store(LoadType, T3, LoadTypePointer, T2, [], [], false), 793 [II3, II2, II1] 794 end, 795 {[I5, I4, I3, I2, I1], Relocs}. 796 797%% 798%% switch 799%% 800trans_switch(I, Relocs, Data) -> 801 RtlSrc = hipe_rtl:switch_src(I), 802 {Src, I1} = trans_src(RtlSrc), 803 Labels = hipe_rtl:switch_labels(I), 804 JumpLabels = [mk_jump_label(L) || L <- Labels], 805 SortOrder = hipe_rtl:switch_sort_order(I), 806 NrLabels = length(Labels), 807 ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)), 808 TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr), 809 TableTypeP = hipe_llvm:mk_pointer(TableType), 810 TypedJumpLabels = [{hipe_llvm:mk_label_type(), X} || X <- JumpLabels], 811 T1 = mk_temp(), 812 {Src2, []} = trans_dst(RtlSrc), 813 TableName = "table_" ++ tl(Src2), 814 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 815 I2 = hipe_llvm:mk_getelementptr(T1, TableTypeP, "@"++TableName, 816 [{WordTy, "0"}, {WordTy, Src}], false), 817 T2 = mk_temp(), 818 BYTE_TYPE_PP = hipe_llvm:mk_pointer(ByteTyPtr), 819 I3 = hipe_llvm:mk_load(T2, BYTE_TYPE_PP, T1, [], [], false), 820 I4 = hipe_llvm:mk_indirectbr(ByteTyPtr, T2, TypedJumpLabels), 821 LMap = [{label, L} || L <- Labels], 822 %% Update data with the info for the jump table 823 {NewData, JTabLab} = 824 case hipe_rtl:switch_sort_order(I) of 825 [] -> 826 hipe_consttab:insert_block(Data, word, LMap); 827 SortOrder -> 828 hipe_consttab:insert_sorted_block(Data, word, LMap, SortOrder) 829 end, 830 Relocs2 = relocs_store(TableName, {switch, {TableType, Labels, NrLabels, 831 SortOrder}, JTabLab}, Relocs), 832 {[I4, I3, I2, I1], Relocs2, NewData}. 833 834%% @doc Pass on RTL code in order to fix invoke and closure calls. 835fix_code(Code) -> 836 fix_calls(Code). 837 838%% @doc Fix invoke calls and closure calls with more than ?NR_ARG_REGS 839%% arguments. 840fix_calls(Code) -> 841 fix_calls(Code, [], []). 842 843fix_calls([], Acc, FailLabels) -> 844 {lists:reverse(Acc), FailLabels}; 845fix_calls([I | Is], Acc, FailLabels) -> 846 case hipe_rtl:is_call(I) of 847 true -> 848 {NewCall, NewFailLabels} = 849 case hipe_rtl:call_fail(I) of 850 [] -> 851 {I, FailLabels}; 852 FailLabel -> 853 fix_invoke_call(I, FailLabel, FailLabels) 854 end, 855 fix_calls(Is, [NewCall|Acc], NewFailLabels); 856 false -> 857 fix_calls(Is, [I|Acc], FailLabels) 858 end. 859 860%% @doc When a call has a fail continuation label it must be extended with a 861%% normal continuation label to go with the LLVM's invoke instruction. 862%% FailLabels is the list of labels of all fail blocks, which are needed to 863%% be declared as landing pads. Furtermore, we must add to fail labels a 864%% call to hipe_bifs:llvm_fix_pinned_regs/0 in order to avoid reloading old 865%% values of pinned registers. This may happen because the result of an 866%% invoke instruction is not available at fail-labels, and, thus, we cannot 867%% get the correct values of pinned registers. Finally, the stack needs to 868%% be re-adjusted when there are stack arguments. 869fix_invoke_call(I, FailLabel, FailLabels) -> 870 NewLabel = hipe_gensym:new_label(llvm), 871 NewCall1 = hipe_rtl:call_normal_update(I, NewLabel), 872 SpAdj = find_sp_adj(hipe_rtl:call_arglist(I)), 873 case lists:keyfind(FailLabel, 1, FailLabels) of 874 %% Same fail label with same Stack Pointer adjustment 875 {FailLabel, NewFailLabel, SpAdj} -> 876 NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel), 877 {NewCall2, FailLabels}; 878 %% Same fail label but with different Stack Pointer adjustment 879 {_, _, _} -> 880 NewFailLabel = hipe_gensym:new_label(llvm), 881 NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel), 882 {NewCall2, [{FailLabel, NewFailLabel, SpAdj} | FailLabels]}; 883 %% New Fail label 884 false -> 885 NewFailLabel = hipe_gensym:new_label(llvm), 886 NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel), 887 {NewCall2, [{FailLabel, NewFailLabel, SpAdj} | FailLabels]} 888 end. 889 890find_sp_adj(ArgList) -> 891 NrArgs = length(ArgList), 892 case NrArgs > ?NR_ARG_REGS of 893 true -> 894 (NrArgs - ?NR_ARG_REGS) * hipe_rtl_arch:word_size(); 895 false -> 896 0 897 end. 898 899%% @doc Add landingpad instruction in Fail Blocks. 900add_landingpads(LLVM_Code, FailLabels) -> 901 FailLabels2 = [convert_label(T) || T <- FailLabels], 902 add_landingpads(LLVM_Code, FailLabels2, []). 903 904add_landingpads([], _, Acc) -> 905 lists:reverse(Acc); 906add_landingpads([I | Is], FailLabels, Acc) -> 907 case hipe_llvm:is_label(I) of 908 true -> 909 Label = hipe_llvm:label_label(I), 910 Ins = create_fail_blocks(Label, FailLabels), 911 add_landingpads(Is, FailLabels, [I | Ins] ++ Acc); 912 false -> 913 add_landingpads(Is, FailLabels, [I | Acc]) 914 end. 915 916convert_label({X,Y,Z}) -> 917 {"L" ++ integer_to_list(X), "FL" ++ integer_to_list(Y), Z}. 918 919%% @doc Create a fail block wich. 920create_fail_blocks(_, []) -> []; 921create_fail_blocks(Label, FailLabels) -> 922 create_fail_blocks(Label, FailLabels, []). 923 924create_fail_blocks(Label, FailLabels, Acc) -> 925 case lists:keytake(Label, 1, FailLabels) of 926 false -> 927 Acc; 928 {value, {Label, FailLabel, SpAdj}, RestFailLabels} -> 929 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 930 I1 = hipe_llvm:mk_label(FailLabel), 931 LP = hipe_llvm:mk_landingpad(), 932 I2 = 933 case SpAdj > 0 of 934 true -> 935 StackPointer = ?ARCH_REGISTERS:reg_name(?ARCH_REGISTERS:sp()), 936 hipe_llvm:mk_adj_stack(integer_to_list(SpAdj), StackPointer, 937 WordTy); 938 false -> [] 939 end, 940 T1 = mk_temp(), 941 FixedRegs = fixed_registers(), 942 FunRetTy = 943 hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 944 I3 = hipe_llvm:mk_call(T1, false, "cc 11", [], FunRetTy, 945 "@hipe_bifs.llvm_fix_pinned_regs.0", [], []), 946 I4 = store_fixed_regs(FixedRegs, T1), 947 I5 = hipe_llvm:mk_br("%" ++ Label), 948 Ins = lists:flatten([I5, I4, I3, I2, LP,I1]), 949 create_fail_blocks(Label, RestFailLabels, Ins ++ Acc) 950 end. 951 952%%------------------------------------------------------------------------------ 953%% Miscellaneous Functions 954%%------------------------------------------------------------------------------ 955 956%% @doc Convert RTL argument list to LLVM argument list. 957trans_args(ArgList) -> 958 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 959 MakeArg = 960 fun(A) -> 961 {Name, I1} = trans_src(A), 962 {{WordTy, Name}, I1} 963 end, 964 [MakeArg(A) || A <- ArgList]. 965 966%% @doc Convert a list of Precoloured registers to LLVM argument list. 967fix_reg_args(ArgList) -> 968 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 969 [{WordTy, A} || A <- ArgList]. 970 971%% @doc Load Precoloured registers. 972load_fixed_regs(RegList) -> 973 Names = [mk_temp_reg(R) || R <- RegList], 974 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 975 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 976 Fun1 = 977 fun (X, Y) -> 978 hipe_llvm:mk_load(X, WordTyPtr, "%" ++ Y ++ "_reg_var", [], [], false) 979 end, 980 Ins = lists:zipwith(Fun1, Names, RegList), 981 {Names, Ins}. 982 983%% @doc Store Precoloured registers. 984store_fixed_regs(RegList, Name) -> 985 Names = [mk_temp_reg(R) || R <- RegList], 986 Indexes = lists:seq(0, erlang:length(RegList) - 1), 987 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 988 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 989 FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 990 Fun1 = 991 fun(X,Y) -> 992 hipe_llvm:mk_extractvalue(X, FunRetTy, Name, integer_to_list(Y), []) 993 end, 994 I1 = lists:zipwith(Fun1, Names, Indexes), 995 Fun2 = 996 fun (X, Y) -> 997 hipe_llvm:mk_store(WordTy, X, WordTyPtr, "%" ++ Y ++ "_reg_var", [], [], 998 false) 999 end, 1000 I2 = lists:zipwith(Fun2, Names, RegList), 1001 [I2, I1]. 1002 1003%%------------------------------------------------------------------------------ 1004%% Translation of Names 1005%%------------------------------------------------------------------------------ 1006 1007%% @doc Fix F in MFA tuple to acceptable LLVM identifier (case of closure). 1008-spec fix_mfa_name(mfa()) -> mfa(). 1009fix_mfa_name({Mod_Name, Closure_Name, Arity}) -> 1010 Fun_Name = list_to_atom(fix_closure_name(Closure_Name)), 1011 {Mod_Name, Fun_Name, Arity}. 1012 1013%% @doc Make an acceptable LLVM identifier for a closure name. 1014fix_closure_name(ClosureName) -> 1015 make_llvm_id(atom_to_list(ClosureName)). 1016 1017%% @doc Create an acceptable LLVM identifier. 1018make_llvm_id(Name) -> 1019 case Name of 1020 "" -> "Empty"; 1021 Other -> lists:flatten([llvm_id(C) || C <- Other]) 1022 end. 1023 1024llvm_id(C) when C=:=46; C>47 andalso C<58; C>64 andalso C<91; C=:=95; 1025 C>96 andalso C<123 -> 1026 C; 1027llvm_id(C) -> 1028 io_lib:format("_~2.16.0B_",[C]). 1029 1030%% @doc Create an acceptable LLVM identifier for an MFA. 1031trans_mfa_name({M,F,A}, Linkage) -> 1032 N0 = atom_to_list(M) ++ "." ++ atom_to_list(F) ++ "." ++ integer_to_list(A), 1033 N = case Linkage of 1034 not_remote -> N0; 1035 remote -> "rem." ++ N0 1036 end, 1037 make_llvm_id(N). 1038 1039%%------------------------------------------------------------------------------ 1040%% Creation of Labels and Temporaries 1041%%------------------------------------------------------------------------------ 1042mk_label(N) -> 1043 "L" ++ integer_to_list(N). 1044 1045mk_jump_label(N) -> 1046 "%L" ++ integer_to_list(N). 1047 1048mk_temp() -> 1049 "%t" ++ integer_to_list(hipe_gensym:new_var(llvm)). 1050 1051mk_temp_reg(Name) -> 1052 "%" ++ Name ++ integer_to_list(hipe_gensym:new_var(llvm)). 1053 1054%%---------------------------------------------------------------------------- 1055%% Translation of Operands 1056%%---------------------------------------------------------------------------- 1057 1058store_stack_dst(TempDst, Dst) -> 1059 {Dst2, II1} = trans_dst(Dst), 1060 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1061 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 1062 II2 = hipe_llvm:mk_store(WordTy, TempDst, WordTyPtr, Dst2, [], [], false), 1063 [II2, II1]. 1064 1065store_float_stack(TempDst, Dst) -> 1066 {Dst2, II1} = trans_dst(Dst), 1067 FloatTy = hipe_llvm:mk_double(), 1068 FloatTyPtr = hipe_llvm:mk_pointer(FloatTy), 1069 II2 = hipe_llvm:mk_store(FloatTy, TempDst, FloatTyPtr, Dst2, [], [], false), 1070 [II2, II1]. 1071 1072trans_float_src(Src) -> 1073 case hipe_rtl:is_const_label(Src) of 1074 true -> 1075 Name = "@DL" ++ integer_to_list(hipe_rtl:const_label_label(Src)), 1076 T1 = mk_temp(), 1077 %% XXX: Hardcoded offset 1078 ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE), 1079 ByteTyPtr = hipe_llvm:mk_pointer(ByteTy), 1080 I1 = hipe_llvm:mk_getelementptr(T1, ByteTyPtr, Name, 1081 [{ByteTy, integer_to_list(?FLOAT_OFFSET)}], true), 1082 T2 = mk_temp(), 1083 FloatTy = hipe_llvm:mk_double(), 1084 FloatTyPtr = hipe_llvm:mk_pointer(FloatTy), 1085 I2 = hipe_llvm:mk_conversion(T2, bitcast, ByteTyPtr, T1, FloatTyPtr), 1086 T3 = mk_temp(), 1087 I3 = hipe_llvm:mk_load(T3, FloatTyPtr, T2, [], [], false), 1088 {T3, [I3, I2, I1]}; 1089 false -> 1090 trans_src(Src) 1091 end. 1092 1093trans_src(A) -> 1094 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1095 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 1096 case hipe_rtl:is_imm(A) of 1097 true -> 1098 Value = integer_to_list(hipe_rtl:imm_value(A)), 1099 {Value, []}; 1100 false -> 1101 case hipe_rtl:is_reg(A) of 1102 true -> 1103 case isPrecoloured(A) of 1104 true -> trans_reg(A, src); 1105 false -> 1106 {Name, []} = trans_reg(A, src), 1107 T1 = mk_temp(), 1108 I1 = hipe_llvm:mk_load(T1, WordTyPtr, Name, [], [], false), 1109 {T1, [I1]} 1110 end; 1111 false -> 1112 case hipe_rtl:is_var(A) of 1113 true -> 1114 RootName = "%vr" ++ integer_to_list(hipe_rtl:var_index(A)), 1115 T1 = mk_temp(), 1116 I1 = hipe_llvm:mk_load(T1, WordTyPtr, RootName, [], [], false), 1117 I2 = 1118 case hipe_rtl:var_liveness(A) of 1119 live -> 1120 []; 1121 dead -> 1122 NilValue = hipe_tagscheme:mk_nil(), 1123 hipe_llvm:mk_store(WordTy, integer_to_list(NilValue), WordTyPtr, RootName, 1124 [], [], false) 1125 end, 1126 {T1, [I2, I1]}; 1127 false -> 1128 case hipe_rtl:is_fpreg(A) of 1129 true -> 1130 {Name, []} = trans_dst(A), 1131 T1 = mk_temp(), 1132 FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()), 1133 I1 = hipe_llvm:mk_load(T1, FloatTyPtr, Name, [], [], false), 1134 {T1, [I1]}; 1135 false -> trans_dst(A) 1136 end 1137 end 1138 end 1139 end. 1140 1141trans_dst(A) -> 1142 case hipe_rtl:is_reg(A) of 1143 true -> 1144 trans_reg(A, dst); 1145 false -> 1146 Name = case hipe_rtl:is_var(A) of 1147 true -> 1148 "%vr" ++ integer_to_list(hipe_rtl:var_index(A)); 1149 false -> 1150 case hipe_rtl:is_fpreg(A) of 1151 true -> "%fr" ++ integer_to_list(hipe_rtl:fpreg_index(A)); 1152 false -> 1153 case hipe_rtl:is_const_label(A) of 1154 true -> 1155 "%DL" ++ integer_to_list(hipe_rtl:const_label_label(A)) ++ "_var"; 1156 false -> 1157 error(badarg, [A]) 1158 end 1159 end 1160 end, 1161 {Name, []} 1162 end. 1163 1164%% @doc Translate a register. If it is precoloured it must be mapped to the 1165%% correct stack slot that holds the precoloured register value. 1166trans_reg(Arg, Position) -> 1167 Index = hipe_rtl:reg_index(Arg), 1168 case isPrecoloured(Arg) of 1169 true -> 1170 Name = map_precoloured_reg(Index), 1171 case Position of 1172 src -> fix_reg_src(Name); 1173 dst -> fix_reg_dst(Name) 1174 end; 1175 false -> 1176 {hipe_rtl_arch:reg_name(Index), []} 1177 end. 1178 1179map_precoloured_reg(Index) -> 1180 case hipe_rtl_arch:reg_name(Index) of 1181 "%r15" -> "%hp_reg_var"; 1182 "%rbp" -> "%p_reg_var"; 1183 "%esi" -> "%hp_reg_var"; 1184 "%ebp" -> "%p_reg_var"; 1185 "%fcalls" -> 1186 {"%p_reg_var", ?ARCH_REGISTERS:proc_offset(?ARCH_REGISTERS:fcalls())}; 1187 "%hplim" -> 1188 {"%p_reg_var", ?ARCH_REGISTERS:proc_offset(?ARCH_REGISTERS:heap_limit())}; 1189 _ -> 1190 exit({?MODULE, map_precoloured_reg, {"Register not mapped yet", Index}}) 1191 end. 1192 1193%% @doc Load precoloured dst register. 1194fix_reg_dst(Register) -> 1195 case Register of 1196 {Name, Offset} -> %% Case of %fcalls, %hplim 1197 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1198 pointer_from_reg(Name, WordTy, Offset); 1199 Name -> %% Case of %p and %hp 1200 {Name, []} 1201 end. 1202 1203%% @doc Load precoloured src register. 1204fix_reg_src(Register) -> 1205 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1206 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 1207 case Register of 1208 {Name, Offset} -> %% Case of %fcalls, %hplim 1209 {T1, I1} = pointer_from_reg(Name, WordTy, Offset), 1210 T2 = mk_temp(), 1211 I2 = hipe_llvm:mk_load(T2, WordTyPtr, T1, [], [] , false), 1212 {T2, [I2, I1]}; 1213 Name -> %% Case of %p and %hp 1214 T1 = mk_temp(), 1215 {T1, hipe_llvm:mk_load(T1, WordTyPtr, Name, [], [], false)} 1216 end. 1217 1218%% @doc Load %fcalls and %hplim. 1219pointer_from_reg(RegName, Type, Offset) -> 1220 PointerType = hipe_llvm:mk_pointer(Type), 1221 T1 = mk_temp(), 1222 I1 = hipe_llvm:mk_load(T1, PointerType, RegName, [], [] ,false), 1223 T2 = mk_temp(), 1224 I2 = hipe_llvm:mk_conversion(T2, inttoptr, Type, T1, PointerType), 1225 T3 = mk_temp(), 1226 %% XXX: Offsets should be a power of 2. 1227 I3 = hipe_llvm:mk_getelementptr(T3, PointerType, T2, 1228 [{Type, integer_to_list(Offset div hipe_rtl_arch:word_size())}], true), 1229 {T3, [I3, I2, I1]}. 1230 1231isPrecoloured(X) -> 1232 hipe_rtl_arch:is_precoloured(X). 1233 1234%%------------------------------------------------------------------------------ 1235%% Translation of operators 1236%%------------------------------------------------------------------------------ 1237 1238trans_op(Op) -> 1239 case Op of 1240 add -> add; 1241 sub -> sub; 1242 'or' -> 'or'; 1243 'and' -> 'and'; 1244 'xor' -> 'xor'; 1245 sll -> shl; 1246 srl -> lshr; 1247 sra -> ashr; 1248 mul -> mul; 1249 'fdiv' -> fdiv; 1250 'sdiv' -> sdiv; 1251 'srem' -> srem; 1252 Other -> exit({?MODULE, trans_op, {"Unknown RTL operator", Other}}) 1253 end. 1254 1255trans_branch_rel_op(Op) -> 1256 case Op of 1257 gtu -> ugt; 1258 geu -> uge; 1259 ltu -> ult; 1260 leu -> ule; 1261 _ -> trans_alub_rel_op(Op) 1262 end. 1263 1264trans_alub_rel_op(Op) -> 1265 case Op of 1266 eq -> eq; 1267 ne -> ne; 1268 gt -> sgt; 1269 ge -> sge; 1270 lt -> slt; 1271 le -> sle 1272 end. 1273 1274trans_prim_op(Op) -> 1275 case Op of 1276 '+' -> "bif_add"; 1277 '-' -> "bif_sub"; 1278 '*' -> "bif_mul"; 1279 'div' -> "bif_div"; 1280 '/' -> "bif_div"; 1281 Other -> atom_to_list(Other) 1282 end. 1283 1284trans_fp_op(Op) -> 1285 case Op of 1286 fadd -> fadd; 1287 fsub -> fsub; 1288 fdiv -> fdiv; 1289 fmul -> fmul; 1290 fchs -> fsub; 1291 Other -> exit({?MODULE, trans_fp_op, {"Unknown RTL float operator",Other}}) 1292 end. 1293 1294%% Misc. 1295insn_dst(I) -> 1296 case I of 1297 #alu{} -> 1298 [hipe_rtl:alu_dst(I)]; 1299 #alub{} -> 1300 case hipe_rtl:alub_has_dst(I) of 1301 true -> [hipe_rtl:alub_dst(I)]; 1302 false -> [] 1303 end; 1304 #call{} -> 1305 case hipe_rtl:call_dstlist(I) of 1306 [] -> []; 1307 [Dst] -> [Dst] 1308 end; 1309 #load{} -> 1310 [hipe_rtl:load_dst(I)]; 1311 #load_address{} -> 1312 [hipe_rtl:load_address_dst(I)]; 1313 #load_atom{} -> 1314 [hipe_rtl:load_atom_dst(I)]; 1315 #move{} -> 1316 [hipe_rtl:move_dst(I)]; 1317 #phi{} -> 1318 [hipe_rtl:phi_dst(I)]; 1319 #fconv{} -> 1320 [hipe_rtl:fconv_dst(I)]; 1321 #fload{} -> 1322 [hipe_rtl:fload_dst(I)]; 1323 #fmove{} -> 1324 [hipe_rtl:fmove_dst(I)]; 1325 #fp{} -> 1326 [hipe_rtl:fp_dst(I)]; 1327 #fp_unop{} -> 1328 [hipe_rtl:fp_unop_dst(I)]; 1329 _ -> 1330 [] 1331 end. 1332 1333llvm_type_from_size(Size) -> 1334 case Size of 1335 byte -> hipe_llvm:mk_int(?BITS_IN_BYTE); 1336 int16 -> hipe_llvm:mk_int(16); 1337 int32 -> hipe_llvm:mk_int(32); 1338 word -> hipe_llvm:mk_int(?BITS_IN_WORD) 1339 end. 1340 1341%% @doc Create definition for the compiled function. The parameters that are 1342%% passed to the stack must be reversed to match with the CC. Also 1343%% precoloured registers that are passed as arguments must be stored to 1344%% the corresonding stack slots. 1345create_function_definition(Fun, Params, Code, LocalVars) -> 1346 FunctionName = trans_mfa_name(Fun, not_remote), 1347 FixedRegs = fixed_registers(), 1348 %% Reverse parameters to match with the Erlang calling convention 1349 ReversedParams = 1350 case erlang:length(Params) > ?NR_ARG_REGS of 1351 false -> 1352 Params; 1353 true -> 1354 {ParamsInRegs, ParamsInStack} = lists:split(?NR_ARG_REGS, Params), 1355 ParamsInRegs ++ lists:reverse(ParamsInStack) 1356 end, 1357 Args = header_regs(FixedRegs) ++ header_params(ReversedParams), 1358 EntryLabel = hipe_llvm:mk_label("Entry"), 1359 FloatTy = hipe_llvm:mk_double(), 1360 ExceptionSync = hipe_llvm:mk_alloca("%exception_sync", FloatTy, [], []), 1361 I2 = load_regs(FixedRegs), 1362 I3 = hipe_llvm:mk_br(mk_jump_label(get(first_label))), 1363 StoredParams = store_params(Params), 1364 EntryBlock = 1365 lists:flatten([EntryLabel, ExceptionSync, I2, LocalVars, StoredParams, I3]), 1366 Final_Code = EntryBlock ++ Code, 1367 FunctionOptions = [nounwind, noredzone, 'gc "erlang"'], 1368 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1369 FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 1370 hipe_llvm:mk_fun_def([], [], "cc 11", [], FunRetTy, FunctionName, Args, 1371 FunctionOptions, [], Final_Code). 1372 1373header_params(Params) -> 1374 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1375 [{WordTy, "%v" ++ integer_to_list(hipe_rtl:var_index(P))} || P <- Params]. 1376 1377store_params(Params) -> 1378 Fun1 = 1379 fun(X) -> 1380 Index = hipe_rtl:var_index(X), 1381 {Name, _} = trans_dst(X), 1382 ParamName = "%v" ++ integer_to_list(Index), 1383 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1384 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 1385 hipe_llvm:mk_store(WordTy, ParamName, WordTyPtr, Name, [], [], false) 1386 end, 1387 lists:map(Fun1, Params). 1388 1389fixed_registers() -> 1390 case get(hipe_target_arch) of 1391 x86 -> 1392 ["hp", "p"]; 1393 amd64 -> 1394 ["hp", "p"]; 1395 Other -> 1396 exit({?MODULE, map_registers, {"Unknown architecture", Other}}) 1397 end. 1398 1399header_regs(Registers) -> 1400 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1401 [{WordTy, "%" ++ X ++ "_in"} || X <- Registers]. 1402 1403load_regs(Registers) -> 1404 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1405 WordTyPtr = hipe_llvm:mk_pointer(WordTy), 1406 Fun1 = 1407 fun(X) -> 1408 I1 = hipe_llvm:mk_alloca("%" ++ X ++ "_reg_var", WordTy, [], []), 1409 I2 = hipe_llvm:mk_store(WordTy, "%" ++ X ++ "_in", WordTyPtr, 1410 "%" ++ X ++ "_reg_var", [], [], false), 1411 [I1, I2] 1412 end, 1413 lists:map(Fun1, Registers). 1414 1415%%------------------------------------------------------------------------------ 1416%% Relocation-specific Stuff 1417%%------------------------------------------------------------------------------ 1418 1419relocs_store(Key, Value, Relocs) -> 1420 dict:store(Key, Value, Relocs). 1421 1422relocs_to_list(Relocs) -> 1423 dict:to_list(Relocs). 1424 1425%% @doc This function is responsible for the actions needed to handle 1426%% relocations: 1427%% 1) Updates relocations with constants and switch jump tables. 1428%% 2) Creates LLVM code to declare relocations as external 1429%% functions/constants. 1430%% 3) Creates LLVM code in order to create local variables for the external 1431%% constants/labels. 1432handle_relocations(Relocs, Data, Fun) -> 1433 RelocsList = relocs_to_list(Relocs), 1434 %% Separate Relocations according to their type 1435 {CallList, AtomList, ClosureList, ClosureLabels, SwitchList} = 1436 seperate_relocs(RelocsList), 1437 %% Create code to declare atoms 1438 AtomDecl = [declare_atom(A) || A <- AtomList], 1439 %% Create code to create local name for atoms 1440 AtomLoad = [load_atom(A) || A <- AtomList], 1441 %% Create code to declare closures 1442 ClosureDecl = [declare_closure(C) || C <- ClosureList], 1443 %% Create code to create local name for closures 1444 ClosureLoad = [load_closure(C) || C <- ClosureList], 1445 %% Find function calls 1446 IsExternalCall = fun (X) -> is_external_call(X, Fun) end, 1447 ExternalCallList = lists:filter(IsExternalCall, CallList), 1448 %% Create code to declare external function 1449 FunDecl = fixed_fun_decl() ++ [call_to_decl(C) || C <- ExternalCallList], 1450 %% Extract constant labels from Constant Map (remove duplicates) 1451 ConstLabels = hipe_consttab:labels(Data), 1452 %% Create code to declare constants 1453 ConstDecl = [declare_constant(C) || C <- ConstLabels], 1454 %% Create code to create local name for constants 1455 ConstLoad = [load_constant(C) || C <- ConstLabels], 1456 %% Create code to create jump tables 1457 SwitchDecl = declare_switches(SwitchList, Fun), 1458 %% Create code to create a table with the labels of all closure calls 1459 {ClosureLabelDecl, Relocs1} = 1460 declare_closure_labels(ClosureLabels, Relocs, Fun), 1461 %% Enter constants to relocations 1462 Relocs2 = lists:foldl(fun const_to_dict/2, Relocs1, ConstLabels), 1463 %% Temporary Store inc_stack and llvm_fix_pinned_regs to Dictionary 1464 %% TODO: Remove this 1465 Relocs3 = dict:store("inc_stack_0", {call, not_remote, {bif, inc_stack_0, 0}}, Relocs2), 1466 Relocs4 = dict:store("hipe_bifs.llvm_fix_pinned_regs.0", 1467 {call, remote, {hipe_bifs, llvm_fix_pinned_regs, 0}}, Relocs3), 1468 BranchMetaData = [ 1469 hipe_llvm:mk_meta(?BRANCH_META_TAKEN, ["branch_weights", 99, 1]) 1470 , hipe_llvm:mk_meta(?BRANCH_META_NOT_TAKEN, ["branch_weights", 1, 99]) 1471 ], 1472 ExternalDeclarations = AtomDecl ++ ClosureDecl ++ ConstDecl ++ FunDecl ++ 1473 ClosureLabelDecl ++ SwitchDecl ++ BranchMetaData, 1474 LocalVariables = AtomLoad ++ ClosureLoad ++ ConstLoad, 1475 {Relocs4, ExternalDeclarations, LocalVariables}. 1476 1477%% @doc Separate relocations according to their type. 1478seperate_relocs(Relocs) -> 1479 seperate_relocs(Relocs, [], [], [], [], []). 1480 1481seperate_relocs([], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) -> 1482 {CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc}; 1483seperate_relocs([R|Rs], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) -> 1484 case R of 1485 {_, {call, _, _}} -> 1486 seperate_relocs(Rs, [R | CallAcc], AtomAcc, ClosureAcc, LabelAcc, 1487 JmpTableAcc); 1488 1489 {_, {atom, _}} -> 1490 seperate_relocs(Rs, CallAcc, [R | AtomAcc], ClosureAcc, LabelAcc, 1491 JmpTableAcc); 1492 {_, {closure, _}} -> 1493 seperate_relocs(Rs, CallAcc, AtomAcc, [R | ClosureAcc], LabelAcc, 1494 JmpTableAcc); 1495 {_, {switch, _, _}} -> 1496 seperate_relocs(Rs, CallAcc, AtomAcc, ClosureAcc, LabelAcc, 1497 [R | JmpTableAcc]); 1498 {_, {closure_label, _, _}} -> 1499 seperate_relocs(Rs, CallAcc, AtomAcc, ClosureAcc, [R | LabelAcc], 1500 JmpTableAcc) 1501 end. 1502 1503%% @doc External declaration of an atom. 1504declare_atom({AtomName, _}) -> 1505 %% The type has to be byte, or a backend might assume the constant is aligned 1506 %% and incorrectly optimise away type tests 1507 ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE), 1508 hipe_llvm:mk_const_decl("@" ++ AtomName, "external constant", ByteTy, ""). 1509 1510%% @doc Creation of local variable for an atom. 1511load_atom({AtomName, _}) -> 1512 Dst = "%" ++ AtomName ++ "_var", 1513 Name = "@" ++ AtomName, 1514 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1515 ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)), 1516 hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy). 1517 1518%% @doc External declaration of a closure. 1519declare_closure({ClosureName, _})-> 1520 ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE), 1521 hipe_llvm:mk_const_decl("@" ++ ClosureName, "external constant", ByteTy, ""). 1522 1523%% @doc Creation of local variable for a closure. 1524load_closure({ClosureName, _})-> 1525 Dst = "%" ++ ClosureName ++ "_var", 1526 Name = "@" ++ ClosureName, 1527 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1528 ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)), 1529 hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy). 1530 1531%% @doc Declaration of a local variable for a switch jump table. 1532declare_switches(JumpTableList, Fun) -> 1533 FunName = trans_mfa_name(Fun, not_remote), 1534 [declare_switch_table(X, FunName) || X <- JumpTableList]. 1535 1536declare_switch_table({Name, {switch, {TableType, Labels, _, _}, _}}, FunName) -> 1537 LabelList = [mk_jump_label(L) || L <- Labels], 1538 Fun1 = fun(X) -> "i8* blockaddress(@" ++ FunName ++ ", " ++ X ++ ")" end, 1539 List2 = lists:map(Fun1, LabelList), 1540 List3 = lists:flatten(lists:join(",\n", List2)), 1541 List4 = "[\n" ++ List3 ++ "\n]\n", 1542 hipe_llvm:mk_const_decl("@" ++ Name, "constant", TableType, List4). 1543 1544%% @doc Declaration of a variable for a table with the labels of all closure 1545%% calls in the code. 1546declare_closure_labels([], Relocs, _Fun) -> 1547 {[], Relocs}; 1548declare_closure_labels(ClosureLabels, Relocs, Fun) -> 1549 FunName = trans_mfa_name(Fun, not_remote), 1550 {LabelList, ArityList} = 1551 lists:unzip([{mk_jump_label(Label), A} || 1552 {_, {closure_label, Label, A}} <- ClosureLabels]), 1553 Relocs1 = relocs_store("table_closures", {table_closures, ArityList}, Relocs), 1554 List2 = 1555 ["i8* blockaddress(@" ++ FunName ++ ", " ++ L ++ ")" || L <- LabelList], 1556 List3 = lists:flatten(lists:join(",\n", List2)), 1557 List4 = "[\n" ++ List3 ++ "\n]\n", 1558 NrLabels = length(LabelList), 1559 ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)), 1560 TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr), 1561 ConstDecl = 1562 hipe_llvm:mk_const_decl("@table_closures", "constant", TableType, List4), 1563 {[ConstDecl], Relocs1}. 1564 1565%% @doc A call is treated as non external only in a case of a local recursive 1566%% function. 1567is_external_call({_, {call, not_remote, MFA}}, MFA) -> false; 1568is_external_call(_, _) -> true. 1569 1570%% @doc External declaration of a function. 1571call_to_decl({Name, {call, _, MFA}}) -> 1572 {M, _F, A} = MFA, 1573 CConv = "cc 11", 1574 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1575 FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 1576 {Type, Args} = 1577 case M of 1578 llvm -> 1579 {hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]), [1, 2]}; 1580 %% +precoloured regs 1581 _ -> 1582 {FunRetTy, lists:seq(1, A + ?NR_PINNED_REGS)} 1583 end, 1584 ArgsTypes = lists:duplicate(length(Args), WordTy), 1585 hipe_llvm:mk_fun_decl([], [], CConv, [], Type, "@" ++ Name, ArgsTypes, []). 1586 1587%% @doc These functions are always declared, even if not used. 1588fixed_fun_decl() -> 1589 ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE), 1590 ByteTyPtr = hipe_llvm:mk_pointer(ByteTy), 1591 LandPad = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_int(32), 1592 "@__gcc_personality_v0", [hipe_llvm:mk_int(32), hipe_llvm:mk_int(64), 1593 ByteTyPtr, ByteTyPtr], []), 1594 GCROOTDecl = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_void(), 1595 "@llvm.gcroot", [hipe_llvm:mk_pointer(ByteTyPtr), ByteTyPtr], []), 1596 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1597 FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)), 1598 FixPinnedRegs = hipe_llvm:mk_fun_decl([], [], [], [], FunRetTy, 1599 "@hipe_bifs.llvm_fix_pinned_regs.0", [], []), 1600 GcMetadata = hipe_llvm:mk_const_decl("@gc_metadata", "external constant", 1601 ByteTy, ""), 1602 [LandPad, GCROOTDecl, FixPinnedRegs, GcMetadata]. 1603 1604%% @doc Declare an External Consant. We declare all constants as i8 in order to 1605%% be able to calcucate pointers of the form DL+6, with the getelementptr 1606%% instruction. Otherwise we have to convert constants form pointers to 1607%% values, add the offset and convert them again to pointers. 1608declare_constant(Label) -> 1609 Name = "@DL" ++ integer_to_list(Label), 1610 ByteTy = hipe_llvm:mk_int(?BITS_IN_BYTE), 1611 hipe_llvm:mk_const_decl(Name, "external constant", ByteTy, ""). 1612 1613%% @doc Load a constant is achieved by converting a pointer to an integer of 1614%% the correct width. 1615load_constant(Label) -> 1616 Dst = "%DL" ++ integer_to_list(Label) ++ "_var", 1617 Name = "@DL" ++ integer_to_list(Label), 1618 WordTy = hipe_llvm:mk_int(?BITS_IN_WORD), 1619 ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(?BITS_IN_BYTE)), 1620 hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy). 1621 1622%% @doc Store external constants and calls to dictionary. 1623const_to_dict(Elem, Dict) -> 1624 Name = "DL" ++ integer_to_list(Elem), 1625 dict:store(Name, {'constant', Elem}, Dict). 1626 1627%% @doc Export the hipe literals that LLVM needs to generate the prologue as 1628%% metadata. 1629add_literals_metadata(ExternalDecls) -> 1630 Pairs = [hipe_llvm:mk_meta(integer_to_list(?FIRST_FREE_META_NO), 1631 ["P_NSP_LIMIT", ?P_NSP_LIMIT]) 1632 ,hipe_llvm:mk_meta(integer_to_list(?FIRST_FREE_META_NO + 1), 1633 ["X86_LEAF_WORDS", ?X86_LEAF_WORDS]) 1634 ,hipe_llvm:mk_meta(integer_to_list(?FIRST_FREE_META_NO + 2), 1635 ["AMD64_LEAF_WORDS", ?AMD64_LEAF_WORDS]) 1636 ], 1637 [hipe_llvm:mk_meta(?HIPE_LITERALS_META, Pairs) | 1638 Pairs ++ ExternalDecls]. 1639