1 2 /*---------------------------------------------------------------*/ 3 /*--- begin host_mips_isel.c ---*/ 4 /*---------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2010-2012 RT-RK 11 mips-valgrind (at) rt-rk.com 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 26 02110-1301, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 */ 30 31 #include "libvex_basictypes.h" 32 #include "libvex_ir.h" 33 #include "libvex.h" 34 35 #include "main_util.h" 36 #include "main_globals.h" 37 #include "host_generic_regs.h" 38 #include "host_mips_defs.h" 39 40 /*---------------------------------------------------------*/ 41 /*--- Register Usage Conventions ---*/ 42 /*---------------------------------------------------------*/ 43 /* 44 45 Integer Regs 46 ------------ 47 ZERO0 Reserved 48 GPR1:9 Allocateable 49 10 GuestStatePointer 50 GPR1:9 Allocateable 51 SP StackFramePointer 52 RA LinkRegister 53 54 */ 55 56 static Bool mode64 = False; 57 58 /* GPR register class for mips32/64 */ 59 #define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32) 60 61 /* FPR register class for mips32/64 */ 62 #define HRcFPR(__mode64) (__mode64 ? HRcFlt64 : HRcFlt32) 63 64 /*---------------------------------------------------------*/ 65 /*--- ISelEnv ---*/ 66 /*---------------------------------------------------------*/ 67 68 /* This carries around: 69 70 - A mapping from IRTemp to IRType, giving the type of any IRTemp we 71 might encounter. This is computed before insn selection starts, 72 and does not change. 73 74 - A mapping from IRTemp to HReg. This tells the insn selector 75 which virtual register(s) are associated with each IRTemp 76 temporary. This is computed before insn selection starts, and 77 does not change. We expect this mapping to map precisely the 78 same set of IRTemps as the type mapping does. 79 80 - vregmap holds the primary register for the IRTemp. 81 - vregmapHI is only used for 64-bit integer-typed 82 IRTemps. It holds the identity of a second 83 32-bit virtual HReg, which holds the high half 84 of the value. 85 86 - The code array, that is, the insns selected so far. 87 88 - A counter, for generating new virtual registers. 89 90 - The host subarchitecture we are selecting insns for. 91 This is set at the start and does not change. 92 93 - A Bool for indicating whether we may generate chain-me 94 instructions for control flow transfers, or whether we must use 95 XAssisted. 96 97 - The maximum guest address of any guest insn in this block. 98 Actually, the address of the highest-addressed byte from any insn 99 in this block. Is set at the start and does not change. This is 100 used for detecting jumps which are definitely forward-edges from 101 this block, and therefore can be made (chained) to the fast entry 102 point of the destination, thereby avoiding the destination's 103 event check. 104 105 Note, this is all (well, mostly) host-independent. 106 */ 107 108 typedef 109 struct { 110 /* Constant -- are set at the start and do not change. */ 111 IRTypeEnv* type_env; 112 113 HReg* vregmap; 114 HReg* vregmapHI; 115 Int n_vregmap; 116 117 UInt hwcaps; 118 Bool mode64; 119 120 Bool chainingAllowed; 121 Addr64 max_ga; 122 123 /* These are modified as we go along. */ 124 HInstrArray* code; 125 Int vreg_ctr; 126 } 127 ISelEnv; 128 129 static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp) 130 { 131 vassert(tmp >= 0); 132 vassert(tmp < env->n_vregmap); 133 return env->vregmap[tmp]; 134 } 135 136 static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp) 137 { 138 vassert(tmp >= 0); 139 vassert(tmp < env->n_vregmap); 140 vassert(env->vregmapHI[tmp] != INVALID_HREG); 141 *vrLO = env->vregmap[tmp]; 142 *vrHI = env->vregmapHI[tmp]; 143 } 144 145 static void 146 lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp) 147 { 148 vassert(env->mode64); 149 vassert(tmp >= 0); 150 vassert(tmp < env->n_vregmap); 151 vassert(env->vregmapHI[tmp] != INVALID_HREG); 152 *vrLO = env->vregmap[tmp]; 153 *vrHI = env->vregmapHI[tmp]; 154 } 155 156 static void addInstr(ISelEnv * env, MIPSInstr * instr) 157 { 158 addHInstr(env->code, instr); 159 if (vex_traceflags & VEX_TRACE_VCODE) { 160 ppMIPSInstr(instr, mode64); 161 vex_printf("\n"); 162 } 163 } 164 165 static HReg newVRegI(ISelEnv * env) 166 { 167 HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64), 168 True /*virtual reg */ ); 169 env->vreg_ctr++; 170 return reg; 171 } 172 173 static HReg newVRegD(ISelEnv * env) 174 { 175 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /*virtual reg */ ); 176 env->vreg_ctr++; 177 return reg; 178 } 179 180 static HReg newVRegF(ISelEnv * env) 181 { 182 HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->mode64), 183 True /*virtual reg */ ); 184 env->vreg_ctr++; 185 return reg; 186 } 187 188 static void add_to_sp(ISelEnv * env, UInt n) 189 { 190 HReg sp = StackPointer(mode64); 191 vassert(n < 256 && (n % 8) == 0); 192 addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True, 193 toUShort(n)))); 194 } 195 196 static void sub_from_sp(ISelEnv * env, UInt n) 197 { 198 HReg sp = StackPointer(mode64); 199 vassert(n < 256 && (n % 8) == 0); 200 addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp, 201 MIPSRH_Imm(True, toUShort(n)))); 202 } 203 204 /*---------------------------------------------------------*/ 205 /*--- ISEL: Forward declarations ---*/ 206 /*---------------------------------------------------------*/ 207 208 /* These are organised as iselXXX and iselXXX_wrk pairs. The 209 iselXXX_wrk do the real work, but are not to be called directly. 210 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then 211 checks that all returned registers are virtual. You should not 212 call the _wrk version directly. 213 */ 214 /* 32-bit mode: Compute an I8/I16/I32 into a RH 215 (reg-or-halfword-immediate). 216 It's important to specify whether the immediate is to be regarded 217 as signed or not. If yes, this will never return -32768 as an 218 immediate; this guaranteed that all signed immediates that are 219 return can have their sign inverted if need be. 220 */ 221 static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e); 222 static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e); 223 224 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an immediate in 225 the range 1 .. 31 inclusive. Used for doing shift amounts. */ 226 static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e); 227 static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e); 228 229 /* compute an I8/I16/I32 into a GPR*/ 230 static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e); 231 static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e); 232 233 /* compute an I32 into an AMode. */ 234 static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e, 235 IRType xferTy); 236 static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy); 237 238 static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, 239 IRExpr * e); 240 static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e); 241 242 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */ 243 static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, 244 ISelEnv * env, IRExpr * e); 245 static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e); 246 247 static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e); 248 static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e); 249 250 static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e); 251 static HReg iselDblExpr(ISelEnv * env, IRExpr * e); 252 253 static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e); 254 static HReg iselFltExpr(ISelEnv * env, IRExpr * e); 255 256 static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode) 257 { 258 /* 259 rounding mode | MIPS | IR 260 ------------------------ 261 to nearest | 00 | 00 262 to zero | 01 | 11 263 to +infinity | 10 | 10 264 to -infinity | 11 | 01 265 */ 266 // rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 2 267 HReg irrm = iselWordExpr_R(env, mode); 268 HReg tmp = newVRegI(env); 269 HReg fcsr_old = newVRegI(env); 270 MIPSAMode *am_addr; 271 272 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm, 273 MIPSRH_Imm(False, 1))); 274 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp))); 275 addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, MIPSRH_Imm(False, 3))); 276 /* save old value of FCSR */ 277 addInstr(env, MIPSInstr_MfFCSR(fcsr_old)); 278 sub_from_sp(env, 8); // Move SP down 4 bytes 279 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 280 281 //store old FCSR to stack 282 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64)); 283 284 //set new value of FCSR 285 addInstr(env, MIPSInstr_MtFCSR(irrm)); 286 } 287 288 static void set_MIPS_rounding_default(ISelEnv * env) 289 { 290 HReg fcsr = newVRegI(env); 291 // load as float 292 MIPSAMode *am_addr; 293 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 294 295 addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64)); 296 297 add_to_sp(env, 8); // Reset SP 298 299 //set new value of FCSR 300 addInstr(env, MIPSInstr_MtFCSR(fcsr)); 301 } 302 303 /*---------------------------------------------------------*/ 304 /*--- ISEL: Misc helpers ---*/ 305 /*---------------------------------------------------------*/ 306 307 /* Make an int reg-reg move. */ 308 static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src) 309 { 310 vassert(hregClass(r_dst) == hregClass(r_src)); 311 vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64); 312 return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src)); 313 } 314 315 /*---------------------------------------------------------*/ 316 /*--- ISEL: Function call helpers ---*/ 317 /*---------------------------------------------------------*/ 318 319 /* Used only in doHelperCall. See big comment in doHelperCall re 320 handling of register-parameter args. This function figures out 321 whether evaluation of an expression might require use of a fixed 322 register. If in doubt return True (safe but suboptimal). 323 */ 324 static Bool mightRequireFixedRegs(IRExpr * e) 325 { 326 switch (e->tag) { 327 case Iex_RdTmp: 328 case Iex_Const: 329 case Iex_Get: 330 return False; 331 default: 332 return True; 333 } 334 } 335 336 /* Load 2*I32 regs to fp reg */ 337 static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo) 338 { 339 HReg fr_dst = newVRegD(env); 340 MIPSAMode *am_addr0, *am_addr1; 341 342 vassert(hregClass(r_srcHi) == HRcInt32); 343 vassert(hregClass(r_srcLo) == HRcInt32); 344 345 sub_from_sp(env, 16); // Move SP down 16 bytes 346 am_addr0 = MIPSAMode_IR(0, StackPointer(mode64)); 347 am_addr1 = MIPSAMode_IR(8, StackPointer(mode64)); 348 349 // store hi,lo as Ity_I32's 350 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64)); 351 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64)); 352 353 // load as float 354 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0)); 355 356 add_to_sp(env, 16); // Reset SP 357 return fr_dst; 358 } 359 360 /* Do a complete function call. guard is a Ity_Bit expression 361 indicating whether or not the call happens. If guard==NULL, the 362 call is unconditional. */ 363 364 static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard, 365 IRCallee * cee, IRExpr ** args) 366 { 367 MIPSCondCode cc; 368 HReg argregs[MIPS_N_REGPARMS]; 369 HReg tmpregs[MIPS_N_REGPARMS]; 370 Bool go_fast; 371 Int n_args, i, argreg; 372 UInt argiregs; 373 ULong target; 374 HReg src = 0; 375 376 /* MIPS O32 calling convention: up to four registers ($a0 ... $a3) 377 are allowed to be used for passing integer arguments. They correspond 378 to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless 379 on MIPS host (since we only implement one calling convention) and so we 380 always ignore it. */ 381 382 /* MIPS 64 calling convention: up to four registers ($a0 ... $a7) 383 are allowed to be used for passing integer arguments. They correspond 384 to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless 385 on MIPS host (since we only implement one calling convention) and so we 386 always ignore it. */ 387 n_args = 0; 388 for (i = 0; args[i]; i++) 389 n_args++; 390 391 if (MIPS_N_REGPARMS < n_args + (passBBP ? 1 : 0)) { 392 vpanic("doHelperCall(MIPS): cannot currently handle > 4 args"); 393 } 394 argregs[0] = hregMIPS_GPR4(mode64); 395 argregs[1] = hregMIPS_GPR5(mode64); 396 argregs[2] = hregMIPS_GPR6(mode64); 397 argregs[3] = hregMIPS_GPR7(mode64); 398 argiregs = 0; 399 400 tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG; 401 402 /* First decide which scheme (slow or fast) is to be used. First 403 assume the fast scheme, and select slow if any contraindications 404 (wow) appear. */ 405 406 go_fast = True; 407 408 if (guard) { 409 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1 410 && guard->Iex.Const.con->Ico.U1 == True) { 411 /* unconditional */ 412 } else { 413 /* Not manifestly unconditional -- be conservative. */ 414 go_fast = False; 415 } 416 } 417 418 if (go_fast) { 419 for (i = 0; i < n_args; i++) { 420 if (mightRequireFixedRegs(args[i])) { 421 go_fast = False; 422 break; 423 } 424 } 425 } 426 427 /* save GuestStatePointer on the stack */ 428 sub_from_sp(env, 8); // Move SP down 4 bytes 429 addInstr(env, MIPSInstr_Store(4, MIPSAMode_IR(0, StackPointer(mode64)), 430 GuestStatePointer(mode64), mode64)); 431 432 /* At this point the scheme to use has been established. Generate 433 code to get the arg values into the argument rregs. */ 434 if (go_fast) { 435 /* FAST SCHEME */ 436 argreg = 0; 437 if (passBBP) { 438 argiregs |= (1 << (argreg + 4)); 439 addInstr(env, mk_iMOVds_RR(argregs[argreg], 440 GuestStatePointer(mode64))); 441 argreg++; 442 } 443 444 for (i = 0; i < n_args; i++) { 445 vassert(argreg < MIPS_N_REGPARMS); 446 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 447 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64); 448 if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { 449 argiregs |= (1 << (argreg + 4)); 450 addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env, 451 args[i]))); 452 } else { // Ity_I64 453 vassert(mode64); 454 argiregs |= (1 << (argreg + 4)); 455 addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env, 456 args[i]))); 457 } 458 argreg++; 459 } 460 /* Fast scheme only applies for unconditional calls. Hence: */ 461 cc = MIPScc_AL; 462 } else { 463 /* SLOW SCHEME; move via temporaries */ 464 argreg = 0; 465 if (passBBP) { 466 /* This is pretty stupid; better to move directly to r3 467 after the rest of the args are done. */ 468 tmpregs[argreg] = newVRegI(env); 469 addInstr(env, mk_iMOVds_RR(tmpregs[argreg], 470 GuestStatePointer(mode64))); 471 argreg++; 472 } 473 for (i = 0; i < n_args; i++) { 474 vassert(argreg < MIPS_N_REGPARMS); 475 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 476 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64); 477 if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { 478 tmpregs[argreg] = iselWordExpr_R(env, args[i]); 479 } else { // Ity_I64 480 vassert(mode64); 481 tmpregs[argreg] = iselWordExpr_R(env, args[i]); 482 } 483 argreg++; 484 } 485 486 /* Now we can compute the condition. We can't do it earlier 487 because the argument computations could trash the condition 488 codes. Be a bit clever to handle the common case where the 489 guard is 1:Bit. */ 490 cc = MIPScc_AL; 491 if (guard) { 492 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1 493 && guard->Iex.Const.con->Ico.U1 == True) { 494 /* unconditional -- do nothing */ 495 } else { 496 cc = iselCondCode(env, guard); 497 src = iselWordExpr_R(env, guard); 498 } 499 } 500 /* Move the args to their final destinations. */ 501 for (i = 0; i < argreg; i++) { 502 if (tmpregs[i] == INVALID_HREG) // Skip invalid regs 503 continue; 504 /* None of these insns, including any spill code that might 505 be generated, may alter the condition codes. */ 506 argiregs |= (1 << (i + 4)); 507 addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i])); 508 } 509 } 510 511 target = toUInt(Ptr_to_ULong(cee->addr)); 512 513 /* Finally, the call itself. */ 514 if (mode64) 515 if (cc == MIPScc_AL) { 516 addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs)); 517 } else { 518 addInstr(env, MIPSInstr_Call(cc, target, argiregs, src)); 519 } else if (cc == MIPScc_AL) { 520 addInstr(env, MIPSInstr_CallAlways(cc, (Addr32) target, argiregs)); 521 } else { 522 addInstr(env, MIPSInstr_Call(cc, (Addr32) target, argiregs, src)); 523 } 524 /* restore GuestStatePointer */ 525 addInstr(env, MIPSInstr_Load(4, GuestStatePointer(mode64), 526 MIPSAMode_IR(0, StackPointer(mode64)), mode64)); 527 add_to_sp(env, 8); // Reset SP 528 } 529 530 /*---------------------------------------------------------*/ 531 /*--- ISEL: Integer expression auxiliaries ---*/ 532 /*---------------------------------------------------------*/ 533 534 /* --------------------- AMODEs --------------------- */ 535 536 /* Return an AMode which computes the value of the specified 537 expression, possibly also adding insns to the code list as a 538 result. The expression may only be a word-size one. 539 */ 540 541 static Bool uInt_fits_in_16_bits(UInt u) 542 { 543 Int i = u & 0xFFFF; 544 i <<= 16; 545 i >>= 16; 546 return toBool(u == (UInt) i); 547 } 548 549 static Bool sane_AMode(ISelEnv * env, MIPSAMode * am) 550 { 551 switch (am->tag) { 552 case Mam_IR: 553 return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) && 554 hregIsVirtual(am->Mam.IR.base) && 555 uInt_fits_in_16_bits(am->Mam.IR.index)); 556 case Mam_RR: 557 return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) && 558 hregIsVirtual(am->Mam.RR.base) && 559 hregClass(am->Mam.RR.index) == HRcGPR(mode64) && 560 hregIsVirtual(am->Mam.IR.index)); 561 default: 562 vpanic("sane_AMode: unknown mips amode tag"); 563 } 564 } 565 566 static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy) 567 { 568 MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy); 569 vassert(sane_AMode(env, am)); 570 return am; 571 } 572 573 /* DO NOT CALL THIS DIRECTLY ! */ 574 static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e, 575 IRType xferTy) 576 { 577 IRType ty = typeOfIRExpr(env->type_env, e); 578 { 579 vassert(ty == Ity_I32); 580 581 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */ 582 if (e->tag == Iex_Binop 583 && e->Iex.Binop.op == Iop_Add32 584 && e->Iex.Binop.arg2->tag == Iex_Const 585 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32 586 && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) { 587 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, 588 iselWordExpr_R(env, e->Iex.Binop.arg1)); 589 } 590 591 /* Add32(expr,expr) */ 592 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) { 593 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1); 594 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2); 595 596 return MIPSAMode_RR(r_idx, r_base); 597 } 598 } 599 600 /* Doesn't match anything in particular. Generate it into 601 a register and use that. */ 602 return MIPSAMode_IR(0, iselWordExpr_R(env, e)); 603 } 604 605 /*---------------------------------------------------------*/ 606 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/ 607 /*---------------------------------------------------------*/ 608 609 /* Select insns for an integer-typed expression, and add them to the 610 code list. Return a reg holding the result. This reg will be a 611 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you 612 want to modify it, ask for a new vreg, copy it in there, and modify 613 the copy. The register allocator will do its best to map both 614 vregs to the same real register, so the copies will often disappear 615 later in the game. 616 617 This should handle expressions of 64, 32, 16 and 8-bit type. 618 All results are returned in a (mode64 ? 64bit : 32bit) register. 619 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits 620 are arbitrary, so you should mask or sign extend partial values 621 if necessary. 622 */ 623 static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e) 624 { 625 HReg r = iselWordExpr_R_wrk(env, e); 626 /* sanity checks ... */ 627 628 vassert(hregClass(r) == HRcGPR(env->mode64)); 629 vassert(hregIsVirtual(r)); 630 return r; 631 } 632 633 /* DO NOT CALL THIS DIRECTLY ! */ 634 static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) 635 { 636 IRType ty = typeOfIRExpr(env->type_env, e); 637 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1 638 || ty == Ity_F32 || (ty == Ity_I64 && mode64) 639 || (ty == Ity_I128 && mode64)); 640 641 switch (e->tag) { 642 /* --------- TEMP --------- */ 643 case Iex_RdTmp: 644 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 645 646 /* --------- LOAD --------- */ 647 case Iex_Load: { 648 HReg r_dst = newVRegI(env); 649 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty); 650 651 if (e->Iex.Load.end != Iend_LE 652 && e->Iex.Load.end != Iend_BE) 653 goto irreducible; 654 655 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), 656 r_dst, am_addr, mode64)); 657 return r_dst; 658 } 659 660 /* --------- BINARY OP --------- */ 661 case Iex_Binop: { 662 MIPSAluOp aluOp; 663 MIPSShftOp shftOp; 664 665 /* Is it an addition or logical style op? */ 666 switch (e->Iex.Binop.op) { 667 case Iop_Add32: 668 aluOp = Malu_ADD; 669 break; 670 671 case Iop_Sub8: 672 case Iop_Sub16: 673 case Iop_Sub32: 674 aluOp = Malu_SUB; 675 break; 676 677 case Iop_And32: 678 case Iop_And64: 679 aluOp = Malu_AND; 680 break; 681 682 case Iop_Or32: 683 case Iop_Or64: 684 aluOp = Malu_OR; 685 break; 686 687 case Iop_Xor32: 688 case Iop_Xor64: 689 aluOp = Malu_XOR; 690 break; 691 692 default: 693 aluOp = Malu_INVALID; 694 break; 695 } 696 697 /* For commutative ops we assume any literal 698 values are on the second operand. */ 699 if (aluOp != Malu_INVALID) { 700 HReg r_dst = newVRegI(env); 701 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 702 MIPSRH *ri_srcR = NULL; 703 /* get right arg into an RH, in the appropriate way */ 704 switch (aluOp) { 705 case Malu_ADD: 706 case Malu_SUB: 707 ri_srcR = iselWordExpr_RH(env, True /*signed */ , 708 e->Iex.Binop.arg2); 709 break; 710 case Malu_AND: 711 case Malu_OR: 712 case Malu_XOR: 713 ri_srcR = iselWordExpr_RH(env, False /*unsigned */, 714 e->Iex.Binop.arg2); 715 break; 716 default: 717 vpanic("iselWordExpr_R_wrk-aluOp-arg2"); 718 } 719 addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR)); 720 return r_dst; 721 } 722 723 /* a shift? */ 724 switch (e->Iex.Binop.op) { 725 case Iop_Shl32: 726 case Iop_Shl64: 727 shftOp = Mshft_SLL; 728 break; 729 case Iop_Shr32: 730 case Iop_Shr64: 731 shftOp = Mshft_SRL; 732 break; 733 case Iop_Sar32: 734 case Iop_Sar64: 735 shftOp = Mshft_SRA; 736 break; 737 default: 738 shftOp = Mshft_INVALID; 739 break; 740 } 741 742 /* we assume any literal values are on the second operand. */ 743 if (shftOp != Mshft_INVALID) { 744 HReg r_dst = newVRegI(env); 745 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 746 MIPSRH *ri_srcR = NULL; 747 /* get right arg into an RH, in the appropriate way */ 748 switch (shftOp) { 749 case Mshft_SLL: 750 case Mshft_SRL: 751 case Mshft_SRA: 752 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop. arg2); 753 break; 754 default: 755 vpanic("iselIntExpr_R_wrk-shftOp-arg2"); 756 } 757 /* widen the left arg if needed */ 758 /*TODO do we need this? */ 759 if (ty == Ity_I8 || ty == Ity_I16) 760 goto irreducible; 761 if (ty == Ity_I64) { 762 vassert(mode64); 763 addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */, 764 r_dst, r_srcL, ri_srcR)); 765 } else { 766 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */, 767 r_dst, r_srcL, ri_srcR)); 768 } 769 return r_dst; 770 } 771 772 /* Cmp*32*(x,y) ? */ 773 if (e->Iex.Binop.op == Iop_CmpEQ32 774 || e->Iex.Binop.op == Iop_CmpNE32 775 || e->Iex.Binop.op == Iop_CmpNE64 776 || e->Iex.Binop.op == Iop_CmpLT32S 777 || e->Iex.Binop.op == Iop_CmpLT32U 778 || e->Iex.Binop.op == Iop_CmpLT64U 779 || e->Iex.Binop.op == Iop_CmpLE32S 780 || e->Iex.Binop.op == Iop_CmpLE64S 781 || e->Iex.Binop.op == Iop_CmpLT64S 782 || e->Iex.Binop.op == Iop_CmpEQ64) { 783 784 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S 785 || e->Iex.Binop.op == Iop_CmpLE32S 786 || e->Iex.Binop.op == Iop_CmpLT64S 787 || e->Iex.Binop.op == Iop_CmpLE64S); 788 Bool size32; 789 HReg dst = newVRegI(env); 790 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 791 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2); 792 793 MIPSCondCode cc; 794 795 switch (e->Iex.Binop.op) { 796 case Iop_CmpEQ32: 797 cc = MIPScc_EQ; 798 size32 = True; 799 break; 800 case Iop_CmpNE32: 801 cc = MIPScc_NE; 802 size32 = True; 803 break; 804 case Iop_CmpNE64: 805 cc = MIPScc_NE; 806 size32 = True; 807 break; 808 case Iop_CmpLT32S: 809 cc = MIPScc_LT; 810 size32 = True; 811 break; 812 case Iop_CmpLT32U: 813 cc = MIPScc_LO; 814 size32 = True; 815 break; 816 case Iop_CmpLT64U: 817 cc = MIPScc_LO; 818 size32 = False; 819 break; 820 case Iop_CmpLE32S: 821 cc = MIPScc_LE; 822 size32 = True; 823 break; 824 case Iop_CmpLE64S: 825 cc = MIPScc_LE; 826 size32 = False; 827 break; 828 case Iop_CmpLT64S: 829 cc = MIPScc_LT; 830 size32 = False; 831 break; 832 case Iop_CmpEQ64: 833 cc = MIPScc_EQ; 834 size32 = False; 835 break; 836 default: 837 vpanic 838 ("iselCondCode(mips): CmpXX32 or CmpXX64"); 839 } 840 841 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc)); 842 return dst; 843 } 844 845 if (e->Iex.Binop.op == Iop_Max32U) { 846 /* 847 tmp = argR - argL; 848 dst = argL; 849 bltz tmp,2; 850 dst = argR; 851 852 */ 853 HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1); 854 MIPSRH *argR = iselWordExpr_RH(env, False /*signed */ , 855 e->Iex.Binop.arg2); 856 HReg dst = newVRegI(env); 857 HReg tmp = newVRegI(env); 858 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, argL, argR)); 859 addInstr(env, MIPSInstr_MovCond(dst, argL, argR, tmp, MIPScc_MI)); 860 861 return dst; 862 } 863 864 if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) { 865 Bool sz32 = (e->Iex.Binop.op == Iop_Mul32); 866 HReg r_dst = newVRegI(env); 867 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 868 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 869 addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ , 870 False /*widen */ , 871 sz32 /*32bit or 64bit */, 872 r_dst, r_srcL, r_srcR)); 873 return r_dst; 874 } 875 876 if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) { 877 HReg r_dst = newVRegI(env); 878 HReg tHi = newVRegI(env); 879 HReg tLo = newVRegI(env); 880 HReg tLo_1 = newVRegI(env); 881 HReg tHi_1 = newVRegI(env); 882 HReg mask = newVRegI(env); 883 884 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32); 885 Bool size = toBool(e->Iex.Binop.op == Iop_MullS32) 886 || toBool(e->Iex.Binop.op == Iop_MullU32); 887 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 888 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 889 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ , 890 True /*widen */ , 891 size /*32bit or 64bit mul */ , 892 r_dst, r_srcL, r_srcR)); 893 894 addInstr(env, MIPSInstr_Mfhi(tHi)); 895 addInstr(env, MIPSInstr_Mflo(tLo)); 896 897 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, 898 tHi, MIPSRH_Imm(False, 32))); 899 900 addInstr(env, MIPSInstr_LI(mask, 0xffffffff)); 901 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 902 MIPSRH_Reg(mask))); 903 904 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 905 MIPSRH_Reg(tLo_1))); 906 907 return r_dst; 908 } 909 910 if (e->Iex.Binop.op == Iop_CmpF64) { 911 HReg r_srcL, r_srcR; 912 { 913 r_srcL = iselDblExpr(env, e->Iex.Binop.arg1); 914 r_srcR = iselDblExpr(env, e->Iex.Binop.arg2); 915 } 916 HReg tmp = newVRegI(env); 917 HReg r_ccMIPS = newVRegI(env); 918 HReg r_ccIR = newVRegI(env); 919 HReg r_ccIR_b0 = newVRegI(env); 920 HReg r_ccIR_b2 = newVRegI(env); 921 HReg r_ccIR_b6 = newVRegI(env); 922 923 /* Create in dst, the IRCmpF64Result encoded result. */ 924 // chech for EQ 925 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR, 926 toUChar(2))); 927 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_ccMIPS, tmp, 928 MIPSRH_Imm(False, 22))); 929 // chech for UN 930 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR, 931 toUChar(1))); 932 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp, 933 MIPSRH_Imm(False, 23))); 934 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS, 935 MIPSRH_Reg(tmp))); 936 // chech for LT 937 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR, 938 toUChar(12))); 939 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, 940 tmp, MIPSRH_Imm(False, 21))); 941 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS, 942 MIPSRH_Reg(tmp))); 943 // chech for GT 944 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR, 945 toUChar(15))); 946 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp, 947 MIPSRH_Imm(False, 20))); 948 949 addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp))); 950 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, 951 MIPSRH_Imm(False, 8))); 952 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS, 953 MIPSRH_Reg(tmp))); 954 /* Map compare result from PPC to IR, 955 conforming to CmpF64 definition. */ 956 /* 957 FP cmp result | MIPS | IR 958 -------------------------- 959 UN | 0x1 | 0x45 960 EQ | 0x2 | 0x40 961 GT | 0x4 | 0x00 962 LT | 0x8 | 0x01 963 */ 964 965 // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3] 966 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS, 967 MIPSRH_Imm(False, 0x3))); 968 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS, 969 MIPSRH_Reg(r_ccIR_b0))); 970 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0, 971 MIPSRH_Imm(False, 0x1))); 972 973 // r_ccIR_b2 = r_ccPPC[0] 974 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS, 975 MIPSRH_Imm(False, 0x2))); 976 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2, 977 MIPSRH_Imm(False, 0x4))); 978 979 // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1] 980 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6, 981 r_ccMIPS, MIPSRH_Imm(False, 0x1))); 982 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS, 983 MIPSRH_Reg(r_ccIR_b6))); 984 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6, 985 MIPSRH_Imm(False, 0x6))); 986 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6, 987 MIPSRH_Imm(False, 0x40))); 988 989 // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 990 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0, 991 MIPSRH_Reg(r_ccIR_b2))); 992 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR, 993 MIPSRH_Reg(r_ccIR_b6))); 994 return r_ccIR; 995 } 996 997 if (e->Iex.Binop.op == Iop_DivModU64to32 || 998 e->Iex.Binop.op == Iop_DivModS64to32) { 999 HReg tLo = newVRegI(env); 1000 HReg tHi = newVRegI(env); 1001 HReg mask = newVRegI(env); 1002 HReg tLo_1 = newVRegI(env); 1003 HReg tHi_1 = newVRegI(env); 1004 HReg r_dst = newVRegI(env); 1005 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32); 1006 1007 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1008 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1009 1010 addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR)); 1011 addInstr(env, MIPSInstr_Mfhi(tHi)); 1012 addInstr(env, MIPSInstr_Mflo(tLo)); 1013 1014 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi, 1015 MIPSRH_Imm(False, 32))); 1016 1017 addInstr(env, MIPSInstr_LI(mask, 0xffffffff)); 1018 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 1019 MIPSRH_Reg(mask))); 1020 1021 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 1022 MIPSRH_Reg(tLo_1))); 1023 1024 return r_dst; 1025 } 1026 1027 if (e->Iex.Binop.op == Iop_32HLto64) { 1028 vassert(mode64); 1029 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 1030 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 1031 HReg tLo_1 = newVRegI(env); 1032 HReg tHi_1 = newVRegI(env); 1033 HReg r_dst = newVRegI(env); 1034 HReg mask = newVRegI(env); 1035 1036 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi, 1037 MIPSRH_Imm(False, 32))); 1038 1039 addInstr(env, MIPSInstr_LI(mask, 0xffffffff)); 1040 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 1041 MIPSRH_Reg(mask))); 1042 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 1043 MIPSRH_Reg(tLo_1))); 1044 1045 return r_dst; 1046 } 1047 1048 if (e->Iex.Binop.op == Iop_F64toI32S) { 1049 HReg valD = iselDblExpr(env, e->Iex.Binop.arg2); 1050 HReg valS = newVRegF(env); 1051 HReg r_dst = newVRegI(env); 1052 MIPSAMode *am_addr; 1053 1054 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 1055 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD)); 1056 set_MIPS_rounding_default(env); 1057 1058 sub_from_sp(env, 16); // Move SP down 16 bytes 1059 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 1060 1061 // store as F32 1062 addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 4, valS, am_addr)); 1063 // load as I32 1064 addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64)); 1065 1066 add_to_sp(env, 16); // Reset SP 1067 1068 return r_dst; 1069 } 1070 1071 break; 1072 } 1073 1074 /* --------- UNARY OP --------- */ 1075 case Iex_Unop: { 1076 IROp op_unop = e->Iex.Unop.op; 1077 1078 switch (op_unop) { 1079 case Iop_1Sto32: 1080 case Iop_8Sto32: 1081 case Iop_16Sto32: 1082 case Iop_16Sto64: 1083 case Iop_8Sto64: 1084 case Iop_1Sto64: { 1085 HReg r_dst = newVRegI(env); 1086 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1087 Bool sz32; 1088 UShort amt; 1089 switch (op_unop) { 1090 case Iop_1Sto32: 1091 amt = 31; 1092 sz32 = True; 1093 break; 1094 case Iop_16Sto32: 1095 amt = 16; 1096 sz32 = True; 1097 break; 1098 case Iop_16Sto64: 1099 amt = 48; 1100 sz32 = False; 1101 break; 1102 case Iop_8Sto32: 1103 amt = 24; 1104 sz32 = True; 1105 break; 1106 case Iop_8Sto64: 1107 amt = 56; 1108 sz32 = False; 1109 break; 1110 case Iop_1Sto64: 1111 amt = 63; 1112 sz32 = False; 1113 break; 1114 default: 1115 vassert(0); 1116 } 1117 1118 addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src, 1119 MIPSRH_Imm(False, amt))); 1120 addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst, 1121 MIPSRH_Imm(False, amt))); 1122 return r_dst; 1123 } 1124 1125 /*not(x) = nor(x,x) */ 1126 case Iop_Not1: { 1127 HReg r_dst = newVRegI(env); 1128 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg); 1129 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL); 1130 1131 addInstr(env, MIPSInstr_LI(r_dst, 0x1)); 1132 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR)); 1133 return r_dst; 1134 } 1135 1136 case Iop_Not32: 1137 case Iop_Not64: { 1138 HReg r_dst = newVRegI(env); 1139 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg); 1140 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL); 1141 1142 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR)); 1143 return r_dst; 1144 } 1145 1146 case Iop_ReinterpF32asI32: { 1147 MIPSAMode *am_addr; 1148 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg); 1149 HReg r_dst = newVRegI(env); 1150 1151 sub_from_sp(env, 16); // Move SP down 16 bytes 1152 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 1153 1154 // store as F32 1155 addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 4, fr_src, 1156 am_addr)); 1157 // load as Ity_I32 1158 addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64)); 1159 1160 add_to_sp(env, 16); // Reset SP 1161 return r_dst; 1162 } 1163 1164 case Iop_ReinterpF64asI64: { 1165 vassert(mode64); 1166 MIPSAMode *am_addr; 1167 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg); 1168 HReg r_dst = newVRegI(env); 1169 1170 sub_from_sp(env, 16); // Move SP down 16 bytes 1171 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 1172 1173 // store as F64 1174 addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 8, fr_src, 1175 am_addr)); 1176 // load as Ity_I64 1177 addInstr(env, MIPSInstr_Load(8, r_dst, am_addr, mode64)); 1178 1179 add_to_sp(env, 16); // Reset SP 1180 return r_dst; 1181 } 1182 1183 case Iop_32to8: 1184 case Iop_32to16: 1185 return iselWordExpr_R(env, e->Iex.Unop.arg); 1186 1187 case Iop_64to8: { 1188 vassert(mode64); 1189 HReg r_src, r_dst; 1190 r_dst = newVRegI(env); 1191 r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1192 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src, 1193 MIPSRH_Imm(False, 0xFF))); 1194 return r_dst; 1195 } 1196 1197 case Iop_16Uto32: 1198 case Iop_8Uto32: 1199 case Iop_1Uto32: { 1200 HReg r_dst = newVRegI(env); 1201 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1202 UShort amt; 1203 switch (op_unop) { 1204 case Iop_1Uto32: 1205 case Iop_1Uto8: 1206 amt = 31; 1207 break; 1208 1209 case Iop_16Uto32: 1210 amt = 16; 1211 break; 1212 1213 default: 1214 amt = 24; 1215 break; 1216 } 1217 1218 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_dst, r_src, 1219 MIPSRH_Imm(False, amt))); 1220 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_dst, r_dst, 1221 MIPSRH_Imm(False, amt))); 1222 return r_dst; 1223 } 1224 1225 case Iop_8Uto16: 1226 case Iop_8Uto64: 1227 case Iop_16Uto64: { 1228 vassert(mode64); 1229 HReg r_dst = newVRegI(env); 1230 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1231 UShort mask = toUShort(op_unop == Iop_16Uto64 ? 0xFFFF : 1232 op_unop == Iop_16Uto32 ? 0xFFFF : 0xFF); 1233 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src, 1234 MIPSRH_Imm(False, mask))); 1235 return r_dst; 1236 } 1237 1238 case Iop_32Uto64: { 1239 HReg r_dst = newVRegI(env); 1240 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1241 vassert(mode64); 1242 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False/*!32bit shift */, 1243 r_dst, r_src, MIPSRH_Imm(False, 32))); 1244 addInstr(env, MIPSInstr_Shft(Mshft_SRL, False/*!32bit shift */, 1245 r_dst, r_dst, MIPSRH_Imm(False, 32))); 1246 return r_dst; 1247 } 1248 1249 case Iop_1Uto64: 1250 vassert(mode64); 1251 return iselWordExpr_R(env, e->Iex.Unop.arg); 1252 1253 case Iop_64HIto32: { 1254 HReg rHi, rLo; 1255 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1256 return rHi; 1257 } 1258 1259 case Iop_64to32: { 1260 HReg rHi, rLo; 1261 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1262 return rLo; 1263 } 1264 1265 case Iop_64to16: { 1266 vassert(env->mode64); 1267 HReg r_dst = newVRegI(env); 1268 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg); 1269 return r_dst; 1270 } 1271 1272 case Iop_32Sto64: { 1273 HReg r_dst = newVRegI(env); 1274 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1275 vassert(mode64); 1276 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True/*!32bit shift */, 1277 r_dst, r_src, MIPSRH_Imm(True, 0))); 1278 return r_dst; 1279 } 1280 1281 case Iop_CmpNEZ8: { 1282 HReg r_dst = newVRegI(env); 1283 HReg tmp = newVRegI(env); 1284 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1285 1286 MIPSCondCode cc; 1287 1288 cc = MIPScc_NE; 1289 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src, 1290 MIPSRH_Imm(False, 0xFF))); 1291 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp, 1292 hregMIPS_GPR0(mode64), cc)); 1293 return r_dst; 1294 } 1295 1296 case Iop_CmpNEZ32: { 1297 HReg r_dst = newVRegI(env); 1298 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1299 1300 MIPSCondCode cc; 1301 1302 cc = MIPScc_NE; 1303 1304 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src, 1305 hregMIPS_GPR0(mode64), cc)); 1306 return r_dst; 1307 } 1308 1309 case Iop_CmpwNEZ32: { 1310 HReg r_dst = newVRegI(env); 1311 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1312 1313 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64), 1314 MIPSRH_Reg(r_src))); 1315 1316 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst, 1317 MIPSRH_Reg(r_src))); 1318 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst, 1319 MIPSRH_Imm(False, 31))); 1320 return r_dst; 1321 } 1322 1323 case Iop_Left8: 1324 case Iop_Left32: 1325 case Iop_Left64: { 1326 if (op_unop == Iop_Left64 && !mode64) 1327 goto irreducible; 1328 HReg r_dst = newVRegI(env); 1329 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1330 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64), 1331 MIPSRH_Reg(r_src))); 1332 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst, 1333 MIPSRH_Reg(r_src))); 1334 return r_dst; 1335 } 1336 1337 case Iop_Clz32: { 1338 HReg r_dst = newVRegI(env); 1339 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1340 addInstr(env, MIPSInstr_Unary(Mun_CLZ, r_dst, r_src)); 1341 return r_dst; 1342 } 1343 1344 case Iop_CmpNEZ64: { 1345 HReg hi, lo; 1346 HReg r_dst = newVRegI(env); 1347 HReg r_src; 1348 r_src = newVRegI(env); 1349 iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg); 1350 addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi))); 1351 MIPSCondCode cc; 1352 1353 cc = MIPScc_NE; 1354 1355 addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src, 1356 hregMIPS_GPR0(mode64), cc)); 1357 return r_dst; 1358 } 1359 1360 case Iop_CmpwNEZ64: { 1361 HReg tmp1; 1362 HReg tmp2 = newVRegI(env); 1363 vassert(env->mode64); 1364 tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg); 1365 1366 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64), 1367 MIPSRH_Reg(tmp1))); 1368 1369 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1))); 1370 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2, 1371 MIPSRH_Imm (False, 63))); 1372 return tmp2; 1373 } 1374 1375 case Iop_128HIto64: { 1376 vassert(mode64); 1377 HReg rHi, rLo; 1378 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1379 return rHi; /* and abandon rLo .. poor wee thing :-) */ 1380 } 1381 1382 case Iop_128to64: { 1383 vassert(mode64); 1384 HReg rHi, rLo; 1385 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1386 return rLo; /* and abandon rLo .. poor wee thing :-) */ 1387 } 1388 1389 default: 1390 break; 1391 } 1392 break; 1393 } 1394 1395 /* --------- GET --------- */ 1396 case Iex_Get: { 1397 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 1398 || ((ty == Ity_I64) && mode64)) { 1399 HReg r_dst = newVRegI(env); 1400 1401 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 1402 GuestStatePointer(mode64)); 1403 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr, 1404 mode64)); 1405 return r_dst; 1406 } 1407 break; 1408 } 1409 1410 /* --------- MULTIPLEX --------- */ 1411 case Iex_Mux0X: { 1412 if ((ty == Ity_I8 || ty == Ity_I16 || 1413 ty == Ity_I32 || ((ty == Ity_I64))) && 1414 typeOfIRExpr(env->type_env, e->Iex.Mux0X.cond) == Ity_I8) { 1415 /* 1416 * r_dst = cond && rX 1417 * cond = not(cond) 1418 * tmp = cond && r0 1419 * r_dst = tmp + r_dst 1420 */ 1421 HReg r0 = iselWordExpr_R(env, e->Iex.Mux0X.expr0); 1422 HReg rX = iselWordExpr_R(env, e->Iex.Mux0X.exprX); 1423 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond); 1424 HReg r_dst = newVRegI(env); 1425 HReg r_tmp = newVRegI(env); 1426 HReg r_tmp1 = newVRegI(env); 1427 HReg r_cond_neg = newVRegI(env); 1428 1429 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp, r_cond, MIPSRH_Reg(rX))); 1430 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond, 1431 MIPSRH_Reg(r_cond))); 1432 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1, r_cond_neg, 1433 MIPSRH_Reg(r0))); 1434 addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst, r_tmp, 1435 MIPSRH_Reg(r_tmp1))); 1436 1437 return r_dst; 1438 } 1439 break; 1440 } 1441 1442 /* --------- LITERAL --------- */ 1443 /* 32/16/8-bit literals */ 1444 case Iex_Const: { 1445 Long l; 1446 HReg r_dst = newVRegI(env); 1447 IRConst *con = e->Iex.Const.con; 1448 switch (con->tag) { 1449 case Ico_U64: 1450 if (!mode64) 1451 goto irreducible; 1452 l = (Long) con->Ico.U64; 1453 break; 1454 case Ico_U32: 1455 l = (Long) (Int) con->Ico.U32; 1456 break; 1457 case Ico_U16: 1458 l = (Long) (Int) (Short) con->Ico.U16; 1459 break; 1460 case Ico_U8: 1461 l = (Long) (Int) (Char) con->Ico.U8; 1462 break; 1463 default: 1464 vpanic("iselIntExpr_R.const(mips)"); 1465 } 1466 addInstr(env, MIPSInstr_LI(r_dst, (ULong) l)); 1467 return r_dst; 1468 } 1469 1470 /* --------- CCALL --------- */ 1471 case Iex_CCall: { 1472 HReg r_dst = newVRegI(env); 1473 vassert(ty == e->Iex.CCall.retty); 1474 1475 /* be very restrictive for now. Only 32/64-bit ints allowed 1476 for args, and 32 bits for return type. */ 1477 if (e->Iex.CCall.retty != Ity_I32 && !mode64) 1478 goto irreducible; 1479 1480 /* Marshal args, do the call, clear stack. */ 1481 doHelperCall(env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args); 1482 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64))); 1483 return r_dst; 1484 } 1485 1486 default: 1487 break; 1488 } /* end switch(e->tag) */ 1489 1490 /* We get here if no pattern matched. */ 1491 irreducible: 1492 vex_printf("--------------->\n"); 1493 if (e->tag == Iex_RdTmp) 1494 vex_printf("Iex_RdTmp \n"); 1495 ppIRExpr(e); 1496 1497 vpanic("iselWordExpr_R(mips): cannot reduce tree"); 1498 } 1499 1500 /* --------------------- RH --------------------- */ 1501 1502 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH 1503 (reg-or-halfword-immediate). It's important to specify whether the 1504 immediate is to be regarded as signed or not. If yes, this will 1505 never return -32768 as an immediate; this guaranteed that all 1506 signed immediates that are return can have their sign inverted if 1507 need be. */ 1508 1509 static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e) 1510 { 1511 MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e); 1512 /* sanity checks ... */ 1513 switch (ri->tag) { 1514 case Mrh_Imm: 1515 vassert(ri->Mrh.Imm.syned == syned); 1516 if (syned) 1517 vassert(ri->Mrh.Imm.imm16 != 0x8000); 1518 return ri; 1519 case Mrh_Reg: 1520 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64)); 1521 vassert(hregIsVirtual(ri->Mrh.Reg.reg)); 1522 return ri; 1523 default: 1524 vpanic("iselIntExpr_RH: unknown mips RH tag"); 1525 } 1526 } 1527 1528 /* DO NOT CALL THIS DIRECTLY ! */ 1529 static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e) 1530 { 1531 ULong u; 1532 Long l; 1533 IRType ty = typeOfIRExpr(env->type_env, e); 1534 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || 1535 ((ty == Ity_I64) && env->mode64)); 1536 1537 /* special case: immediate */ 1538 if (e->tag == Iex_Const) { 1539 IRConst *con = e->Iex.Const.con; 1540 /* What value are we aiming to generate? */ 1541 switch (con->tag) { 1542 /* Note: Not sign-extending - we carry 'syned' around */ 1543 case Ico_U64: 1544 vassert(env->mode64); 1545 u = con->Ico.U64; 1546 break; 1547 case Ico_U32: 1548 u = 0xFFFFFFFF & con->Ico.U32; 1549 break; 1550 case Ico_U16: 1551 u = 0x0000FFFF & con->Ico.U16; 1552 break; 1553 case Ico_U8: 1554 u = 0x000000FF & con->Ico.U8; 1555 break; 1556 default: 1557 vpanic("iselIntExpr_RH.Iex_Const(mips)"); 1558 } 1559 l = (Long) u; 1560 /* Now figure out if it's representable. */ 1561 if (!syned && u <= 65535) { 1562 return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF)); 1563 } 1564 if (syned && l >= -32767 && l <= 32767) { 1565 return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF)); 1566 } 1567 /* no luck; use the Slow Way. */ 1568 } 1569 /* default case: calculate into a register and return that */ 1570 return MIPSRH_Reg(iselWordExpr_R(env, e)); 1571 } 1572 1573 /* --------------------- RH5u --------------------- */ 1574 1575 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter 1576 being an immediate in the range 1 .. 31 inclusive. Used for doing 1577 shift amounts. */ 1578 1579 static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e) 1580 { 1581 MIPSRH *ri; 1582 ri = iselWordExpr_RH5u_wrk(env, e); 1583 /* sanity checks ... */ 1584 switch (ri->tag) { 1585 case Mrh_Imm: 1586 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31); 1587 vassert(!ri->Mrh.Imm.syned); 1588 return ri; 1589 case Mrh_Reg: 1590 vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32); 1591 vassert(hregIsVirtual(ri->Mrh.Reg.reg)); 1592 return ri; 1593 default: 1594 vpanic("iselIntExpr_RH5u: unknown mips RH tag"); 1595 } 1596 } 1597 1598 /* DO NOT CALL THIS DIRECTLY ! */ 1599 static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e) 1600 { 1601 IRType ty = typeOfIRExpr(env->type_env, e); 1602 vassert(ty == Ity_I8); 1603 1604 /* special case: immediate */ 1605 if (e->tag == Iex_Const 1606 && e->Iex.Const.con->tag == Ico_U8 1607 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) { 1608 return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8); 1609 } 1610 1611 /* default case: calculate into a register and return that */ 1612 return MIPSRH_Reg(iselWordExpr_R(env, e)); 1613 } 1614 1615 /* --------------------- CONDCODE --------------------- */ 1616 1617 /* Generate code to evaluated a bit-typed expression, returning the 1618 condition code which would correspond when the expression would 1619 notionally have returned 1. */ 1620 1621 static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e) 1622 { 1623 MIPSCondCode cc = iselCondCode_wrk(env,e); 1624 vassert(cc != MIPScc_NV); 1625 return cc; 1626 } 1627 1628 /* DO NOT CALL THIS DIRECTLY ! */ 1629 static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e) 1630 { 1631 vassert(e); 1632 vassert(typeOfIRExpr(env->type_env, e) == Ity_I1); 1633 /* Cmp*32*(x,y) ? */ 1634 if (e->Iex.Binop.op == Iop_CmpEQ32 1635 || e->Iex.Binop.op == Iop_CmpNE32 1636 || e->Iex.Binop.op == Iop_CmpNE64 1637 || e->Iex.Binop.op == Iop_CmpLT32S 1638 || e->Iex.Binop.op == Iop_CmpLT32U 1639 || e->Iex.Binop.op == Iop_CmpLT64U 1640 || e->Iex.Binop.op == Iop_CmpLE32S 1641 || e->Iex.Binop.op == Iop_CmpLE64S 1642 || e->Iex.Binop.op == Iop_CmpLT64S 1643 || e->Iex.Binop.op == Iop_CmpEQ64) { 1644 1645 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S 1646 || e->Iex.Binop.op == Iop_CmpLE32S 1647 || e->Iex.Binop.op == Iop_CmpLT64S 1648 || e->Iex.Binop.op == Iop_CmpLE64S); 1649 Bool size32; 1650 HReg dst = newVRegI(env); 1651 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 1652 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2); 1653 1654 MIPSCondCode cc; 1655 1656 switch (e->Iex.Binop.op) { 1657 case Iop_CmpEQ32: 1658 cc = MIPScc_EQ; 1659 size32 = True; 1660 break; 1661 case Iop_CmpNE32: 1662 cc = MIPScc_NE; 1663 size32 = True; 1664 break; 1665 case Iop_CmpNE64: 1666 cc = MIPScc_NE; 1667 size32 = True; 1668 break; 1669 case Iop_CmpLT32S: 1670 cc = MIPScc_LT; 1671 size32 = True; 1672 break; 1673 case Iop_CmpLT32U: 1674 cc = MIPScc_LO; 1675 size32 = True; 1676 break; 1677 case Iop_CmpLT64U: 1678 cc = MIPScc_LO; 1679 size32 = False; 1680 break; 1681 case Iop_CmpLE32S: 1682 cc = MIPScc_LE; 1683 size32 = True; 1684 break; 1685 case Iop_CmpLE64S: 1686 cc = MIPScc_LE; 1687 size32 = False; 1688 break; 1689 case Iop_CmpLT64S: 1690 cc = MIPScc_LT; 1691 size32 = False; 1692 break; 1693 case Iop_CmpEQ64: 1694 cc = MIPScc_EQ; 1695 size32 = False; 1696 break; 1697 default: 1698 vpanic 1699 ("iselCondCode(mips): CmpXX32 or CmpXX64"); 1700 } 1701 1702 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc)); 1703 // Store result to guest_COND 1704 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64)); 1705 1706 addInstr(env, MIPSInstr_Store(4, 1707 MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base), 1708 dst, mode64)); 1709 return cc; 1710 } 1711 if (e->Iex.Binop.op == Iop_Not1) { 1712 HReg r_dst = newVRegI(env); 1713 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg); 1714 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL); 1715 1716 addInstr(env, MIPSInstr_LI(r_dst, 0x1)); 1717 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR)); 1718 // Store result to guest_COND 1719 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64)); 1720 1721 addInstr(env, MIPSInstr_Store(4, 1722 MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base), 1723 r_dst, mode64)); 1724 return MIPScc_NE; 1725 } 1726 if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) { 1727 HReg r_dst = iselWordExpr_R_wrk(env, e); 1728 // Store result to guest_COND 1729 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64)); 1730 1731 addInstr(env, MIPSInstr_Store(4, 1732 MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base), 1733 r_dst, mode64)); 1734 return MIPScc_EQ; 1735 } 1736 1737 vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag); 1738 ppIRExpr(e); 1739 vpanic("iselCondCode(mips)"); 1740 } 1741 1742 /*---------------------------------------------------------*/ 1743 /*--- ISEL: Integer expressions (128 bit) ---*/ 1744 /*---------------------------------------------------------*/ 1745 1746 /* 64-bit mode ONLY: compute a 128-bit value into a register pair, 1747 which is returned as the first two parameters. As with 1748 iselWordExpr_R, these may be either real or virtual regs; in any 1749 case they must not be changed by subsequent code emitted by the 1750 caller. */ 1751 1752 static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 1753 { 1754 vassert(env->mode64); 1755 iselInt128Expr_wrk(rHi, rLo, env, e); 1756 # if 0 1757 vex_printf("\n"); 1758 ppIRExpr(e); 1759 vex_printf("\n"); 1760 # endif 1761 vassert(hregClass(*rHi) == HRcGPR(env->mode64)); 1762 vassert(hregIsVirtual(*rHi)); 1763 vassert(hregClass(*rLo) == HRcGPR(env->mode64)); 1764 vassert(hregIsVirtual(*rLo)); 1765 } 1766 1767 /* DO NOT CALL THIS DIRECTLY ! */ 1768 static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, 1769 IRExpr * e) 1770 { 1771 vassert(e); 1772 vassert(typeOfIRExpr(env->type_env, e) == Ity_I128); 1773 1774 /* read 128-bit IRTemp */ 1775 if (e->tag == Iex_RdTmp) { 1776 lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp); 1777 return; 1778 } 1779 1780 /* --------- BINARY ops --------- */ 1781 if (e->tag == Iex_Binop) { 1782 switch (e->Iex.Binop.op) { 1783 /* 64 x 64 -> 128 multiply */ 1784 case Iop_MullU64: 1785 case Iop_MullS64: 1786 { 1787 HReg tLo = newVRegI(env); 1788 HReg tHi = newVRegI(env); 1789 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64); 1790 HReg r_dst = newVRegI(env); 1791 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1792 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1793 addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ , 1794 r_dst, r_srcL, r_srcR)); 1795 addInstr(env, MIPSInstr_Mfhi(tHi)); 1796 addInstr(env, MIPSInstr_Mflo(tLo)); 1797 *rHi = tHi; 1798 *rLo = tLo; 1799 return; 1800 } 1801 1802 /* 64HLto128(e1,e2) */ 1803 case Iop_64HLto128: 1804 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 1805 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 1806 return; 1807 1808 case Iop_DivModS64to64: { 1809 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1810 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1811 HReg tLo = newVRegI(env); 1812 HReg tHi = newVRegI(env); 1813 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64); 1814 1815 addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR)); 1816 addInstr(env, MIPSInstr_Mfhi(tHi)); 1817 addInstr(env, MIPSInstr_Mflo(tLo)); 1818 *rHi = tHi; 1819 *rLo = tLo; 1820 return; 1821 } 1822 1823 case Iop_DivModU128to64: { 1824 vassert(mode64); 1825 HReg rHi1, rLo1; 1826 iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1); 1827 1828 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1829 HReg tLo = newVRegI(env); 1830 HReg tHi = newVRegI(env); 1831 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64); 1832 1833 addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR)); 1834 addInstr(env, MIPSInstr_Mfhi(tHi)); 1835 addInstr(env, MIPSInstr_Mflo(tLo)); 1836 *rHi = tHi; 1837 *rLo = tLo; 1838 return; 1839 } 1840 1841 default: 1842 break; 1843 } 1844 } 1845 vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag); 1846 ppIRExpr(e); 1847 vpanic("iselInt128Expr(mips64)"); 1848 } 1849 1850 /*---------------------------------------------------------*/ 1851 /*--- ISEL: Integer expressions (64 bit) ---*/ 1852 /*---------------------------------------------------------*/ 1853 1854 /* 32-bit mode ONLY. Compute a 64-bit value into the register 1855 * pair HI, LO. HI and LO must not be changed by subsequent 1856 * code emitted by the caller. */ 1857 1858 static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 1859 { 1860 vassert(!env->mode64); 1861 iselInt64Expr_wrk(rHi, rLo, env, e); 1862 vassert(hregClass(*rHi) == HRcInt32); 1863 vassert(hregIsVirtual(*rHi)); 1864 vassert(hregClass(*rLo) == HRcInt32); 1865 vassert(hregIsVirtual(*rLo)); 1866 } 1867 1868 /* DO NOT CALL THIS DIRECTLY ! */ 1869 static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 1870 { 1871 vassert(e); 1872 vassert(typeOfIRExpr(env->type_env, e) == Ity_I64); 1873 1874 /* read 64-bit IRTemp */ 1875 if (e->tag == Iex_RdTmp) { 1876 lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp); 1877 return; 1878 } 1879 /* 64-bit load */ 1880 if (e->tag == Iex_Load) { 1881 HReg tLo = newVRegI(env); 1882 HReg tHi = newVRegI(env); 1883 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr); 1884 addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64)); 1885 addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64)); 1886 *rHi = tHi; 1887 *rLo = tLo; 1888 return; 1889 } 1890 1891 /* 64-bit literal */ 1892 if (e->tag == Iex_Const) { 1893 ULong w64 = e->Iex.Const.con->Ico.U64; 1894 UInt wHi = toUInt(w64 >> 32); 1895 UInt wLo = toUInt(w64); 1896 HReg tLo = newVRegI(env); 1897 HReg tHi = newVRegI(env); 1898 vassert(e->Iex.Const.con->tag == Ico_U64); 1899 1900 if (wLo == wHi) { 1901 /* Save a precious Int register in this special case. */ 1902 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo)); 1903 *rHi = tLo; 1904 *rLo = tLo; 1905 } else { 1906 addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi)); 1907 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo)); 1908 *rHi = tHi; 1909 *rLo = tLo; 1910 } 1911 1912 return; 1913 } 1914 1915 /* 64-bit GET */ 1916 if (e->tag == Iex_Get) { 1917 HReg tLo = newVRegI(env); 1918 HReg tHi = newVRegI(env); 1919 1920 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 1921 GuestStatePointer(mode64)); 1922 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64)); 1923 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64)); 1924 *rHi = tHi; 1925 *rLo = tLo; 1926 return; 1927 } 1928 1929 /* 64-bit Mux0X */ 1930 if (e->tag == Iex_Mux0X) { 1931 HReg expr0Lo, expr0Hi; 1932 HReg exprXLo, exprXHi; 1933 HReg tmpHi = newVRegI(env); 1934 HReg tmpLo = newVRegI(env); 1935 HReg tmp1Hi = newVRegI(env); 1936 HReg tmp1Lo = newVRegI(env); 1937 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond); 1938 HReg r_cond_neg = newVRegI(env); 1939 HReg desLo = newVRegI(env); 1940 HReg desHi = newVRegI(env); 1941 1942 /* expr0Hi:expr0Lo = expr0 */ 1943 /* exprXHi:exprXLo = exprX */ 1944 iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.Mux0X.expr0); 1945 iselInt64Expr(&exprXHi, &exprXLo, env, e->Iex.Mux0X.exprX); 1946 1947 addInstr(env, MIPSInstr_Alu(Malu_AND, tmpLo, r_cond, 1948 MIPSRH_Reg(exprXLo))); 1949 addInstr(env, MIPSInstr_Alu(Malu_AND, tmpHi, r_cond, 1950 MIPSRH_Reg(exprXHi))); 1951 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond, 1952 MIPSRH_Reg(r_cond))); 1953 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Lo, r_cond_neg, 1954 MIPSRH_Reg(exprXLo))); 1955 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Hi, r_cond_neg, 1956 MIPSRH_Reg(exprXHi))); 1957 addInstr(env, MIPSInstr_Alu(Malu_ADD, desLo, tmpLo, 1958 MIPSRH_Reg(tmp1Lo))); 1959 addInstr(env, MIPSInstr_Alu(Malu_ADD, desHi, tmpHi, 1960 MIPSRH_Reg(tmp1Hi))); 1961 *rHi = desHi; 1962 *rLo = desLo; 1963 return; 1964 } 1965 1966 /* --------- BINARY ops --------- */ 1967 if (e->tag == Iex_Binop) { 1968 IROp op_binop = e->Iex.Binop.op; 1969 switch (op_binop) { 1970 /* 32 x 32 -> 64 multiply */ 1971 /* Add64 */ 1972 case Iop_Add64: { 1973 HReg xLo, xHi, yLo, yHi; 1974 HReg tHi = newVRegI(env); 1975 HReg tLo = newVRegI(env); 1976 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 1977 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 1978 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, xHi, MIPSRH_Reg(yHi))); 1979 addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo))); 1980 *rHi = tHi; 1981 *rLo = tLo; 1982 return; 1983 } 1984 case Iop_MullU32: 1985 case Iop_MullS32: { 1986 HReg tLo = newVRegI(env); 1987 HReg tHi = newVRegI(env); 1988 HReg r_dst = newVRegI(env); 1989 Bool syned = toBool(op_binop == Iop_MullS32); 1990 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1991 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1992 1993 addInstr(env, MIPSInstr_Mul(syned/*Unsigned or Signed */ , 1994 True /*widen */ , True, 1995 r_dst, r_srcL, r_srcR)); 1996 addInstr(env, MIPSInstr_Mfhi(tHi)); 1997 addInstr(env, MIPSInstr_Mflo(tLo)); 1998 *rHi = tHi; 1999 *rLo = tLo; 2000 2001 return; 2002 } 2003 case Iop_DivModS64to32: 2004 case Iop_DivModU64to32: { 2005 HReg r_sHi, r_sLo; 2006 HReg tLo = newVRegI(env); 2007 HReg tHi = newVRegI(env); 2008 Bool syned = toBool(op_binop == Iop_DivModS64to32); 2009 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2010 2011 iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1); 2012 addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR)); 2013 addInstr(env, MIPSInstr_Mfhi(tHi)); 2014 addInstr(env, MIPSInstr_Mflo(tLo)); 2015 *rHi = tHi; 2016 *rLo = tLo; 2017 2018 return; 2019 } 2020 2021 /* 32HLto64(e1,e2) */ 2022 case Iop_32HLto64: 2023 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 2024 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 2025 2026 return; 2027 /* Or64/And64/Xor64 */ 2028 case Iop_Or64: 2029 case Iop_And64: 2030 case Iop_Xor64: { 2031 HReg xLo, xHi, yLo, yHi; 2032 HReg tLo = newVRegI(env); 2033 HReg tHi = newVRegI(env); 2034 MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR : 2035 (op_binop == Iop_And64) ? Malu_AND : Malu_XOR; 2036 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 2037 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 2038 addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi))); 2039 addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo))); 2040 *rHi = tHi; 2041 *rLo = tLo; 2042 return; 2043 } 2044 2045 default: 2046 break; 2047 } 2048 } 2049 2050 /* --------- UNARY ops --------- */ 2051 if (e->tag == Iex_Unop) { 2052 2053 switch (e->Iex.Unop.op) { 2054 case Iop_1Sto64: { 2055 HReg tLo = newVRegI(env); 2056 HReg tHi = newVRegI(env); 2057 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2058 HReg tmp = newVRegI(env); 2059 2060 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src, 2061 MIPSRH_Imm(False, 31))); 2062 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, src, 2063 MIPSRH_Imm(False, 31))); 2064 2065 addInstr(env, mk_iMOVds_RR(tHi, tmp)); 2066 addInstr(env, mk_iMOVds_RR(tLo, tmp)); 2067 2068 *rHi = tHi; 2069 *rLo = tLo; 2070 return; 2071 } 2072 2073 /* 32Sto64(e) */ 2074 case Iop_32Sto64: { 2075 HReg tLo = newVRegI(env); 2076 HReg tHi = newVRegI(env); 2077 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2078 addInstr(env, mk_iMOVds_RR(tHi, src)); 2079 addInstr(env, mk_iMOVds_RR(tLo, src)); 2080 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi, 2081 MIPSRH_Imm(False, 31))); 2082 *rHi = tHi; 2083 *rLo = tLo; 2084 return; 2085 } 2086 2087 /* 32Uto64(e) */ 2088 case Iop_32Uto64: { 2089 HReg tLo = newVRegI(env); 2090 HReg tHi = newVRegI(env); 2091 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2092 addInstr(env, mk_iMOVds_RR(tLo, src)); 2093 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64), 2094 MIPSRH_Reg(hregMIPS_GPR0(mode64)))); 2095 *rHi = tHi; 2096 *rLo = tLo; 2097 return; 2098 } 2099 2100 case Iop_CmpwNEZ64: { 2101 HReg srcLo, srcHi; 2102 HReg tmp1 = newVRegI(env); 2103 HReg tmp2 = newVRegI(env); 2104 /* srcHi:srcLo = arg */ 2105 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg); 2106 /* tmp1 = srcHi | srcLo */ 2107 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo, 2108 MIPSRH_Reg(srcHi))); 2109 /* tmp2 = (tmp1 | -tmp1) >>s 31 */ 2110 2111 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64), 2112 MIPSRH_Reg(tmp1))); 2113 2114 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1))); 2115 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2, 2116 MIPSRH_Imm(False, 31))); 2117 *rHi = tmp2; 2118 *rLo = tmp2; 2119 return; 2120 2121 } 2122 case Iop_ReinterpF64asI64: { 2123 HReg tLo = newVRegI(env); 2124 HReg tHi = newVRegI(env); 2125 MIPSAMode *am_addr; 2126 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg); 2127 2128 sub_from_sp(env, 16); // Move SP down 16 bytes 2129 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2130 2131 // store as F64 2132 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, 2133 am_addr)); 2134 // load as 2xI32 2135 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64)); 2136 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr), 2137 mode64)); 2138 2139 add_to_sp(env, 16); // Reset SP 2140 2141 *rHi = tHi; 2142 *rLo = tLo; 2143 return; 2144 } 2145 2146 default: 2147 vex_printf("UNARY: No such op: "); 2148 ppIROp(e->Iex.Unop.op); 2149 vex_printf("\n"); 2150 break; 2151 } 2152 } 2153 2154 vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag); 2155 ppIRExpr(e); 2156 vpanic("iselInt64Expr(mips)"); 2157 } 2158 2159 /*---------------------------------------------------------*/ 2160 /*--- ISEL: Floating point expressions (32 bit) ---*/ 2161 /*---------------------------------------------------------*/ 2162 2163 /* Nothing interesting here; really just wrappers for 2164 64-bit stuff. */ 2165 2166 static HReg iselFltExpr(ISelEnv * env, IRExpr * e) 2167 { 2168 HReg r = iselFltExpr_wrk(env, e); 2169 vassert(hregIsVirtual(r)); 2170 return r; 2171 } 2172 2173 /* DO NOT CALL THIS DIRECTLY */ 2174 static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) 2175 { 2176 IRType ty = typeOfIRExpr(env->type_env, e); 2177 vassert(ty == Ity_F32 || (ty == Ity_F64 && mode64)); 2178 2179 if (e->tag == Iex_RdTmp) { 2180 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 2181 } 2182 2183 if (e->tag == Iex_Load) { 2184 MIPSAMode *am_addr; 2185 HReg r_dst = newVRegF(env); 2186 vassert(e->Iex.Load.ty == Ity_F32 2187 || (e->Iex.Load.ty == Ity_F64 && mode64)); 2188 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty); 2189 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr)); 2190 return r_dst; 2191 } 2192 2193 if (e->tag == Iex_Get) { 2194 HReg r_dst = newVRegF(env); 2195 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 2196 GuestStatePointer(mode64)); 2197 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr)); 2198 return r_dst; 2199 } 2200 2201 if (e->tag == Iex_Unop) { 2202 switch (e->Iex.Unop.op) { 2203 case Iop_ReinterpI32asF32: { 2204 MIPSAMode *am_addr; 2205 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg); 2206 HReg r_dst = newVRegF(env); 2207 2208 sub_from_sp(env, 16); // Move SP down 16 bytes 2209 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2210 2211 // store as I32 2212 addInstr(env, MIPSInstr_Store(4, am_addr, fr_src, mode64)); 2213 2214 // load as Ity_F32 2215 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr)); 2216 2217 add_to_sp(env, 16); // Reset SP 2218 return r_dst; 2219 2220 } 2221 case Iop_F32toF64: { 2222 /* first arg is rounding mode; we ignore it. */ 2223 MIPSAMode *am_addr; 2224 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 2225 HReg dst = newVRegF(env); 2226 2227 sub_from_sp(env, 16); // Move SP down 16 bytes 2228 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2229 2230 addInstr(env, MIPSInstr_Store(4, 2231 MIPSAMode_IR(am_addr->Mam.IR.index + 4, 2232 am_addr->Mam.IR.base), 2233 hregMIPS_GPR0(mode64), mode64)); 2234 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, src, am_addr)); 2235 2236 // load as Ity_F32 2237 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, dst, am_addr)); 2238 add_to_sp(env, 16); // Reset SP 2239 2240 return dst; 2241 } 2242 case Iop_ReinterpI64asF64: 2243 { 2244 vassert(mode64); 2245 MIPSAMode *am_addr; 2246 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg); 2247 HReg r_dst = newVRegF(env); 2248 2249 sub_from_sp(env, 16); // Move SP down 16 bytes 2250 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2251 2252 // store as I32 2253 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64)); 2254 2255 // load as Ity_F32 2256 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr)); 2257 2258 add_to_sp(env, 16); // Reset SP 2259 return r_dst; 2260 } 2261 case Iop_AbsF32: 2262 case Iop_AbsF64: { 2263 Bool sz32 = e->Iex.Unop.op == Iop_AbsF32; 2264 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 2265 HReg dst = newVRegF(env); 2266 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src)); 2267 return dst; 2268 } 2269 case Iop_NegF32: 2270 case Iop_NegF64: { 2271 Bool sz32 = e->Iex.Unop.op == Iop_NegF32; 2272 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 2273 HReg dst = newVRegF(env); 2274 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src)); 2275 return dst; 2276 } 2277 default: 2278 break; 2279 } 2280 } 2281 2282 if (e->tag == Iex_Triop) { 2283 switch (e->Iex.Triop.details->op) { 2284 case Iop_DivF32: 2285 case Iop_DivF64: 2286 case Iop_MulF32: 2287 case Iop_MulF64: 2288 case Iop_AddF32: 2289 case Iop_AddF64: 2290 case Iop_SubF32: 2291 case Iop_SubF64: { 2292 MIPSFpOp op = 0; 2293 /*INVALID*/ HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2); 2294 HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3); 2295 HReg dst = newVRegF(env); 2296 switch (e->Iex.Triop.details->op) { 2297 case Iop_DivF32: 2298 op = Mfp_DIVS; 2299 break; 2300 case Iop_MulF32: 2301 op = Mfp_MULS; 2302 break; 2303 case Iop_AddF32: 2304 op = Mfp_ADDS; 2305 break; 2306 case Iop_SubF32: 2307 op = Mfp_SUBS; 2308 break; 2309 default: 2310 vassert(0); 2311 } 2312 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR)); 2313 return dst; 2314 } 2315 default: 2316 break; 2317 } 2318 } 2319 2320 if (e->tag == Iex_Binop) { 2321 switch (e->Iex.Binop.op) { 2322 case Iop_F64toF32: { 2323 HReg valD = iselDblExpr(env, e->Iex.Binop.arg2); 2324 HReg valS = newVRegF(env); 2325 2326 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 2327 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD)); 2328 set_MIPS_rounding_default(env); 2329 return valS; 2330 } 2331 2332 case Iop_RoundF32toInt: { 2333 HReg valS = newVRegF(env); 2334 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); 2335 2336 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 2337 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF)); 2338 2339 set_MIPS_rounding_default(env); 2340 return valS; 2341 } 2342 2343 case Iop_I32StoF32: { 2344 HReg r_dst = newVRegF(env); 2345 2346 MIPSAMode *am_addr; 2347 HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2); 2348 HReg tmp = newVRegF(env); 2349 2350 sub_from_sp(env, 16); // Move SP down 16 bytes 2351 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2352 2353 // store as I32 2354 addInstr(env, MIPSInstr_Store(4, am_addr, fr_src, mode64)); 2355 2356 // load as Ity_F32 2357 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, tmp, am_addr)); 2358 2359 add_to_sp(env, 16); // Reset SP 2360 2361 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 2362 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp)); 2363 set_MIPS_rounding_default(env); 2364 2365 return r_dst; 2366 } 2367 2368 case Iop_SqrtF32: 2369 case Iop_SqrtF64: { 2370 /* first arg is rounding mode; we ignore it. */ 2371 Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32; 2372 HReg src = iselFltExpr(env, e->Iex.Binop.arg2); 2373 HReg dst = newVRegF(env); 2374 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 2375 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst, 2376 src)); 2377 set_MIPS_rounding_default(env); 2378 return dst; 2379 } 2380 2381 default: 2382 break; 2383 } 2384 } 2385 2386 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) { 2387 /* This is quite subtle. The only way to do the relevant 2388 truncation is to do a single-precision store and then a 2389 double precision load to get it back into a register. The 2390 problem is, if the data is then written to memory a second 2391 time, as in 2392 2393 STbe(...) = TruncF64asF32(...) 2394 2395 then will the second truncation further alter the value? The 2396 answer is no: flds (as generated here) followed by fsts 2397 (generated for the STbe) is the identity function on 32-bit 2398 floats, so we are safe. 2399 2400 Another upshot of this is that if iselStmt can see the 2401 entirety of 2402 2403 STbe(...) = TruncF64asF32(arg) 2404 2405 then it can short circuit having to deal with TruncF64asF32 2406 individually; instead just compute arg into a 64-bit FP 2407 register and do 'fsts' (since that itself does the 2408 truncation). 2409 2410 We generate pretty poor code here (should be ok both for 2411 32-bit and 64-bit mode); but it is expected that for the most 2412 part the latter optimisation will apply and hence this code 2413 will not often be used. 2414 */ 2415 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg); 2416 HReg fdst = newVRegF(env); 2417 MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64)); 2418 2419 sub_from_sp(env, 16); 2420 // store as F32, hence truncating 2421 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1)); 2422 // and reload. Good huh?! (sigh) 2423 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1)); 2424 add_to_sp(env, 16); 2425 return fdst; 2426 } 2427 2428 vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag); 2429 ppIRExpr(e); 2430 vpanic("iselFltExpr_wrk(mips)"); 2431 } 2432 2433 static HReg iselDblExpr(ISelEnv * env, IRExpr * e) 2434 { 2435 HReg r = iselDblExpr_wrk(env, e); 2436 vassert(hregClass(r) == HRcFlt64); 2437 vassert(hregIsVirtual(r)); 2438 return r; 2439 } 2440 2441 /* DO NOT CALL THIS DIRECTLY */ 2442 static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) 2443 { 2444 IRType ty = typeOfIRExpr(env->type_env, e); 2445 vassert(e); 2446 vassert(ty == Ity_F64); 2447 2448 if (e->tag == Iex_RdTmp) { 2449 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 2450 } 2451 2452 /* --------- LOAD --------- */ 2453 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) { 2454 HReg r_dst = newVRegD(env); 2455 MIPSAMode *am_addr; 2456 vassert(e->Iex.Load.ty == Ity_F64); 2457 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty); 2458 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr)); 2459 return r_dst; 2460 } 2461 2462 /* --------- GET --------- */ 2463 if (e->tag == Iex_Get) { 2464 2465 HReg r_dst = newVRegD(env); 2466 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 2467 GuestStatePointer(mode64)); 2468 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr)); 2469 return r_dst; 2470 } 2471 2472 if (e->tag == Iex_Unop) { 2473 MIPSFpOp fpop = Mfp_INVALID; 2474 switch (e->Iex.Unop.op) { 2475 case Iop_NegF64: 2476 fpop = Mfp_NEGD; 2477 break; 2478 case Iop_AbsF64: 2479 fpop = Mfp_ABSD; 2480 break; 2481 case Iop_F32toF64: { 2482 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 2483 HReg dst = newVRegD(env); 2484 2485 HReg irrm = newVRegI(env); 2486 2487 MIPSAMode *am_addr1 = MIPSAMode_IR(284, GuestStatePointer(mode64)); 2488 2489 addInstr(env, MIPSInstr_Load(4, irrm, am_addr1, mode64)); 2490 2491 // set new FCSR 2492 HReg tmp = newVRegI(env); 2493 HReg fcsr_old = newVRegI(env); 2494 MIPSAMode *am_addr; 2495 2496 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm, 2497 MIPSRH_Imm(False, 1))); 2498 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp))); 2499 addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, 2500 MIPSRH_Imm(False, 3))); 2501 /* save old value of FCSR */ 2502 addInstr(env, MIPSInstr_MfFCSR(fcsr_old)); 2503 sub_from_sp(env, 8); // Move SP down 4 bytes 2504 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2505 2506 //store old FCSR to stack 2507 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64)); 2508 2509 //set new value of FCSR 2510 addInstr(env, MIPSInstr_MtFCSR(irrm)); 2511 2512 //set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 2513 addInstr(env, MIPSInstr_FpUnary(Mfp_CVTD, dst, src)); 2514 set_MIPS_rounding_default(env); 2515 return dst; 2516 } 2517 case Iop_ReinterpI64asF64: { 2518 HReg Hi; 2519 HReg Lo; 2520 HReg dst = newVRegD(env); 2521 2522 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg); 2523 2524 dst = mk_LoadRR32toFPR(env, Hi, Lo); // 2*I32 -> F64 2525 return dst; 2526 } 2527 case Iop_I32StoF64: { 2528 HReg dst = newVRegD(env); 2529 HReg tmp1 = newVRegF(env); 2530 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 2531 MIPSAMode *am_addr; 2532 sub_from_sp(env, 16); // Move SP down 16 bytes 2533 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2534 2535 // store as I32 2536 addInstr(env, MIPSInstr_Store(4, am_addr, r_src, mode64)); 2537 2538 // load as Ity_F32 2539 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, tmp1, am_addr)); 2540 2541 add_to_sp(env, 16); // Reset SP 2542 2543 HReg irrm = newVRegI(env); 2544 2545 MIPSAMode *am_addr1 = MIPSAMode_IR(284, GuestStatePointer(mode64)); 2546 2547 addInstr(env, MIPSInstr_Load(4, irrm, am_addr1, mode64)); 2548 2549 //set rounding mode 2550 HReg tmp = newVRegI(env); 2551 HReg fcsr_old = newVRegI(env); 2552 2553 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm, 2554 MIPSRH_Imm(False, 1))); 2555 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp))); 2556 addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, 2557 MIPSRH_Imm(False, 3))); 2558 /* save old value of FCSR */ 2559 addInstr(env, MIPSInstr_MfFCSR(fcsr_old)); 2560 sub_from_sp(env, 8); // Move SP down 4 bytes 2561 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2562 2563 //store old FCSR to stack 2564 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64)); 2565 2566 //set new value of FCSR 2567 addInstr(env, MIPSInstr_MtFCSR(irrm)); 2568 2569 // and do convert 2570 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp1)); 2571 set_MIPS_rounding_default(env); 2572 2573 return dst; 2574 } 2575 default: 2576 break; 2577 } 2578 2579 if (fpop != Mfp_INVALID) { 2580 HReg src = iselDblExpr(env, e->Iex.Unop.arg); 2581 HReg dst = newVRegD(env); 2582 addInstr(env, MIPSInstr_FpUnary(fpop, dst, src)); 2583 return dst; 2584 } 2585 } 2586 2587 if (e->tag == Iex_Binop) { 2588 switch (e->Iex.Binop.op) { 2589 case Iop_RoundF64toInt: { 2590 HReg valD = iselDblExpr(env, e->Iex.Binop.arg2); 2591 MIPSRH *fmt = iselWordExpr_RH(env, False, e->Iex.Binop.arg1); 2592 HReg valD1 = newVRegD(env); 2593 2594 if (fmt->Mrh.Imm.imm16 == 0x3) 2595 addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, valD1, valD)); 2596 else if (fmt->Mrh.Imm.imm16 == 0x2) 2597 addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, valD1, valD)); 2598 else 2599 vassert(0); 2600 return valD1; 2601 } 2602 2603 case Iop_SqrtF64:{ 2604 /* first arg is rounding mode; we ignore it. */ 2605 HReg src = iselDblExpr(env, e->Iex.Binop.arg2); 2606 HReg dst = newVRegD(env); 2607 addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src)); 2608 return dst; 2609 } 2610 2611 default: 2612 break; 2613 2614 } 2615 } 2616 2617 if (e->tag == Iex_Triop) { 2618 switch (e->Iex.Triop.details->op) { 2619 case Iop_DivF64: 2620 case Iop_DivF32: 2621 case Iop_MulF64: 2622 case Iop_AddF64: 2623 case Iop_SubF64: { 2624 MIPSFpOp op = 0; 2625 /*INVALID*/ HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2); 2626 HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3); 2627 HReg dst = newVRegD(env); 2628 switch (e->Iex.Triop.details->op) { 2629 case Iop_DivF64: 2630 op = Mfp_DIVD; 2631 break; 2632 case Iop_MulF64: 2633 op = Mfp_MULD; 2634 break; 2635 case Iop_AddF64: 2636 op = Mfp_ADDD; 2637 break; 2638 case Iop_SubF64: 2639 op = Mfp_SUBD; 2640 break; 2641 default: 2642 vassert(0); 2643 } 2644 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR)); 2645 return dst; 2646 } 2647 default: 2648 break; 2649 } 2650 } 2651 2652 /* --------- MULTIPLEX --------- */ 2653 if (e->tag == Iex_Mux0X) { 2654 if (ty == Ity_F64 2655 && typeOfIRExpr(env->type_env, e->Iex.Mux0X.cond) == Ity_I8) { 2656 HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0); 2657 HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX); 2658 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond); 2659 HReg r_cond_neg = newVRegI(env); 2660 HReg r_dst = newVRegD(env); 2661 HReg r_tmp_lo = newVRegI(env); 2662 HReg r_tmp_hi = newVRegI(env); 2663 HReg r_tmp1_lo = newVRegI(env); 2664 HReg r_tmp1_hi = newVRegI(env); 2665 HReg r_r0_lo = newVRegI(env); 2666 HReg r_r0_hi = newVRegI(env); 2667 HReg r_rX_lo = newVRegI(env); 2668 HReg r_rX_hi = newVRegI(env); 2669 HReg r_dst_lo = newVRegI(env); 2670 HReg r_dst_hi = newVRegI(env); 2671 2672 sub_from_sp(env, 16); // Move SP down 16 bytes 2673 MIPSAMode *am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2674 2675 // store as Ity_F64 2676 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, r0, am_addr)); 2677 2678 // load as 2xI32 2679 addInstr(env, MIPSInstr_Load(4, r_r0_lo, am_addr, mode64)); 2680 addInstr(env, MIPSInstr_Load(4, r_r0_hi, nextMIPSAModeFloat(am_addr), 2681 mode64)); 2682 2683 add_to_sp(env, 16); // Reset SP 2684 2685 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp_lo, r_cond, 2686 MIPSRH_Reg(r_r0_lo))); 2687 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp_hi, r_cond, 2688 MIPSRH_Reg(r_r0_hi))); 2689 2690 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond, 2691 MIPSRH_Reg(r_cond))); 2692 2693 sub_from_sp(env, 16); // Move SP down 16 bytes 2694 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2695 2696 // store as Ity_F64 2697 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, rX, am_addr)); 2698 2699 // load as 2xI32 2700 addInstr(env, MIPSInstr_Load(4, r_rX_lo, am_addr, mode64)); 2701 addInstr(env, MIPSInstr_Load(4, r_rX_hi, nextMIPSAModeFloat(am_addr), 2702 mode64)); 2703 2704 add_to_sp(env, 16); // Reset SP 2705 2706 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1_lo, r_cond_neg, 2707 MIPSRH_Reg(r_rX_lo))); 2708 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1_hi, r_cond_neg, 2709 MIPSRH_Reg(r_rX_hi))); 2710 2711 addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst_lo, r_tmp_lo, 2712 MIPSRH_Reg(r_tmp1_lo))); 2713 addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst_hi, r_tmp_hi, 2714 MIPSRH_Reg(r_tmp1_hi))); 2715 2716 sub_from_sp(env, 16); // Move SP down 16 bytes 2717 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2718 2719 // store as I32 2720 addInstr(env, MIPSInstr_Store(4, am_addr, r_dst_lo, mode64)); 2721 addInstr(env, MIPSInstr_Store(4, nextMIPSAModeFloat(am_addr), 2722 r_dst_hi, mode64)); 2723 2724 // load as Ity_F32 2725 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr)); 2726 2727 add_to_sp(env, 16); // Reset SP 2728 2729 return r_dst; 2730 } 2731 } 2732 2733 vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag); 2734 ppIRExpr(e); 2735 vpanic("iselDblExpr_wrk(mips)"); 2736 } 2737 2738 /*---------------------------------------------------------*/ 2739 /*--- ISEL: Statements ---*/ 2740 /*---------------------------------------------------------*/ 2741 2742 static void iselStmt(ISelEnv * env, IRStmt * stmt) 2743 { 2744 if (vex_traceflags & VEX_TRACE_VCODE) { 2745 vex_printf("\n-- "); 2746 2747 ppIRStmt(stmt); 2748 vex_printf("\n"); 2749 } 2750 2751 switch (stmt->tag) { 2752 /* --------- STORE --------- */ 2753 case Ist_Store: { 2754 MIPSAMode *am_addr; 2755 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 2756 2757 /*constructs addressing mode from address provided */ 2758 am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd); 2759 2760 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 || 2761 (mode64 && (tyd == Ity_I64))) { 2762 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data); 2763 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)), 2764 am_addr, r_src, mode64)); 2765 return; 2766 } 2767 if (!mode64 && (tyd == Ity_I64)) { 2768 HReg vHi, vLo; 2769 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr); 2770 2771 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data); 2772 2773 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 2774 MIPSAMode_IR(0, r_addr), vHi, mode64)); 2775 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 2776 MIPSAMode_IR(4, r_addr), vLo, mode64)); 2777 return; 2778 } 2779 if (tyd == Ity_F32) { 2780 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data); 2781 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src, 2782 am_addr)); 2783 return; 2784 } 2785 2786 break; 2787 } 2788 2789 /* --------- PUT --------- */ 2790 case Ist_Put: { 2791 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 2792 2793 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || 2794 (ty == Ity_I64 && mode64)) { 2795 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data); 2796 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 2797 GuestStatePointer(mode64)); 2798 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)), 2799 am_addr, r_src, mode64)); 2800 return; 2801 } 2802 2803 if (ty == Ity_I64 && !mode64) { 2804 HReg vHi, vLo; 2805 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 2806 GuestStatePointer(mode64)); 2807 MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4, 2808 GuestStatePointer(mode64)); 2809 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data); 2810 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 2811 am_addr, vLo, mode64)); 2812 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 2813 am_addr4, vHi, mode64)); 2814 return; 2815 2816 } 2817 2818 if (ty == Ity_F32) { 2819 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data); 2820 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 2821 GuestStatePointer(mode64)); 2822 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src, 2823 am_addr)); 2824 return; 2825 } 2826 2827 if (ty == Ity_F64) { 2828 HReg fr_src; 2829 fr_src = iselDblExpr(env, stmt->Ist.Put.data); 2830 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 2831 GuestStatePointer(mode64)); 2832 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, 2833 am_addr)); 2834 return; 2835 } 2836 break; 2837 } 2838 2839 /* --------- TMP --------- */ 2840 case Ist_WrTmp: { 2841 IRTemp tmp = stmt->Ist.WrTmp.tmp; 2842 IRType ty = typeOfIRTemp(env->type_env, tmp); 2843 2844 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) { 2845 HReg r_dst = lookupIRTemp(env, tmp); 2846 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data); 2847 addInstr(env, mk_iMOVds_RR(r_dst, r_src)); 2848 return; 2849 } 2850 2851 if (ty == Ity_I64) { 2852 HReg rHi, rLo, dstHi, dstLo; 2853 iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data); 2854 lookupIRTemp64(&dstHi, &dstLo, env, tmp); 2855 addInstr(env, mk_iMOVds_RR(dstHi, rHi)); 2856 addInstr(env, mk_iMOVds_RR(dstLo, rLo)); 2857 return; 2858 } 2859 2860 if (ty == Ity_F32) { 2861 HReg fr_dst = lookupIRTemp(env, tmp); 2862 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data); 2863 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src)); 2864 return; 2865 } 2866 2867 if (ty == Ity_F64) { 2868 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data); 2869 HReg dst = lookupIRTemp(env, tmp); 2870 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src)); 2871 return; 2872 } 2873 break; 2874 } 2875 2876 /* --------- Call to DIRTY helper --------- */ 2877 case Ist_Dirty: { 2878 IRType retty; 2879 IRDirty *d = stmt->Ist.Dirty.details; 2880 Bool passBBP = False; 2881 2882 if (d->nFxState == 0) 2883 vassert(!d->needsBBP); 2884 passBBP = toBool(d->nFxState > 0 && d->needsBBP); 2885 2886 /* Marshal args, do the call, clear stack. */ 2887 doHelperCall(env, passBBP, d->guard, d->cee, d->args); 2888 2889 /* Now figure out what to do with the returned value, if any. */ 2890 if (d->tmp == IRTemp_INVALID) 2891 /* No return value. Nothing to do. */ 2892 return; 2893 2894 retty = typeOfIRTemp(env->type_env, d->tmp); 2895 if (retty == Ity_I64 && !mode64) { 2896 vex_printf 2897 ("Dirty! Return 64 bits. Not implemented (yet!)\n"); 2898 return; 2899 } 2900 if (retty == Ity_I8 || retty == Ity_I16 || retty == Ity_I32 2901 || (retty == Ity_I64 && mode64)) { 2902 /* The returned value is in %r2. Park it in the register 2903 associated with tmp. */ 2904 HReg r_dst = lookupIRTemp(env, d->tmp); 2905 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64))); 2906 return; 2907 } 2908 break; 2909 } 2910 2911 /* --------- Load Linked or Store Conditional --------- */ 2912 case Ist_LLSC: { 2913 //Temporary solution; this need to be rewritten again for MIPS. 2914 //On MIPS you can not read from address that is locked with LL before SC. 2915 // If you read from address that is locked than SC will fall. 2916 IRTemp res = stmt->Ist.LLSC.result; 2917 IRType tyRes = typeOfIRTemp(env->type_env, res); 2918 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr); 2919 2920 if (!mode64 && (tyAddr != Ity_I32)) 2921 goto stmt_fail; 2922 2923 if (stmt->Ist.LLSC.storedata == NULL) { 2924 /* LL */ 2925 MIPSAMode *r_addr; 2926 /*constructs addressing mode from address provided */ 2927 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr); 2928 2929 HReg r_dst = lookupIRTemp(env, res); 2930 if (tyRes == Ity_I32) { 2931 addInstr(env, MIPSInstr_Load(4, r_dst, r_addr, mode64)); 2932 return; 2933 } else if (tyRes == Ity_I64 && mode64) { 2934 addInstr(env, MIPSInstr_Load(8, r_dst, r_addr, mode64)); 2935 return; 2936 } 2937 /* fallthru */ ; 2938 } else { 2939 /* SC */ 2940 MIPSAMode *r_addr; 2941 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr); 2942 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata); 2943 HReg r_dst = lookupIRTemp(env, res); 2944 IRType tyData = typeOfIRExpr(env->type_env, 2945 stmt->Ist.LLSC.storedata); 2946 2947 if (tyData == Ity_I32) { 2948 addInstr(env, MIPSInstr_Store(4, r_addr, r_src, mode64)); 2949 addInstr(env, MIPSInstr_LI(r_dst, 0x1)); 2950 return; 2951 } else if (tyData == Ity_I64 && mode64) { 2952 addInstr(env, MIPSInstr_Store(8, r_addr, r_src, mode64)); 2953 addInstr(env, MIPSInstr_LI(r_dst, 0x1)); 2954 return; 2955 } 2956 /* fallthru */ 2957 } 2958 goto stmt_fail; 2959 /*NOTREACHED*/} 2960 2961 /* --------- INSTR MARK --------- */ 2962 /* Doesn't generate any executable code ... */ 2963 case Ist_IMark: 2964 return; 2965 2966 /* --------- ABI HINT --------- */ 2967 /* These have no meaning (denotation in the IR) and so we ignore 2968 them ... if any actually made it this far. */ 2969 case Ist_AbiHint: 2970 return; 2971 2972 /* --------- NO-OP --------- */ 2973 /* Fairly self-explanatory, wouldn't you say? */ 2974 case Ist_NoOp: 2975 return; 2976 2977 /* --------- EXIT --------- */ 2978 case Ist_Exit: { 2979 IRConst* dst = stmt->Ist.Exit.dst; 2980 if (!mode64 && dst->tag != Ico_U32) 2981 vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value"); 2982 if (mode64 && dst->tag != Ico_U64) 2983 vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value"); 2984 2985 MIPSCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard); 2986 MIPSAMode* amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP, 2987 hregMIPS_GPR10(mode64)); 2988 2989 /* Case: boring transfer to known address */ 2990 if (stmt->Ist.Exit.jk == Ijk_Boring 2991 || stmt->Ist.Exit.jk == Ijk_Call 2992 /* || stmt->Ist.Exit.jk == Ijk_Ret */) { 2993 if (env->chainingAllowed) { 2994 /* .. almost always true .. */ 2995 /* Skip the event check at the dst if this is a forwards 2996 edge. */ 2997 Bool toFastEP 2998 = mode64 2999 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga) 3000 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga); 3001 if (0) vex_printf("%s", toFastEP ? "Y" : ","); 3002 addInstr(env, MIPSInstr_XDirect( 3003 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64 3004 : (Addr64)stmt->Ist.Exit.dst->Ico.U32, 3005 amPC, cc, toFastEP)); 3006 } else { 3007 /* .. very occasionally .. */ 3008 /* We can't use chaining, so ask for an assisted transfer, 3009 as that's the only alternative that is allowable. */ 3010 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst)); 3011 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring)); 3012 } 3013 return; 3014 } 3015 3016 /* Case: assisted transfer to arbitrary address */ 3017 switch (stmt->Ist.Exit.jk) { 3018 /* Keep this list in sync with that in iselNext below */ 3019 case Ijk_ClientReq: 3020 case Ijk_EmFail: 3021 case Ijk_EmWarn: 3022 case Ijk_NoDecode: 3023 case Ijk_NoRedir: 3024 case Ijk_SigBUS: 3025 case Ijk_SigTRAP: 3026 case Ijk_Sys_syscall: 3027 case Ijk_TInval: 3028 { 3029 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst)); 3030 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, 3031 stmt->Ist.Exit.jk)); 3032 return; 3033 } 3034 default: 3035 break; 3036 } 3037 3038 /* Do we ever expect to see any other kind? */ 3039 goto stmt_fail; 3040 } 3041 3042 default: 3043 break; 3044 } 3045 3046 stmt_fail: 3047 vex_printf("stmt_fail tag: 0x%x\n", stmt->tag); 3048 ppIRStmt(stmt); 3049 vpanic("iselStmt:\n"); 3050 } 3051 3052 /*---------------------------------------------------------*/ 3053 /*--- ISEL: Basic block terminators (Nexts) ---*/ 3054 /*---------------------------------------------------------*/ 3055 3056 static void iselNext ( ISelEnv* env, 3057 IRExpr* next, IRJumpKind jk, Int offsIP ) 3058 { 3059 if (vex_traceflags & VEX_TRACE_VCODE) { 3060 vex_printf( "\n-- PUT(%d) = ", offsIP); 3061 ppIRExpr( next ); 3062 vex_printf( "; exit-"); 3063 ppIRJumpKind(jk); 3064 vex_printf( "\n"); 3065 } 3066 3067 /* Case: boring transfer to known address */ 3068 if (next->tag == Iex_Const) { 3069 IRConst* cdst = next->Iex.Const.con; 3070 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32)); 3071 if (jk == Ijk_Boring || jk == Ijk_Call) { 3072 /* Boring transfer to known address */ 3073 MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64)); 3074 if (env->chainingAllowed) { 3075 /* .. almost always true .. */ 3076 /* Skip the event check at the dst if this is a forwards 3077 edge. */ 3078 Bool toFastEP 3079 = env->mode64 3080 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga) 3081 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga); 3082 if (0) vex_printf("%s", toFastEP ? "X" : "."); 3083 addInstr(env, MIPSInstr_XDirect( 3084 env->mode64 ? (Addr64)cdst->Ico.U64 3085 : (Addr64)cdst->Ico.U32, 3086 amPC, MIPScc_AL, toFastEP)); 3087 } else { 3088 /* .. very occasionally .. */ 3089 /* We can't use chaining, so ask for an assisted transfer, 3090 as that's the only alternative that is allowable. */ 3091 HReg r = iselWordExpr_R(env, next); 3092 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, 3093 Ijk_Boring)); 3094 } 3095 return; 3096 } 3097 } 3098 3099 /* Case: call/return (==boring) transfer to any address */ 3100 switch (jk) { 3101 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: { 3102 3103 HReg r = iselWordExpr_R(env, next); 3104 MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64)); 3105 if (env->chainingAllowed) { 3106 addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL)); 3107 } else { 3108 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, 3109 Ijk_Boring)); 3110 } 3111 return; 3112 } 3113 default: 3114 break; 3115 } 3116 3117 /* Case: assisted transfer to arbitrary address */ 3118 switch (jk) { 3119 /* Keep this list in sync with that for Ist_Exit above */ 3120 case Ijk_ClientReq: 3121 case Ijk_EmFail: 3122 case Ijk_EmWarn: 3123 case Ijk_NoDecode: 3124 case Ijk_NoRedir: 3125 case Ijk_SigBUS: 3126 case Ijk_SigTRAP: 3127 case Ijk_Sys_syscall: 3128 case Ijk_TInval: { 3129 HReg r = iselWordExpr_R(env, next); 3130 MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64)); 3131 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk)); 3132 return; 3133 } 3134 default: 3135 break; 3136 } 3137 3138 vex_printf( "\n-- PUT(%d) = ", offsIP); 3139 ppIRExpr( next ); 3140 vex_printf( "; exit-"); 3141 ppIRJumpKind(jk); 3142 vex_printf( "\n"); 3143 vassert(0); // are we expecting any other kind? 3144 } 3145 3146 /*---------------------------------------------------------*/ 3147 /*--- Insn selector top-level ---*/ 3148 /*---------------------------------------------------------*/ 3149 3150 /* Translate an entire BB to mips code. */ 3151 HInstrArray *iselSB_MIPS ( IRSB* bb, 3152 VexArch arch_host, 3153 VexArchInfo* archinfo_host, 3154 VexAbiInfo* vbi, 3155 Int offs_Host_EvC_Counter, 3156 Int offs_Host_EvC_FailAddr, 3157 Bool chainingAllowed, 3158 Bool addProfInc, 3159 Addr64 max_ga ) 3160 { 3161 Int i, j; 3162 HReg hreg, hregHI; 3163 ISelEnv* env; 3164 UInt hwcaps_host = archinfo_host->hwcaps; 3165 MIPSAMode *amCounter, *amFailAddr; 3166 3167 /* sanity ... */ 3168 vassert(arch_host == VexArchMIPS32); 3169 vassert(VEX_PRID_COMP_MIPS == hwcaps_host 3170 || VEX_PRID_COMP_BROADCOM == hwcaps_host); 3171 3172 mode64 = arch_host != VexArchMIPS32; 3173 3174 /* Make up an initial environment to use. */ 3175 env = LibVEX_Alloc(sizeof(ISelEnv)); 3176 env->vreg_ctr = 0; 3177 env->mode64 = mode64; 3178 3179 /* Set up output code array. */ 3180 env->code = newHInstrArray(); 3181 3182 /* Copy BB's type env. */ 3183 env->type_env = bb->tyenv; 3184 3185 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 3186 change as we go along. */ 3187 env->n_vregmap = bb->tyenv->types_used; 3188 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); 3189 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); 3190 3191 /* and finally ... */ 3192 env->hwcaps = hwcaps_host; 3193 env->chainingAllowed = chainingAllowed; 3194 env->hwcaps = hwcaps_host; 3195 env->max_ga = max_ga; 3196 3197 /* For each IR temporary, allocate a suitably-kinded virtual 3198 register. */ 3199 j = 0; 3200 for (i = 0; i < env->n_vregmap; i++) { 3201 hregHI = hreg = INVALID_HREG; 3202 switch (bb->tyenv->types[i]) { 3203 case Ity_I1: 3204 case Ity_I8: 3205 case Ity_I16: 3206 case Ity_I32: { 3207 hreg = mkHReg(j++, HRcInt32, True); 3208 break; 3209 } 3210 case Ity_I64: { 3211 hreg = mkHReg(j++, HRcInt32, True); 3212 hregHI = mkHReg(j++, HRcInt32, True); 3213 break; 3214 } 3215 case Ity_I128: 3216 vassert(mode64); 3217 hreg = mkHReg(j++, HRcInt64, True); 3218 hregHI = mkHReg(j++, HRcInt64, True); 3219 break; 3220 case Ity_F32: { 3221 hreg = mkHReg(j++, HRcFlt32, True); 3222 break; 3223 } 3224 case Ity_F64: 3225 hreg = mkHReg(j++, HRcFlt64, True); 3226 break; 3227 default: 3228 ppIRType(bb->tyenv->types[i]); 3229 vpanic("iselBB(mips): IRTemp type"); 3230 } 3231 env->vregmap[i] = hreg; 3232 env->vregmapHI[i] = hregHI; 3233 } 3234 env->vreg_ctr = j; 3235 3236 /* The very first instruction must be an event check. */ 3237 amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, hregMIPS_GPR10(mode64)); 3238 amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, hregMIPS_GPR10(mode64)); 3239 addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr)); 3240 3241 /* Possibly a block counter increment (for profiling). At this 3242 point we don't know the address of the counter, so just pretend 3243 it is zero. It will have to be patched later, but before this 3244 translation is used, by a call to LibVEX_patchProfCtr. */ 3245 if (addProfInc) { 3246 addInstr(env, MIPSInstr_ProfInc()); 3247 } 3248 3249 /* Ok, finally we can iterate over the statements. */ 3250 for (i = 0; i < bb->stmts_used; i++) 3251 iselStmt(env, bb->stmts[i]); 3252 3253 iselNext(env, bb->next, bb->jumpkind, bb->offsIP); 3254 3255 /* record the number of vregs we used. */ 3256 env->code->n_vregs = env->vreg_ctr; 3257 return env->code; 3258 3259 } 3260 3261 /*---------------------------------------------------------------*/ 3262 /*--- end host_mips_isel.c ---*/ 3263 /*---------------------------------------------------------------*/ 3264