1%% -*- erlang-indent-level: 2 -*- 2%% 3%% Licensed under the Apache License, Version 2.0 (the "License"); 4%% you may not use this file except in compliance with the License. 5%% You may obtain a copy of the License at 6%% 7%% http://www.apache.org/licenses/LICENSE-2.0 8%% 9%% Unless required by applicable law or agreed to in writing, software 10%% distributed under the License is distributed on an "AS IS" BASIS, 11%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12%% See the License for the specific language governing permissions and 13%% limitations under the License. 14 15-module(hipe_rtl_to_sparc). 16 17-export([translate/1]). 18 19-include("../rtl/hipe_rtl.hrl"). 20 21translate(RTL) -> 22 hipe_gensym:init(sparc), 23 hipe_gensym:set_var(sparc, hipe_sparc_registers:first_virtual()), 24 hipe_gensym:set_label(sparc, hipe_gensym:get_label(rtl)), 25 Map0 = vmap_empty(), 26 {Formals, Map1} = conv_formals(hipe_rtl:rtl_params(RTL), Map0), 27 OldData = hipe_rtl:rtl_data(RTL), 28 {Code0, NewData} = conv_insn_list(hipe_rtl:rtl_code(RTL), Map1, OldData), 29 {RegFormals, _} = split_args(Formals), 30 Code = 31 case RegFormals of 32 [] -> Code0; 33 _ -> [hipe_sparc:mk_label(hipe_gensym:get_next_label(sparc)) | 34 move_formals(RegFormals, Code0)] 35 end, 36 IsClosure = hipe_rtl:rtl_is_closure(RTL), 37 IsLeaf = hipe_rtl:rtl_is_leaf(RTL), 38 hipe_sparc:mk_defun(hipe_rtl:rtl_fun(RTL), 39 Formals, 40 IsClosure, 41 IsLeaf, 42 Code, 43 NewData, 44 [], 45 []). 46 47conv_insn_list([H|T], Map, Data) -> 48 {NewH, NewMap, NewData1} = conv_insn(H, Map, Data), 49 %% io:format("~w \n ==>\n ~w\n- - - - - - - - -\n",[H,NewH]), 50 {NewT, NewData2} = conv_insn_list(T, NewMap, NewData1), 51 {NewH ++ NewT, NewData2}; 52conv_insn_list([], _, Data) -> 53 {[], Data}. 54 55conv_insn(I, Map, Data) -> 56 case I of 57 #alu{} -> conv_alu(I, Map, Data); 58 #alub{} -> conv_alub(I, Map, Data); 59 #call{} -> conv_call(I, Map, Data); 60 #comment{} -> conv_comment(I, Map, Data); 61 #enter{} -> conv_enter(I, Map, Data); 62 #goto{} -> conv_goto(I, Map, Data); 63 #label{} -> conv_label(I, Map, Data); 64 #load{} -> conv_load(I, Map, Data); 65 #load_address{} -> conv_load_address(I, Map, Data); 66 #load_atom{} -> conv_load_atom(I, Map, Data); 67 #move{} -> conv_move(I, Map, Data); 68 #return{} -> conv_return(I, Map, Data); 69 #store{} -> conv_store(I, Map, Data); 70 #switch{} -> conv_switch(I, Map, Data); % XXX: only switch uses/updates Data 71 #fconv{} -> conv_fconv(I, Map, Data); 72 #fmove{} -> conv_fmove(I, Map, Data); 73 #fload{} -> conv_fload(I, Map, Data); 74 #fstore{} -> conv_fstore(I, Map, Data); 75 #fp{} -> conv_fp_binary(I, Map, Data); 76 #fp_unop{} -> conv_fp_unary(I, Map, Data); 77 _ -> exit({?MODULE,conv_insn,I}) 78 end. 79 80conv_fconv(I, Map, Data) -> 81 %% Dst := (double)Src, where Dst is FP reg and Src is GP reg or imm 82 {Src, Map1} = conv_src(hipe_rtl:fconv_src(I), Map), 83 {Dst, Map2} = conv_fpreg(hipe_rtl:fconv_dst(I), Map1), 84 I2 = mk_fconv(Src, Dst), 85 {I2, Map2, Data}. 86 87mk_fconv(Src, Dst) -> 88 CSP = hipe_sparc:mk_temp(14, 'untagged'), % o6 89 Offset = 100, 90 mk_store('stw', Src, CSP, Offset) ++ 91 [hipe_sparc:mk_pseudo_fload(CSP, hipe_sparc:mk_simm13(Offset), Dst, true), 92 hipe_sparc:mk_fp_unary('fitod', Dst, Dst)]. 93 94conv_fmove(I, Map, Data) -> 95 %% Dst := Src, where both Dst and Src are FP regs 96 {Src, Map1} = conv_fpreg(hipe_rtl:fmove_src(I), Map), 97 {Dst, Map2} = conv_fpreg(hipe_rtl:fmove_dst(I), Map1), 98 I2 = mk_fmove(Src, Dst), 99 {I2, Map2, Data}. 100 101mk_fmove(Src, Dst) -> 102 [hipe_sparc:mk_pseudo_fmove(Src, Dst)]. 103 104conv_fload(I, Map, Data) -> 105 %% Dst := MEM[Base+Off], where Dst is FP reg 106 {Base1, Map1} = conv_src(hipe_rtl:fload_src(I), Map), 107 {Base2, Map2} = conv_src(hipe_rtl:fload_offset(I), Map1), 108 {Dst, Map3} = conv_fpreg(hipe_rtl:fload_dst(I), Map2), 109 I2 = mk_fload(Base1, Base2, Dst), 110 {I2, Map3, Data}. 111 112mk_fload(Base1, Base2, Dst) -> 113 case hipe_sparc:is_temp(Base1) of 114 true -> 115 case hipe_sparc:is_temp(Base2) of 116 true -> 117 mk_fload_rr(Base1, Base2, Dst); 118 _ -> 119 mk_fload_ri(Base1, Base2, Dst) 120 end; 121 _ -> 122 case hipe_sparc:is_temp(Base2) of 123 true -> 124 mk_fload_ri(Base2, Base1, Dst); 125 _ -> 126 mk_fload_ii(Base1, Base2, Dst) 127 end 128 end. 129 130mk_fload_rr(Base1, Base2, Dst) -> 131 Tmp = new_untagged_temp(), 132 Disp = hipe_sparc:mk_simm13(0), 133 [hipe_sparc:mk_alu('add', Base1, Base2, Tmp), 134 hipe_sparc:mk_pseudo_fload(Tmp, Disp, Dst, false)]. 135 136mk_fload_ii(Base1, Base2, Dst) -> 137 io:format("~w: RTL fload with two immediates\n", [?MODULE]), 138 Tmp = new_untagged_temp(), 139 mk_set(Base1, Tmp, mk_fload_ri(Tmp, Base2, Dst)). 140 141mk_fload_ri(Base, Disp, Dst) -> 142 hipe_sparc:mk_fload(Base, Disp, Dst, 'new'). 143 144conv_fstore(I, Map, Data) -> 145 %% MEM[Base+Off] := Src, where Src is FP reg 146 {Base1, Map1} = conv_dst(hipe_rtl:fstore_base(I), Map), 147 {Base2, Map2} = conv_src(hipe_rtl:fstore_offset(I), Map1), 148 {Src, Map3} = conv_fpreg(hipe_rtl:fstore_src(I), Map2), 149 I2 = mk_fstore(Src, Base1, Base2), 150 {I2, Map3, Data}. 151 152mk_fstore(Src, Base1, Base2) -> 153 case hipe_sparc:is_temp(Base2) of 154 true -> 155 mk_fstore_rr(Src, Base1, Base2); 156 _ -> 157 mk_fstore_ri(Src, Base1, Base2) 158 end. 159 160mk_fstore_rr(Src, Base1, Base2) -> 161 Tmp = new_untagged_temp(), 162 Disp = hipe_sparc:mk_simm13(0), 163 [hipe_sparc:mk_alu('add', Base1, Base2, Tmp), 164 hipe_sparc:mk_pseudo_fstore(Src, Tmp, Disp)]. 165 166mk_fstore_ri(Src, Base, Disp) -> 167 hipe_sparc:mk_fstore(Src, Base, Disp, 'new'). 168 169conv_fp_binary(I, Map, Data) -> 170 {Src1, Map1} = conv_fpreg(hipe_rtl:fp_src1(I), Map), 171 {Src2, Map2} = conv_fpreg(hipe_rtl:fp_src2(I), Map1), 172 {Dst, Map3} = conv_fpreg(hipe_rtl:fp_dst(I), Map2), 173 RtlFpOp = hipe_rtl:fp_op(I), 174 I2 = mk_fp_binary(RtlFpOp, Src1, Src2, Dst), 175 {I2, Map3, Data}. 176 177mk_fp_binary(RtlFpOp, Src1, Src2, Dst) -> 178 FpBinOp = 179 case RtlFpOp of 180 'fadd' -> 'faddd'; 181 'fdiv' -> 'fdivd'; 182 'fmul' -> 'fmuld'; 183 'fsub' -> 'fsubd' 184 end, 185 [hipe_sparc:mk_fp_binary(FpBinOp, Src1, Src2, Dst)]. 186 187conv_fp_unary(I, Map, Data) -> 188 {Src, Map1} = conv_fpreg(hipe_rtl:fp_unop_src(I), Map), 189 {Dst, Map2} = conv_fpreg(hipe_rtl:fp_unop_dst(I), Map1), 190 RtlFpUnOp = hipe_rtl:fp_unop_op(I), 191 I2 = mk_fp_unary(RtlFpUnOp, Src, Dst), 192 {I2, Map2, Data}. 193 194mk_fp_unary(RtlFpUnOp, Src, Dst) -> 195 FpUnOp = 196 case RtlFpUnOp of 197 'fchs' -> 'fnegd' 198 end, 199 [hipe_sparc:mk_fp_unary(FpUnOp, Src, Dst)]. 200 201conv_alu(I, Map, Data) -> 202 %% dst = src1 aluop src2 203 {Dst, Map0} = conv_dst(hipe_rtl:alu_dst(I), Map), 204 {Src1, Map1} = conv_src(hipe_rtl:alu_src1(I), Map0), 205 {Src2, Map2} = conv_src(hipe_rtl:alu_src2(I), Map1), 206 AluOp = conv_aluop(hipe_rtl:alu_op(I)), 207 {I2, _DidCommute} = mk_alu(AluOp, Src1, Src2, Dst), 208 {I2, Map2, Data}. 209 210mk_alu(XAluOp, Src1, Src2, Dst) -> 211 case hipe_sparc:is_temp(Src1) of 212 true -> 213 case hipe_sparc:is_temp(Src2) of 214 true -> 215 {mk_alu_rs(XAluOp, Src1, Src2, Dst), 216 false}; 217 _ -> 218 {mk_alu_ri(XAluOp, Src1, Src2, Dst), 219 false} 220 end; 221 _ -> 222 case hipe_sparc:is_temp(Src2) of 223 true -> 224 mk_alu_ir(XAluOp, Src1, Src2, Dst); 225 _ -> 226 {mk_alu_ii(XAluOp, Src1, Src2, Dst), 227 false} 228 end 229 end. 230 231mk_alu_ii(XAluOp, Src1, Src2, Dst) -> 232 io:format("~w: ALU with two immediates (~w ~w ~w ~w)\n", 233 [?MODULE, XAluOp, Src1, Src2, Dst]), 234 Tmp = new_untagged_temp(), 235 mk_set(Src1, Tmp, mk_alu_ri(XAluOp, Tmp, Src2, Dst)). 236 237mk_alu_ir(XAluOp, Src1, Src2, Dst) -> 238 case xaluop_commutes(XAluOp) of 239 true -> 240 {mk_alu_ri(XAluOp, Src2, Src1, Dst), 241 true}; 242 _ -> 243 Tmp = new_untagged_temp(), 244 {mk_set(Src1, Tmp, mk_alu_rs(XAluOp, Tmp, Src2, Dst)), 245 false} 246 end. 247 248mk_alu_ri(XAluOp, Src1, Src2, Dst) -> 249 case xaluop_is_shift(XAluOp) of 250 true -> 251 mk_shift_ri(XAluOp, Src1, Src2, Dst); 252 false -> 253 mk_arith_ri(XAluOp, Src1, Src2, Dst) 254 end. 255 256mk_shift_ri(XShiftOp, Src1, Src2, Dst) when is_integer(Src2) -> 257 if Src2 >= 0, Src2 < 32 -> % XXX: sparc64: < 64 258 mk_alu_rs(XShiftOp, Src1, hipe_sparc:mk_uimm5(Src2), Dst); 259 true -> 260 exit({?MODULE,mk_shift_ri,Src2}) % excessive shifts are errors 261 end. 262 263mk_arith_ri(XAluOp, Src1, Src2, Dst) when is_integer(Src2) -> 264 if -4096 =< Src2, Src2 < 4096 -> 265 mk_alu_rs(XAluOp, Src1, hipe_sparc:mk_simm13(Src2), Dst); 266 true -> 267 Tmp = new_untagged_temp(), 268 mk_set(Src2, Tmp, mk_alu_rs(XAluOp, Src1, Tmp, Dst)) 269 end. 270 271mk_alu_rs(XAluOp, Src1, Src2, Dst) -> 272 [hipe_sparc:mk_alu(xaluop_normalise(XAluOp), Src1, Src2, Dst)]. 273 274conv_alub(I, Map, Data) -> 275 %% dst = src1 aluop src2; if COND goto label 276 HasDst = hipe_rtl:alub_has_dst(I), 277 {Dst, Map0} = 278 case HasDst of 279 false -> {hipe_sparc:mk_g0(), Map}; 280 true -> conv_dst(hipe_rtl:alub_dst(I), Map) 281 end, 282 {Src1, Map1} = conv_src(hipe_rtl:alub_src1(I), Map0), 283 {Src2, Map2} = conv_src(hipe_rtl:alub_src2(I), Map1), 284 Cond = conv_cond(hipe_rtl:alub_cond(I)), 285 RtlAlubOp = hipe_rtl:alub_op(I), 286 I2 = 287 case RtlAlubOp of 288 'mul' -> 289 %% To check for overflow in 32x32->32 multiplication: 290 %% smul Src1,Src2,Dst % Dst is lo32(Res), %y is %hi32(Res) 291 %% rd %y,TmpHi 292 %% sra Dst,31,TmpSign % fill TmpSign with sign of Dst 293 %% subcc TmpSign,TmpHi,%g0 294 %% [bne OverflowLabel] 295 NewCond = 296 case Cond of 297 vs -> ne; 298 vc -> eq 299 end, 300 TmpHi = hipe_sparc:mk_new_temp('untagged'), 301 TmpSign = hipe_sparc:mk_new_temp('untagged'), 302 G0 = hipe_sparc:mk_g0(), 303 {I1, _DidCommute} = mk_alu('smul', Src1, Src2, Dst), 304 I1 ++ 305 [hipe_sparc:mk_rdy(TmpHi), 306 hipe_sparc:mk_alu('sra', Dst, hipe_sparc:mk_uimm5(31), TmpSign) | 307 conv_alub2(G0, TmpSign, 'cmpcc', NewCond, TmpHi, I)]; 308 _ -> 309 XAluOp = 310 case (not HasDst) andalso RtlAlubOp =:= 'sub' of 311 true -> 'cmpcc'; % == a subcc that commutes 312 false -> conv_alubop_cc(RtlAlubOp) 313 end, 314 conv_alub2(Dst, Src1, XAluOp, Cond, Src2, I) 315 end, 316 {I2, Map2, Data}. 317 318conv_alub2(Dst, Src1, XAluOp, Cond, Src2, I) -> 319 conv_alub_bp(Dst, Src1, XAluOp, Cond, Src2, I). 320 321conv_alub_bp(Dst, Src1, XAluOp, Cond, Src2, I) -> 322 TrueLab = hipe_rtl:alub_true_label(I), 323 FalseLab = hipe_rtl:alub_false_label(I), 324 Pred = hipe_rtl:alub_pred(I), 325 %% "Dst = Src1 AluOp Src2; if COND" becomes 326 %% "Dst = Src1 AluOpCC Src22; if-COND(CC)" 327 {I2, DidCommute} = mk_alu(XAluOp, Src1, Src2, Dst), 328 NewCond = 329 case DidCommute andalso XAluOp =:= 'cmpcc' of 330 true -> commute_cond(Cond); % subcc does not commute; its conditions do 331 false -> Cond 332 end, 333 I2 ++ mk_pseudo_bp(NewCond, TrueLab, FalseLab, Pred). 334 335conv_alubop_cc(RtlAlubOp) -> 336 case RtlAlubOp of 337 'add' -> 'addcc'; 338 'sub' -> 'subcc'; 339 %% mul: handled elsewhere 340 'or' -> 'orcc'; 341 'and' -> 'andcc'; 342 'xor' -> 'xorcc' 343 %% no shift ops 344 end. 345 346conv_call(I, Map, Data) -> 347 {Args, Map0} = conv_src_list(hipe_rtl:call_arglist(I), Map), 348 {Dsts, Map1} = conv_dst_list(hipe_rtl:call_dstlist(I), Map0), 349 {Fun, Map2} = conv_fun(hipe_rtl:call_fun(I), Map1), 350 ContLab = hipe_rtl:call_continuation(I), 351 ExnLab = hipe_rtl:call_fail(I), 352 Linkage = hipe_rtl:call_type(I), 353 I2 = mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage), 354 {I2, Map2, Data}. 355 356mk_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) -> 357 case hipe_sparc:is_prim(Fun) of 358 true -> 359 mk_primop_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage); 360 false -> 361 mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) 362 end. 363 364mk_primop_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) -> 365 case hipe_sparc:prim_prim(Prim) of 366 %% no SPARC-specific primops defined yet 367 _ -> 368 mk_general_call(Dsts, Prim, Args, ContLab, ExnLab, Linkage) 369 end. 370 371mk_general_call(Dsts, Fun, Args, ContLab, ExnLab, Linkage) -> 372 %% The backend does not support pseudo_calls without a 373 %% continuation label, so we make sure each call has one. 374 {RealContLab, Tail} = 375 case mk_call_results(Dsts) of 376 [] -> 377 %% Avoid consing up a dummy basic block if the moves list 378 %% is empty, as is typical for calls to suspend/0. 379 %% This should be subsumed by a general "optimise the CFG" 380 %% module, and could probably be removed. 381 case ContLab of 382 [] -> 383 NewContLab = hipe_gensym:get_next_label(sparc), 384 {NewContLab, [hipe_sparc:mk_label(NewContLab)]}; 385 _ -> 386 {ContLab, []} 387 end; 388 Moves -> 389 %% Change the call to continue at a new basic block. 390 %% In this block move the result registers to the Dsts, 391 %% then continue at the call's original continuation. 392 NewContLab = hipe_gensym:get_next_label(sparc), 393 case ContLab of 394 [] -> 395 %% This is just a fallthrough 396 %% No jump back after the moves. 397 {NewContLab, 398 [hipe_sparc:mk_label(NewContLab) | 399 Moves]}; 400 _ -> 401 %% The call has a continuation. Jump to it. 402 {NewContLab, 403 [hipe_sparc:mk_label(NewContLab) | 404 Moves ++ 405 [hipe_sparc:mk_b_label(ContLab)]]} 406 end 407 end, 408 SDesc = hipe_sparc:mk_sdesc(ExnLab, 0, length(Args), {}), 409 CallInsn = hipe_sparc:mk_pseudo_call(Fun, SDesc, RealContLab, Linkage), 410 {RegArgs,StkArgs} = split_args(Args), 411 mk_push_args(StkArgs, move_actuals(RegArgs, [CallInsn | Tail])). 412 413mk_call_results(Dsts) -> 414 case Dsts of 415 [] -> []; 416 [Dst] -> 417 RV = hipe_sparc:mk_rv(), 418 [hipe_sparc:mk_pseudo_move(RV, Dst)] 419 end. 420 421mk_push_args(StkArgs, Tail) -> 422 case length(StkArgs) of 423 0 -> 424 Tail; 425 NrStkArgs -> 426 [hipe_sparc:mk_pseudo_call_prepare(NrStkArgs) | 427 mk_store_args(StkArgs, NrStkArgs * word_size(), Tail)] 428 end. 429 430mk_store_args([Arg|Args], PrevOffset, Tail) -> 431 Offset = PrevOffset - word_size(), 432 {Src,FixSrc} = 433 case hipe_sparc:is_temp(Arg) of 434 true -> 435 {Arg, []}; 436 _ -> 437 Tmp = new_tagged_temp(), 438 {Tmp, mk_set(Arg, Tmp)} 439 end, 440 %% XXX: sparc64: stx 441 Store = hipe_sparc:mk_store('stw', Src, hipe_sparc:mk_sp(), hipe_sparc:mk_simm13(Offset)), 442 mk_store_args(Args, Offset, FixSrc ++ [Store | Tail]); 443mk_store_args([], _, Tail) -> 444 Tail. 445 446conv_comment(I, Map, Data) -> 447 I2 = [hipe_sparc:mk_comment(hipe_rtl:comment_text(I))], 448 {I2, Map, Data}. 449 450conv_enter(I, Map, Data) -> 451 {Args, Map0} = conv_src_list(hipe_rtl:enter_arglist(I), Map), 452 {Fun, Map1} = conv_fun(hipe_rtl:enter_fun(I), Map0), 453 I2 = mk_enter(Fun, Args, hipe_rtl:enter_type(I)), 454 {I2, Map1, Data}. 455 456mk_enter(Fun, Args, Linkage) -> 457 Arity = length(Args), 458 {RegArgs,StkArgs} = split_args(Args), 459 move_actuals(RegArgs, 460 [hipe_sparc:mk_pseudo_tailcall_prepare(), 461 hipe_sparc:mk_pseudo_tailcall(Fun, Arity, StkArgs, Linkage)]). 462 463conv_goto(I, Map, Data) -> 464 I2 = [hipe_sparc:mk_b_label(hipe_rtl:goto_label(I))], 465 {I2, Map, Data}. 466 467conv_label(I, Map, Data) -> 468 I2 = [hipe_sparc:mk_label(hipe_rtl:label_name(I))], 469 {I2, Map, Data}. 470 471conv_load(I, Map, Data) -> 472 {Dst, Map0} = conv_dst(hipe_rtl:load_dst(I), Map), 473 {Base1, Map1} = conv_src(hipe_rtl:load_src(I), Map0), 474 {Base2, Map2} = conv_src(hipe_rtl:load_offset(I), Map1), 475 LdOp = conv_ldop(hipe_rtl:load_size(I), hipe_rtl:load_sign(I)), 476 {I2, _DidCommute} = mk_alu(LdOp, Base1, Base2, Dst), 477 {I2, Map2, Data}. 478 479conv_ldop(LoadSize, LoadSign) -> 480 case LoadSize of 481 word -> 'lduw'; % XXX: sparc64: ldx 482 int32 -> 'lduw'; % XXX: sparc64: lduw or ldsw 483 int16 -> 484 case LoadSign of 485 signed -> 'ldsh'; 486 unsigned -> 'lduh' 487 end; 488 byte -> 489 case LoadSign of 490 signed -> 'ldsb'; 491 unsigned -> 'ldub' 492 end 493 end. 494 495conv_load_address(I, Map, Data) -> 496 {Dst, Map0} = conv_dst(hipe_rtl:load_address_dst(I), Map), 497 Addr = hipe_rtl:load_address_addr(I), 498 Type = hipe_rtl:load_address_type(I), 499 Src = {Addr,Type}, 500 I2 = [hipe_sparc:mk_pseudo_set(Src, Dst)], 501 {I2, Map0, Data}. 502 503conv_load_atom(I, Map, Data) -> 504 {Dst, Map0} = conv_dst(hipe_rtl:load_atom_dst(I), Map), 505 Src = hipe_rtl:load_atom_atom(I), 506 I2 = [hipe_sparc:mk_pseudo_set(Src, Dst)], 507 {I2, Map0, Data}. 508 509conv_move(I, Map, Data) -> 510 {Dst, Map0} = conv_dst(hipe_rtl:move_dst(I), Map), 511 {Src, Map1} = conv_src(hipe_rtl:move_src(I), Map0), 512 I2 = mk_move(Src, Dst, []), 513 {I2, Map1, Data}. 514 515mk_move(Src, Dst, Tail) -> 516 case hipe_sparc:is_temp(Src) of 517 true -> [hipe_sparc:mk_pseudo_move(Src, Dst) | Tail]; 518 _ -> mk_set(Src, Dst, Tail) 519 end. 520 521conv_return(I, Map, Data) -> 522 %% TODO: multiple-value returns 523 {[Arg], Map0} = conv_src_list(hipe_rtl:return_varlist(I), Map), 524 I2 = mk_move(Arg, hipe_sparc:mk_rv(), [hipe_sparc:mk_pseudo_ret()]), 525 {I2, Map0, Data}. 526 527conv_store(I, Map, Data) -> 528 {Base1, Map0} = conv_src(hipe_rtl:store_base(I), Map), 529 {Src, Map1} = conv_src(hipe_rtl:store_src(I), Map0), 530 {Base2, Map2} = conv_src(hipe_rtl:store_offset(I), Map1), 531 StOp = conv_stop(hipe_rtl:store_size(I)), 532 I2 = mk_store(StOp, Src, Base1, Base2), 533 {I2, Map2, Data}. 534 535conv_stop(StoreSize) -> 536 case StoreSize of 537 word -> 'stw'; % XXX: sparc64: stx 538 int32 -> 'stw'; 539 byte -> 'stb' 540 end. 541 542mk_store(StOp, Src, Base1, Base2) -> 543 case hipe_sparc:is_temp(Src) of 544 true -> 545 mk_store2(StOp, Src, Base1, Base2); 546 _ -> 547 Tmp = new_untagged_temp(), 548 mk_set(Src, Tmp, mk_store2(StOp, Tmp, Base1, Base2)) 549 end. 550 551mk_store2(StOp, Src, Base1, Base2) -> 552 case hipe_sparc:is_temp(Base1) of 553 true -> 554 case hipe_sparc:is_temp(Base2) of 555 true -> 556 mk_store_rr(StOp, Src, Base1, Base2); 557 _ -> 558 mk_store_ri(StOp, Src, Base1, Base2) 559 end; 560 _ -> 561 case hipe_sparc:is_temp(Base2) of 562 true -> 563 mk_store_ri(StOp, Src, Base2, Base1); 564 _ -> 565 mk_store_ii(StOp, Src, Base1, Base2) 566 end 567 end. 568 569mk_store_ii(StOp, Src, Base, Disp) -> 570 Tmp = new_untagged_temp(), 571 mk_set(Base, Tmp, mk_store_ri(StOp, Src, Tmp, Disp)). 572 573mk_store_ri(StOp, Src, Base, Disp) -> 574 hipe_sparc:mk_store(StOp, Src, Base, Disp, 'new', []). 575 576mk_store_rr(StOp, Src, Base1, Base2) -> 577 [hipe_sparc:mk_store(StOp, Src, Base1, Base2)]. 578 579conv_switch(I, Map, Data) -> 580 Labels = hipe_rtl:switch_labels(I), 581 LMap = [{label,L} || L <- Labels], 582 {NewData, JTabLab} = 583 case hipe_rtl:switch_sort_order(I) of 584 [] -> 585 hipe_consttab:insert_block(Data, word, LMap); 586 SortOrder -> 587 hipe_consttab:insert_sorted_block(Data, word, LMap, SortOrder) 588 end, 589 %% no immediates allowed here 590 {IndexR, Map1} = conv_dst(hipe_rtl:switch_src(I), Map), 591 JTabR = new_untagged_temp(), 592 OffsetR = new_untagged_temp(), 593 DestR = new_untagged_temp(), 594 I2 = 595 [hipe_sparc:mk_pseudo_set({JTabLab,constant}, JTabR), 596 %% XXX: sparc64: << 3 597 hipe_sparc:mk_alu('sll', IndexR, hipe_sparc:mk_uimm5(2), OffsetR), 598 %% XXX: sparc64: ldx 599 hipe_sparc:mk_alu('lduw', JTabR, OffsetR, DestR), 600 hipe_sparc:mk_jmp(DestR, hipe_sparc:mk_simm13(0), Labels)], 601 {I2, Map1, NewData}. 602 603%%% Create a conditional branch. 604 605mk_pseudo_bp(Cond, TrueLabel, FalseLabel, Pred) -> 606 [hipe_sparc:mk_pseudo_bp(Cond, TrueLabel, FalseLabel, Pred)]. 607 608%%% Load an integer constant into a register. 609 610mk_set(Value, Dst) -> mk_set(Value, Dst, []). 611 612mk_set(Value, Dst, Tail) -> 613 hipe_sparc:mk_set(Value, Dst, Tail). 614 615%%% Convert an RTL ALU op. 616 617conv_aluop(RtlAluOp) -> 618 case RtlAluOp of 619 'add' -> 'add'; 620 'sub' -> 'sub'; 621 'mul' -> 'mulx'; 622 'or' -> 'or'; 623 'and' -> 'and'; 624 'xor' -> 'xor'; 625 'sll' -> 'sll'; % XXX: sparc64: sllx 626 'srl' -> 'srl'; % XXX: sparc64: srlx 627 'sra' -> 'sra' % XXX: sparc64: srax 628 end. 629 630%%% Check if an extended SPARC AluOp commutes. 631 632xaluop_commutes(XAluOp) -> 633 case XAluOp of 634 %% 'cmp' -> true; 635 'cmpcc' -> true; 636 'add' -> true; 637 'addcc' -> true; 638 'and' -> true; 639 'andcc' -> true; 640 'or' -> true; 641 'orcc' -> true; 642 'xor' -> true; 643 'xorcc' -> true; 644 'sub' -> false; 645 'subcc' -> false; 646 'mulx' -> true; 647 'smul' -> true; 648 'sll' -> false; 649 'srl' -> false; 650 'sra' -> false; 651 %% 'sllx' -> false; 652 %% 'srlx' -> false; 653 %% 'srax' -> false; 654 'ldsb' -> true; 655 'ldsh' -> true; 656 %% 'ldsw' -> true; 657 'ldub' -> true; 658 'lduh' -> true; 659 'lduw' -> true 660 %% 'ldx' -> true 661 end. 662 663%%% Check if an extended SPARC AluOp is a shift. 664 665xaluop_is_shift(XAluOp) -> 666 case XAluOp of 667 'add' -> false; 668 'addcc' -> false; 669 'and' -> false; 670 'andcc' -> false; 671 'cmpcc' -> false; 672 'ldsb' -> false; 673 'ldub' -> false; 674 'lduw' -> false; 675 'or' -> false; 676 'sll' -> true; 677 %% 'sllx' -> true; 678 'smul' -> false; 679 'sra' -> true; 680 %% 'srax' -> true; 681 'srl' -> true; 682 %% 'srlx' -> true; 683 'sub' -> false; 684 'subcc' -> false; 685 'xor' -> false 686 end. 687 688%%% Convert an extended SPARC AluOp back to a plain AluOp. 689%%% This just maps cmp{,cc} to sub{,cc}. 690 691xaluop_normalise(XAluOp) -> 692 case XAluOp of 693 'add' -> 'add'; 694 'addcc' -> 'addcc'; 695 'and' -> 'and'; 696 'andcc' -> 'andcc'; 697 %% 'cmp' -> 'sub'; 698 'cmpcc' -> 'subcc'; 699 'ldsb' -> 'ldsb'; 700 'ldub' -> 'ldub'; 701 'lduw' -> 'lduw'; 702 'or' -> 'or'; 703 'sll' -> 'sll'; 704 'smul' -> 'smul'; 705 'sra' -> 'sra'; 706 'srl' -> 'srl'; 707 'sub' -> 'sub'; 708 'subcc' -> 'subcc'; 709 'xor' -> 'xor' 710 end. 711 712%%% Convert an RTL condition code. 713 714conv_cond(RtlCond) -> 715 case RtlCond of 716 eq -> 'e'; 717 ne -> 'ne'; 718 gt -> 'g'; 719 gtu -> 'gu'; % >u 720 ge -> 'ge'; 721 geu -> 'geu'; % >=u 722 lt -> 'l'; 723 ltu -> 'lu'; % <u 724 le -> 'le'; 725 leu -> 'leu'; % <=u 726 overflow -> 'vs'; 727 not_overflow -> 'vc' 728 end. 729 730%%% Commute a SPARC condition code. 731 732commute_cond(Cond) -> % if x Cond y, then y commute_cond(Cond) x 733 case Cond of 734 'e' -> 'e'; % ==, == 735 'ne' -> 'ne'; % !=, != 736 'g' -> 'l'; % >, < 737 'ge' -> 'le'; % >=, <= 738 'l' -> 'g'; % <, > 739 'le' -> 'ge'; % <=, >= 740 'gu' -> 'lu'; % >u, <u 741 'geu' -> 'leu'; % >=u, <=u 742 'lu' -> 'gu'; % <u, >u 743 'leu' -> 'geu' % <=u, >=u 744 %% vs/vc: n/a 745 end. 746 747%%% Split a list of formal or actual parameters into the 748%%% part passed in registers and the part passed on the stack. 749%%% The parameters passed in registers are also tagged with 750%%% the corresponding registers. 751 752split_args(Args) -> 753 split_args(0, hipe_sparc_registers:nr_args(), Args, []). 754 755split_args(I, N, [Arg|Args], RegArgs) when I < N -> 756 Reg = hipe_sparc_registers:arg(I), 757 Temp = hipe_sparc:mk_temp(Reg, 'tagged'), 758 split_args(I+1, N, Args, [{Arg,Temp}|RegArgs]); 759split_args(_, _, StkArgs, RegArgs) -> 760 {RegArgs, StkArgs}. 761 762%%% Convert a list of actual parameters passed in 763%%% registers (from split_args/1) to a list of moves. 764 765move_actuals([{Src,Dst}|Actuals], Rest) -> 766 move_actuals(Actuals, mk_move(Src, Dst, Rest)); 767move_actuals([], Rest) -> 768 Rest. 769 770%%% Convert a list of formal parameters passed in 771%%% registers (from split_args/1) to a list of moves. 772 773move_formals([{Dst,Src}|Formals], Rest) -> 774 move_formals(Formals, [hipe_sparc:mk_pseudo_move(Src, Dst) | Rest]); 775move_formals([], Rest) -> 776 Rest. 777 778%%% Convert a 'fun' operand (MFA, prim, or temp) 779 780conv_fun(Fun, Map) -> 781 case hipe_rtl:is_var(Fun) of 782 true -> 783 conv_dst(Fun, Map); 784 false -> 785 case hipe_rtl:is_reg(Fun) of 786 true -> 787 conv_dst(Fun, Map); 788 false -> 789 if is_atom(Fun) -> 790 {hipe_sparc:mk_prim(Fun), Map}; 791 true -> 792 {conv_mfa(Fun), Map} 793 end 794 end 795 end. 796 797%%% Convert an MFA operand. 798 799conv_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) -> 800 hipe_sparc:mk_mfa(M, F, A). 801 802%%% Convert an RTL source operand (imm/var/reg). 803%%% Returns a temp or a naked integer. 804 805conv_src(Opnd, Map) -> 806 case hipe_rtl:is_imm(Opnd) of 807 true -> 808 Value = hipe_rtl:imm_value(Opnd), 809 if is_integer(Value) -> 810 {Value, Map} 811 end; 812 false -> 813 conv_dst(Opnd, Map) 814 end. 815 816conv_src_list([O|Os], Map) -> 817 {V, Map1} = conv_src(O, Map), 818 {Vs, Map2} = conv_src_list(Os, Map1), 819 {[V|Vs], Map2}; 820conv_src_list([], Map) -> 821 {[], Map}. 822 823%%% Convert an RTL destination operand (var/reg). 824 825conv_fpreg(Opnd, Map) -> 826 true = hipe_rtl:is_fpreg(Opnd), 827 conv_dst(Opnd, Map). 828 829conv_dst(Opnd, Map) -> 830 {Name, Type} = 831 case hipe_rtl:is_var(Opnd) of 832 true -> 833 {hipe_rtl:var_index(Opnd), 'tagged'}; 834 false -> 835 case hipe_rtl:is_fpreg(Opnd) of 836 true -> 837 {hipe_rtl:fpreg_index(Opnd), 'double'}; 838 false -> 839 {hipe_rtl:reg_index(Opnd), 'untagged'} 840 end 841 end, 842 IsPrecoloured = 843 case Type of 844 'double' -> false; %hipe_sparc_registers:is_precoloured_fpr(Name); 845 _ -> hipe_sparc_registers:is_precoloured_gpr(Name) 846 end, 847 case IsPrecoloured of 848 true -> 849 {hipe_sparc:mk_temp(Name, Type), Map}; 850 false -> 851 case vmap_lookup(Map, Opnd) of 852 {value, NewTemp} -> 853 {NewTemp, Map}; 854 _ -> 855 NewTemp = hipe_sparc:mk_new_temp(Type), 856 {NewTemp, vmap_bind(Map, Opnd, NewTemp)} 857 end 858 end. 859 860conv_dst_list([O|Os], Map) -> 861 {Dst, Map1} = conv_dst(O, Map), 862 {Dsts, Map2} = conv_dst_list(Os, Map1), 863 {[Dst|Dsts], Map2}; 864conv_dst_list([], Map) -> 865 {[], Map}. 866 867conv_formals(Os, Map) -> 868 conv_formals(hipe_sparc_registers:nr_args(), Os, Map, []). 869 870conv_formals(N, [O|Os], Map, Res) -> 871 Type = 872 case hipe_rtl:is_var(O) of 873 true -> 'tagged'; 874 _ -> 'untagged' 875 end, 876 Dst = 877 if N > 0 -> hipe_sparc:mk_new_temp(Type); % allocatable 878 true -> hipe_sparc:mk_new_nonallocatable_temp(Type) 879 end, 880 Map1 = vmap_bind(Map, O, Dst), 881 conv_formals(N-1, Os, Map1, [Dst|Res]); 882conv_formals(_, [], Map, Res) -> 883 {lists:reverse(Res), Map}. 884 885%%% new_untagged_temp -- conjure up an untagged scratch reg 886 887new_untagged_temp() -> 888 hipe_sparc:mk_new_temp('untagged'). 889 890%%% new_tagged_temp -- conjure up a tagged scratch reg 891 892new_tagged_temp() -> 893 hipe_sparc:mk_new_temp('tagged'). 894 895%%% Map from RTL var/reg operands to temps. 896 897vmap_empty() -> 898 gb_trees:empty(). 899 900vmap_lookup(Map, Key) -> 901 gb_trees:lookup(Key, Map). 902 903vmap_bind(Map, Key, Val) -> 904 gb_trees:insert(Key, Val, Map). 905 906word_size() -> 907 hipe_rtl_arch:word_size(). 908