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-2013 RT-RK 11 mips-valgrind@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_generic_simd64.h" /* for 64-bit SIMD helpers */ 39#include "host_mips_defs.h" 40 41/*---------------------------------------------------------*/ 42/*--- Register Usage Conventions ---*/ 43/*---------------------------------------------------------*/ 44 45/* Integer Regs 46 ------------ 47 ZERO0 Reserved 48 GPR12:22 Allocateable 49 23 GuestStatePointer 50 SP StackFramePointer 51 RA LinkRegister */ 52 53static Bool mode64 = False; 54 55/* Host CPU has FPU and 32 dbl. prec. FP registers. */ 56static Bool fp_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/* guest_COND offset */ 65#define COND_OFFSET(_mode64) ((_mode64) ? 612 : 448) 66 67/*---------------------------------------------------------*/ 68/*--- ISelEnv ---*/ 69/*---------------------------------------------------------*/ 70 71/* This carries around: 72 73 - A mapping from IRTemp to IRType, giving the type of any IRTemp we 74 might encounter. This is computed before insn selection starts, 75 and does not change. 76 77 - A mapping from IRTemp to HReg. This tells the insn selector 78 which virtual register(s) are associated with each IRTemp 79 temporary. This is computed before insn selection starts, and 80 does not change. We expect this mapping to map precisely the 81 same set of IRTemps as the type mapping does. 82 83 - vregmap holds the primary register for the IRTemp. 84 - vregmapHI is only used for 64-bit integer-typed 85 IRTemps. It holds the identity of a second 86 32-bit virtual HReg, which holds the high half 87 of the value. 88 89 - The code array, that is, the insns selected so far. 90 91 - A counter, for generating new virtual registers. 92 93 - The host subarchitecture we are selecting insns for. 94 This is set at the start and does not change. 95 96 - A Bool for indicating whether we may generate chain-me 97 instructions for control flow transfers, or whether we must use 98 XAssisted. 99 100 - The maximum guest address of any guest insn in this block. 101 Actually, the address of the highest-addressed byte from any insn 102 in this block. Is set at the start and does not change. This is 103 used for detecting jumps which are definitely forward-edges from 104 this block, and therefore can be made (chained) to the fast entry 105 point of the destination, thereby avoiding the destination's 106 event check. 107 108 Note, this is all (well, mostly) host-independent. 109*/ 110 111typedef 112 struct { 113 /* Constant -- are set at the start and do not change. */ 114 IRTypeEnv* type_env; 115 116 HReg* vregmap; 117 HReg* vregmapHI; 118 Int n_vregmap; 119 120 UInt hwcaps; 121 Bool mode64; 122 Bool fp_mode64; 123 124 Bool chainingAllowed; 125 Addr64 max_ga; 126 127 /* These are modified as we go along. */ 128 HInstrArray* code; 129 Int vreg_ctr; 130 } 131 ISelEnv; 132 133static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp) 134{ 135 vassert(tmp >= 0); 136 vassert(tmp < env->n_vregmap); 137 return env->vregmap[tmp]; 138} 139 140static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp) 141{ 142 vassert(tmp >= 0); 143 vassert(tmp < env->n_vregmap); 144 vassert(! hregIsInvalid(env->vregmapHI[tmp])); 145 *vrLO = env->vregmap[tmp]; 146 *vrHI = env->vregmapHI[tmp]; 147} 148 149static void 150lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp) 151{ 152 vassert(env->mode64); 153 vassert(tmp >= 0); 154 vassert(tmp < env->n_vregmap); 155 vassert(! hregIsInvalid(env->vregmapHI[tmp])); 156 *vrLO = env->vregmap[tmp]; 157 *vrHI = env->vregmapHI[tmp]; 158} 159 160static void addInstr(ISelEnv * env, MIPSInstr * instr) 161{ 162 addHInstr(env->code, instr); 163 if (vex_traceflags & VEX_TRACE_VCODE) { 164 ppMIPSInstr(instr, mode64); 165 vex_printf("\n"); 166 } 167} 168 169static HReg newVRegI(ISelEnv * env) 170{ 171 HReg reg = mkHReg(True/*virtual reg*/, 172 HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr); 173 env->vreg_ctr++; 174 return reg; 175} 176 177static HReg newVRegD(ISelEnv * env) 178{ 179 HReg reg = mkHReg(True/*virtual reg*/, 180 HRcFlt64, 0/*enc*/, env->vreg_ctr); 181 env->vreg_ctr++; 182 return reg; 183} 184 185static HReg newVRegF(ISelEnv * env) 186{ 187 HReg reg = mkHReg(True/*virtual reg*/, 188 HRcFPR(env->mode64), 0/*enc*/, env->vreg_ctr); 189 env->vreg_ctr++; 190 return reg; 191} 192 193static void add_to_sp(ISelEnv * env, UInt n) 194{ 195 HReg sp = StackPointer(mode64); 196 vassert(n < 256 && (n % 8) == 0); 197 if (mode64) 198 addInstr(env, MIPSInstr_Alu(Malu_DADD, sp, sp, MIPSRH_Imm(True, 199 toUShort(n)))); 200 else 201 addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True, 202 toUShort(n)))); 203} 204 205static void sub_from_sp(ISelEnv * env, UInt n) 206{ 207 HReg sp = StackPointer(mode64); 208 vassert(n < 256 && (n % 8) == 0); 209 if (mode64) 210 addInstr(env, MIPSInstr_Alu(Malu_DSUB, sp, sp, 211 MIPSRH_Imm(True, toUShort(n)))); 212 else 213 addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp, 214 MIPSRH_Imm(True, toUShort(n)))); 215} 216 217/*---------------------------------------------------------*/ 218/*--- ISEL: Forward declarations ---*/ 219/*---------------------------------------------------------*/ 220 221/* These are organised as iselXXX and iselXXX_wrk pairs. The 222 iselXXX_wrk do the real work, but are not to be called directly. 223 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then 224 checks that all returned registers are virtual. You should not 225 call the _wrk version directly. 226*/ 227/* 32-bit mode: Compute an I8/I16/I32 into a RH 228 (reg-or-halfword-immediate). 229 It's important to specify whether the immediate is to be regarded 230 as signed or not. If yes, this will never return -32768 as an 231 immediate; this guaranteed that all signed immediates that are 232 return can have their sign inverted if need be. 233*/ 234static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e); 235static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e); 236 237/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an 238 immediate in the range 1 .. 31 inclusive. Used for doing shift amounts. */ 239static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e); 240static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e); 241 242/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an 243 immediate in the range 1 .. 63 inclusive. Used for doing shift amounts. */ 244static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e); 245static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e); 246 247/* compute an I8/I16/I32 into a GPR*/ 248static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e); 249static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e); 250 251/* compute an I32 into an AMode. */ 252static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e, 253 IRType xferTy); 254static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy); 255 256static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, 257 IRExpr * e); 258static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e); 259 260/* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */ 261static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, 262 ISelEnv * env, IRExpr * e); 263static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e); 264 265static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e); 266static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e); 267 268static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e); 269static HReg iselDblExpr(ISelEnv * env, IRExpr * e); 270 271static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e); 272static HReg iselFltExpr(ISelEnv * env, IRExpr * e); 273 274static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode) 275{ 276 /* 277 rounding mode | MIPS | IR 278 ------------------------ 279 to nearest | 00 | 00 280 to zero | 01 | 11 281 to +infinity | 10 | 10 282 to -infinity | 11 | 01 283 */ 284 /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 2 */ 285 HReg irrm = iselWordExpr_R(env, mode); 286 HReg tmp = newVRegI(env); 287 HReg fcsr_old = newVRegI(env); 288 MIPSAMode *am_addr; 289 290 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm, 291 MIPSRH_Imm(False, 1))); 292 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp))); 293 addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, MIPSRH_Imm(False, 3))); 294 /* save old value of FCSR */ 295 addInstr(env, MIPSInstr_MfFCSR(fcsr_old)); 296 sub_from_sp(env, 8); /* Move SP down 8 bytes */ 297 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 298 299 /* store old FCSR to stack */ 300 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64)); 301 302 /* set new value of FCSR */ 303 addInstr(env, MIPSInstr_MtFCSR(irrm)); 304} 305 306static void set_MIPS_rounding_default(ISelEnv * env) 307{ 308 HReg fcsr = newVRegI(env); 309 /* load as float */ 310 MIPSAMode *am_addr; 311 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 312 313 addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64)); 314 315 add_to_sp(env, 8); /* Reset SP */ 316 317 /* set new value of FCSR*/ 318 addInstr(env, MIPSInstr_MtFCSR(fcsr)); 319} 320 321/*---------------------------------------------------------*/ 322/*--- ISEL: Misc helpers ---*/ 323/*---------------------------------------------------------*/ 324 325/* Make an int reg-reg move. */ 326static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src) 327{ 328 vassert(hregClass(r_dst) == hregClass(r_src)); 329 vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64); 330 return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src)); 331} 332 333/*---------------------------------------------------------*/ 334/*--- ISEL: Function call helpers ---*/ 335/*---------------------------------------------------------*/ 336 337/* Used only in doHelperCall. See big comment in doHelperCall re 338 handling of register-parameter args. This function figures out 339 whether evaluation of an expression might require use of a fixed 340 register. If in doubt return True (safe but suboptimal). 341*/ 342static Bool mightRequireFixedRegs(IRExpr * e) 343{ 344 switch (e->tag) { 345 case Iex_RdTmp: 346 case Iex_Const: 347 case Iex_Get: 348 return False; 349 default: 350 return True; 351 } 352} 353 354/* Load 2*I32 regs to fp reg */ 355static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo) 356{ 357 HReg fr_dst = newVRegD(env); 358 MIPSAMode *am_addr0, *am_addr1; 359 360 vassert(hregClass(r_srcHi) == HRcInt32); 361 vassert(hregClass(r_srcLo) == HRcInt32); 362 363 sub_from_sp(env, 16); /* Move SP down 16 bytes */ 364 am_addr0 = MIPSAMode_IR(0, StackPointer(mode64)); 365 am_addr1 = MIPSAMode_IR(4, StackPointer(mode64)); 366 367 /* store hi,lo as Ity_I32's */ 368#if defined (_MIPSEL) 369 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64)); 370 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64)); 371#elif defined (_MIPSEB) 372 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcHi, mode64)); 373 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcLo, mode64)); 374#else 375 /* Stop gcc on other platforms complaining about am_addr1 being set 376 but not used. */ 377 (void)am_addr1; 378#endif 379 380 /* load as float */ 381 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0)); 382 383 add_to_sp(env, 16); /* Reset SP */ 384 return fr_dst; 385} 386 387/* Do a complete function call. |guard| is a Ity_Bit expression 388 indicating whether or not the call happens. If guard==NULL, the 389 call is unconditional. |retloc| is set to indicate where the 390 return value is after the call. The caller (of this fn) must 391 generate code to add |stackAdjustAfterCall| to the stack pointer 392 after the call is done. */ 393 394static void doHelperCall(/*OUT*/UInt* stackAdjustAfterCall, 395 /*OUT*/RetLoc* retloc, 396 ISelEnv* env, 397 IRExpr* guard, 398 IRCallee* cee, IRType retTy, IRExpr** args ) 399{ 400 MIPSCondCode cc; 401 HReg argregs[MIPS_N_REGPARMS]; 402 HReg tmpregs[MIPS_N_REGPARMS]; 403 Bool go_fast; 404 Int n_args, i, argreg; 405 UInt argiregs; 406 HReg src = INVALID_HREG; 407 408 /* Set default returns. We'll update them later if needed. */ 409 *stackAdjustAfterCall = 0; 410 *retloc = mk_RetLoc_INVALID(); 411 412 /* These are used for cross-checking that IR-level constraints on 413 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */ 414 UInt nVECRETs = 0; 415 UInt nBBPTRs = 0; 416 417 /* MIPS O32 calling convention: up to four registers ($a0 ... $a3) 418 are allowed to be used for passing integer arguments. They correspond 419 to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless 420 on MIPS host (since we only implement one calling convention) and so we 421 always ignore it. */ 422 423 /* MIPS 64 calling convention: up to four registers ($a0 ... $a7) 424 are allowed to be used for passing integer arguments. They correspond 425 to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless 426 on MIPS host (since we only implement one calling convention) and so we 427 always ignore it. */ 428 429 /* The return type can be I{64,32,16,8} or V{128,256}. In the 430 latter two cases, it is expected that |args| will contain the 431 special node IRExpr_VECRET(), in which case this routine 432 generates code to allocate space on the stack for the vector 433 return value. Since we are not passing any scalars on the 434 stack, it is enough to preallocate the return space before 435 marshalling any arguments, in this case. 436 437 |args| may also contain IRExpr_BBPTR(), in which case the value 438 in the guest state pointer register is passed as the 439 corresponding argument. */ 440 441 n_args = 0; 442 for (i = 0; args[i]; i++) { 443 IRExpr* arg = args[i]; 444 if (UNLIKELY(arg->tag == Iex_VECRET)) { 445 nVECRETs++; 446 } else if (UNLIKELY(arg->tag == Iex_BBPTR)) { 447 nBBPTRs++; 448 } 449 n_args++; 450 } 451 452 if (n_args > MIPS_N_REGPARMS) { 453 vpanic("doHelperCall(MIPS): cannot currently handle > 4 or 8 args"); 454 } 455 if (mode64) { 456 argregs[0] = hregMIPS_GPR4(mode64); 457 argregs[1] = hregMIPS_GPR5(mode64); 458 argregs[2] = hregMIPS_GPR6(mode64); 459 argregs[3] = hregMIPS_GPR7(mode64); 460 argregs[4] = hregMIPS_GPR8(mode64); 461 argregs[5] = hregMIPS_GPR9(mode64); 462 argregs[6] = hregMIPS_GPR10(mode64); 463 argregs[7] = hregMIPS_GPR11(mode64); 464 argiregs = 0; 465 tmpregs[0] = tmpregs[1] = tmpregs[2] = 466 tmpregs[3] = tmpregs[4] = tmpregs[5] = 467 tmpregs[6] = tmpregs[7] = INVALID_HREG; 468 } else { 469 argregs[0] = hregMIPS_GPR4(mode64); 470 argregs[1] = hregMIPS_GPR5(mode64); 471 argregs[2] = hregMIPS_GPR6(mode64); 472 argregs[3] = hregMIPS_GPR7(mode64); 473 argiregs = 0; 474 tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG; 475 } 476 477 /* First decide which scheme (slow or fast) is to be used. First assume the 478 fast scheme, and select slow if any contraindications (wow) appear. */ 479 480 go_fast = True; 481 482 /* We'll need space on the stack for the return value. Avoid 483 possible complications with nested calls by using the slow 484 scheme. */ 485 if (retTy == Ity_V128 || retTy == Ity_V256) 486 go_fast = False; 487 488 if (go_fast && guard) { 489 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1 490 && guard->Iex.Const.con->Ico.U1 == True) { 491 /* unconditional */ 492 } else { 493 /* Not manifestly unconditional -- be conservative. */ 494 go_fast = False; 495 } 496 } 497 498 if (go_fast) { 499 for (i = 0; i < n_args; i++) { 500 if (mightRequireFixedRegs(args[i])) { 501 go_fast = False; 502 break; 503 } 504 } 505 } 506 507 /* At this point the scheme to use has been established. Generate 508 code to get the arg values into the argument rregs. */ 509 if (go_fast) { 510 /* FAST SCHEME */ 511 argreg = 0; 512 513 for (i = 0; i < n_args; i++) { 514 IRExpr* arg = args[i]; 515 vassert(argreg < MIPS_N_REGPARMS); 516 517 IRType aTy = Ity_INVALID; 518 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg))) 519 aTy = typeOfIRExpr(env->type_env, arg); 520 521 if (aTy == Ity_I32 || mode64) { 522 argiregs |= (1 << (argreg + 4)); 523 addInstr(env, mk_iMOVds_RR(argregs[argreg], 524 iselWordExpr_R(env, arg))); 525 argreg++; 526 } else if (aTy == Ity_I64) { /* Ity_I64 */ 527 if (argreg & 1) { 528 argreg++; 529 argiregs |= (1 << (argreg + 4)); 530 } 531 HReg rHi, rLo; 532 iselInt64Expr(&rHi, &rLo, env, arg); 533 argiregs |= (1 << (argreg + 4)); 534 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi )); 535 argiregs |= (1 << (argreg + 4)); 536 addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo)); 537 argreg++; 538 } else if (arg->tag == Iex_BBPTR) { 539 vassert(0); // ATC 540 addInstr(env, mk_iMOVds_RR(argregs[argreg], 541 GuestStatePointer(mode64))); 542 argreg++; 543 } else if (arg->tag == Iex_VECRET) { 544 // If this happens, it denotes ill-formed IR. 545 vassert(0); 546 } 547 } 548 /* Fast scheme only applies for unconditional calls. Hence: */ 549 cc = MIPScc_AL; 550 } else { 551 /* SLOW SCHEME; move via temporaries */ 552 argreg = 0; 553 554 for (i = 0; i < n_args; i++) { 555 vassert(argreg < MIPS_N_REGPARMS); 556 IRExpr* arg = args[i]; 557 558 IRType aTy = Ity_INVALID; 559 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg))) 560 aTy = typeOfIRExpr(env->type_env, arg); 561 562 if (aTy == Ity_I32 || (mode64 && arg->tag != Iex_BBPTR)) { 563 tmpregs[argreg] = iselWordExpr_R(env, arg); 564 argreg++; 565 } else if (aTy == Ity_I64) { /* Ity_I64 */ 566 if (argreg & 1) 567 argreg++; 568 if (argreg + 1 >= MIPS_N_REGPARMS) 569 vassert(0); /* out of argregs */ 570 HReg raHi, raLo; 571 iselInt64Expr(&raHi, &raLo, env, arg); 572 tmpregs[argreg] = raLo; 573 argreg++; 574 tmpregs[argreg] = raHi; 575 argreg++; 576 } else if (arg->tag == Iex_BBPTR) { 577 tmpregs[argreg] = GuestStatePointer(mode64); 578 argreg++; 579 } 580 else if (arg->tag == Iex_VECRET) { 581 // If this happens, it denotes ill-formed IR 582 vassert(0); 583 } 584 } 585 586 /* Now we can compute the condition. We can't do it earlier 587 because the argument computations could trash the condition 588 codes. Be a bit clever to handle the common case where the 589 guard is 1:Bit. */ 590 cc = MIPScc_AL; 591 if (guard) { 592 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1 593 && guard->Iex.Const.con->Ico.U1 == True) { 594 /* unconditional -- do nothing */ 595 } else { 596 cc = iselCondCode(env, guard); 597 src = iselWordExpr_R(env, guard); 598 } 599 } 600 /* Move the args to their final destinations. */ 601 for (i = 0; i < argreg; i++) { 602 if (hregIsInvalid(tmpregs[i])) /* Skip invalid regs */ 603 continue; 604 /* None of these insns, including any spill code that might 605 be generated, may alter the condition codes. */ 606 argiregs |= (1 << (i + 4)); 607 addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i])); 608 } 609 } 610 611 /* Do final checks, set the return values, and generate the call 612 instruction proper. */ 613 vassert(nBBPTRs == 0 || nBBPTRs == 1); 614 vassert(nVECRETs == (retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0); 615 vassert(*stackAdjustAfterCall == 0); 616 vassert(is_RetLoc_INVALID(*retloc)); 617 switch (retTy) { 618 case Ity_INVALID: 619 /* Function doesn't return a value. */ 620 *retloc = mk_RetLoc_simple(RLPri_None); 621 break; 622 case Ity_I64: 623 *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int); 624 break; 625 case Ity_I32: case Ity_I16: case Ity_I8: 626 *retloc = mk_RetLoc_simple(RLPri_Int); 627 break; 628 case Ity_V128: 629 vassert(0); // ATC 630 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0); 631 *stackAdjustAfterCall = 16; 632 break; 633 case Ity_V256: 634 vassert(0); // ATC 635 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0); 636 *stackAdjustAfterCall = 32; 637 break; 638 default: 639 /* IR can denote other possible return types, but we don't 640 handle those here. */ 641 vassert(0); 642 } 643 644 Addr64 target = mode64 ? (Addr)cee->addr : 645 toUInt((Addr)cee->addr); 646 647 /* Finally, generate the call itself. This needs the *retloc value 648 set in the switch above, which is why it's at the end. */ 649 if (cc == MIPScc_AL) 650 addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs, 651 *retloc)); 652 else 653 addInstr(env, MIPSInstr_Call(cc, target, argiregs, src, *retloc)); 654} 655 656/*---------------------------------------------------------*/ 657/*--- ISEL: Integer expression auxiliaries ---*/ 658/*---------------------------------------------------------*/ 659 660/* --------------------- AMODEs --------------------- */ 661 662/* Return an AMode which computes the value of the specified 663 expression, possibly also adding insns to the code list as a 664 result. The expression may only be a word-size one. 665*/ 666 667static Bool uInt_fits_in_16_bits(UInt u) 668{ 669 Int i = u & 0xFFFF; 670 i <<= 16; 671 i >>= 16; 672 return toBool(u == (UInt) i); 673} 674 675static Bool uLong_fits_in_16_bits ( ULong u ) 676{ 677 Long i = u & 0xFFFFULL; 678 i <<= 48; 679 i >>= 48; 680 return toBool(u == (ULong) i); 681} 682 683static Bool uLong_is_4_aligned ( ULong u ) 684{ 685 return toBool((u & 3ULL) == 0); 686} 687 688static Bool sane_AMode(ISelEnv * env, MIPSAMode * am) 689{ 690 switch (am->tag) { 691 case Mam_IR: 692 return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) && 693 hregIsVirtual(am->Mam.IR.base) && 694 uInt_fits_in_16_bits(am->Mam.IR.index)); 695 case Mam_RR: 696 return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) && 697 hregIsVirtual(am->Mam.RR.base) && 698 hregClass(am->Mam.RR.index) == HRcGPR(mode64) && 699 hregIsVirtual(am->Mam.RR.index)); 700 default: 701 vpanic("sane_AMode: unknown mips amode tag"); 702 } 703} 704 705static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy) 706{ 707 MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy); 708 vassert(sane_AMode(env, am)); 709 return am; 710} 711 712/* DO NOT CALL THIS DIRECTLY ! */ 713static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e, 714 IRType xferTy) 715{ 716 IRType ty = typeOfIRExpr(env->type_env, e); 717 if (env->mode64) { 718 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64); 719 vassert(ty == Ity_I64); 720 721 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */ 722 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64 723 && e->Iex.Binop.arg2->tag == Iex_Const 724 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64 725 && (aligned4imm ? 726 uLong_is_4_aligned(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64) : True) 727 && uLong_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) { 728 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U64, 729 iselWordExpr_R(env, e->Iex.Binop.arg1)); 730 } 731 732 /* Add64(expr,expr) */ 733 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64) { 734 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1); 735 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2); 736 return MIPSAMode_RR(r_idx, r_base); 737 } 738 } else { 739 vassert(ty == Ity_I32); 740 741 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */ 742 if (e->tag == Iex_Binop 743 && e->Iex.Binop.op == Iop_Add32 744 && e->Iex.Binop.arg2->tag == Iex_Const 745 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32 746 && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) { 747 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, 748 iselWordExpr_R(env, e->Iex.Binop.arg1)); 749 } 750 751 /* Add32(expr,expr) */ 752 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) { 753 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1); 754 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2); 755 756 return MIPSAMode_RR(r_idx, r_base); 757 } 758 } 759 760 /* Doesn't match anything in particular. Generate it into 761 a register and use that. */ 762 return MIPSAMode_IR(0, iselWordExpr_R(env, e)); 763} 764 765/*---------------------------------------------------------*/ 766/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/ 767/*---------------------------------------------------------*/ 768 769/* Select insns for an integer-typed expression, and add them to the 770 code list. Return a reg holding the result. This reg will be a 771 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you 772 want to modify it, ask for a new vreg, copy it in there, and modify 773 the copy. The register allocator will do its best to map both 774 vregs to the same real register, so the copies will often disappear 775 later in the game. 776 777 This should handle expressions of 64, 32, 16 and 8-bit type. 778 All results are returned in a (mode64 ? 64bit : 32bit) register. 779 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits 780 are arbitrary, so you should mask or sign extend partial values 781 if necessary. 782*/ 783static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e) 784{ 785 HReg r = iselWordExpr_R_wrk(env, e); 786 /* sanity checks ... */ 787 788 vassert(hregClass(r) == HRcGPR(env->mode64)); 789 vassert(hregIsVirtual(r)); 790 return r; 791} 792 793/* DO NOT CALL THIS DIRECTLY ! */ 794static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e) 795{ 796 UInt argiregs = 0; 797 IRType ty = typeOfIRExpr(env->type_env, e); 798 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1 799 || ty == Ity_F32 || (ty == Ity_I64 && mode64) 800 || (ty == Ity_I128 && mode64)); 801 802 switch (e->tag) { 803 /* --------- TEMP --------- */ 804 case Iex_RdTmp: 805 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 806 807 /* --------- LOAD --------- */ 808 case Iex_Load: { 809 HReg r_dst = newVRegI(env); 810 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty); 811 812 if (e->Iex.Load.end != Iend_LE 813 && e->Iex.Load.end != Iend_BE) 814 goto irreducible; 815 816 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), 817 r_dst, am_addr, mode64)); 818 return r_dst; 819 } 820 821 /* --------- BINARY OP --------- */ 822 case Iex_Binop: { 823 MIPSAluOp aluOp; 824 MIPSShftOp shftOp; 825 826 /* Is it an addition or logical style op? */ 827 switch (e->Iex.Binop.op) { 828 case Iop_Add8: 829 case Iop_Add16: 830 case Iop_Add32: 831 aluOp = Malu_ADD; 832 break; 833 834 case Iop_Sub8: 835 case Iop_Sub16: 836 case Iop_Sub32: 837 aluOp = Malu_SUB; 838 break; 839 840 case Iop_Sub64: 841 aluOp = Malu_DSUB; 842 break; 843 844 case Iop_And8: 845 case Iop_And16: 846 case Iop_And32: 847 case Iop_And64: 848 aluOp = Malu_AND; 849 break; 850 851 case Iop_Or8: 852 case Iop_Or16: 853 case Iop_Or32: 854 case Iop_Or64: 855 aluOp = Malu_OR; 856 break; 857 858 case Iop_Xor8: 859 case Iop_Xor16: 860 case Iop_Xor32: 861 case Iop_Xor64: 862 aluOp = Malu_XOR; 863 break; 864 865 case Iop_Add64: 866 aluOp = Malu_DADD; 867 break; 868 869 default: 870 aluOp = Malu_INVALID; 871 break; 872 } 873 874 /* For commutative ops we assume any literal 875 values are on the second operand. */ 876 if (aluOp != Malu_INVALID) { 877 HReg r_dst = newVRegI(env); 878 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 879 MIPSRH *ri_srcR = NULL; 880 /* get right arg into an RH, in the appropriate way */ 881 switch (aluOp) { 882 case Malu_ADD: 883 case Malu_SUB: 884 case Malu_DADD: 885 case Malu_DSUB: 886 ri_srcR = iselWordExpr_RH(env, True /*signed */ , 887 e->Iex.Binop.arg2); 888 break; 889 case Malu_AND: 890 case Malu_OR: 891 case Malu_XOR: 892 ri_srcR = iselWordExpr_RH(env, False /*unsigned */, 893 e->Iex.Binop.arg2); 894 break; 895 default: 896 vpanic("iselWordExpr_R_wrk-aluOp-arg2"); 897 } 898 addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR)); 899 return r_dst; 900 } 901 902 /* a shift? */ 903 switch (e->Iex.Binop.op) { 904 case Iop_Shl32: 905 case Iop_Shl64: 906 shftOp = Mshft_SLL; 907 break; 908 case Iop_Shr32: 909 case Iop_Shr64: 910 shftOp = Mshft_SRL; 911 break; 912 case Iop_Sar32: 913 case Iop_Sar64: 914 shftOp = Mshft_SRA; 915 break; 916 default: 917 shftOp = Mshft_INVALID; 918 break; 919 } 920 921 /* we assume any literal values are on the second operand. */ 922 if (shftOp != Mshft_INVALID) { 923 HReg r_dst = newVRegI(env); 924 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 925 MIPSRH *ri_srcR; 926 if (mode64) 927 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); 928 else 929 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); 930 931 if (ty == Ity_I8) { 932 vassert(0); 933 } else if (ty == Ity_I32) { 934 if (mode64 && (shftOp == Mshft_SRA || shftOp == Mshft_SRL)) { 935 HReg tmp = newVRegI(env); 936 HReg r_srcL_se = newVRegI(env); 937 /* SRA, SRAV, SRL, SRLV: On 64-bit processors, if GPR rt does 938 not contain a sign-extended 32-bit value (bits 63..31 939 equal), then the result of the operation is UNPREDICTABLE. 940 So we need to sign-extend r_srcL: 941 DSLLV tmp, r_srcL, 32 942 DSRAV r_srcL_se, tmp, 32 943 */ 944 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tmp, 945 r_srcL, MIPSRH_Imm(False, 32))); 946 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, r_srcL_se, 947 tmp, MIPSRH_Imm(False, 32))); 948 /* And finally do the shift. */ 949 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */, 950 r_dst, r_srcL_se, ri_srcR)); 951 } else 952 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */, 953 r_dst, r_srcL, ri_srcR)); 954 } else if (ty == Ity_I64) { 955 vassert(mode64); 956 addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */, 957 r_dst, r_srcL, ri_srcR)); 958 } else 959 goto irreducible; 960 return r_dst; 961 } 962 963 /* Cmp*32*(x,y) ? */ 964 if (e->Iex.Binop.op == Iop_CmpEQ32 965 || e->Iex.Binop.op == Iop_CmpEQ16 966 || e->Iex.Binop.op == Iop_CmpNE32 967 || e->Iex.Binop.op == Iop_CmpNE64 968 || e->Iex.Binop.op == Iop_CmpLT32S 969 || e->Iex.Binop.op == Iop_CmpLT32U 970 || e->Iex.Binop.op == Iop_CmpLT64U 971 || e->Iex.Binop.op == Iop_CmpLE32U 972 || e->Iex.Binop.op == Iop_CmpLE32S 973 || e->Iex.Binop.op == Iop_CmpLE64S 974 || e->Iex.Binop.op == Iop_CmpLT64S 975 || e->Iex.Binop.op == Iop_CmpEQ64 976 || e->Iex.Binop.op == Iop_CasCmpEQ32 977 || e->Iex.Binop.op == Iop_CasCmpEQ64) { 978 979 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S 980 || e->Iex.Binop.op == Iop_CmpLE32S 981 || e->Iex.Binop.op == Iop_CmpLT64S 982 || e->Iex.Binop.op == Iop_CmpLE64S); 983 Bool size32; 984 HReg dst = newVRegI(env); 985 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 986 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2); 987 988 MIPSCondCode cc; 989 990 switch (e->Iex.Binop.op) { 991 case Iop_CmpEQ32: 992 case Iop_CasCmpEQ32: 993 cc = MIPScc_EQ; 994 size32 = True; 995 break; 996 case Iop_CmpEQ16: 997 cc = MIPScc_EQ; 998 size32 = True; 999 break; 1000 case Iop_CmpNE32: 1001 cc = MIPScc_NE; 1002 size32 = True; 1003 break; 1004 case Iop_CmpNE64: 1005 cc = MIPScc_NE; 1006 size32 = True; 1007 break; 1008 case Iop_CmpLT32S: 1009 cc = MIPScc_LT; 1010 size32 = True; 1011 break; 1012 case Iop_CmpLT32U: 1013 cc = MIPScc_LO; 1014 size32 = True; 1015 break; 1016 case Iop_CmpLT64U: 1017 cc = MIPScc_LO; 1018 size32 = False; 1019 break; 1020 case Iop_CmpLE32U: 1021 cc = MIPScc_LE; 1022 size32 = True; 1023 break; 1024 case Iop_CmpLE32S: 1025 cc = MIPScc_LE; 1026 size32 = True; 1027 break; 1028 case Iop_CmpLE64S: 1029 cc = MIPScc_LE; 1030 size32 = False; 1031 break; 1032 case Iop_CmpLT64S: 1033 cc = MIPScc_LT; 1034 size32 = False; 1035 break; 1036 case Iop_CmpEQ64: 1037 case Iop_CasCmpEQ64: 1038 cc = MIPScc_EQ; 1039 size32 = False; 1040 break; 1041 default: 1042 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64"); 1043 } 1044 1045 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc)); 1046 return dst; 1047 } 1048 1049 if (e->Iex.Binop.op == Iop_Max32U) { 1050 HReg tmp = newVRegI(env); 1051 HReg r_dst = newVRegI(env); 1052 HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1053 HReg argR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1054 MIPSRH *argRH = iselWordExpr_RH(env, False /*signed */ , 1055 e->Iex.Binop.arg2); 1056 /* max (v0, s0) 1057 ------------ 1058 slt v1, v0, s0 1059 movn v0, s0, v1 */ 1060 1061 addInstr(env, MIPSInstr_Alu(Malu_SLT, tmp, argL, argRH)); 1062 addInstr(env, mk_iMOVds_RR(r_dst, argL)); 1063 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, argR, tmp)); 1064 return r_dst; 1065 } 1066 1067 if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) { 1068 Bool sz32 = (e->Iex.Binop.op == Iop_Mul32); 1069 HReg r_dst = newVRegI(env); 1070 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1071 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1072 addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ , 1073 False /*widen */ , 1074 sz32 /*32bit or 64bit */, 1075 r_dst, r_srcL, r_srcR)); 1076 return r_dst; 1077 } 1078 1079 if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) { 1080 HReg r_dst = newVRegI(env); 1081 HReg tHi = newVRegI(env); 1082 HReg tLo = newVRegI(env); 1083 HReg tLo_1 = newVRegI(env); 1084 HReg tHi_1 = newVRegI(env); 1085 HReg mask = newVRegI(env); 1086 1087 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32); 1088 Bool size = toBool(e->Iex.Binop.op == Iop_MullS32) 1089 || toBool(e->Iex.Binop.op == Iop_MullU32); 1090 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1091 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1092 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ , 1093 True /*widen */ , 1094 size /*32bit or 64bit mul */ , 1095 r_dst, r_srcL, r_srcR)); 1096 1097 addInstr(env, MIPSInstr_Mfhi(tHi)); 1098 addInstr(env, MIPSInstr_Mflo(tLo)); 1099 1100 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, 1101 tHi, MIPSRH_Imm(False, 32))); 1102 1103 addInstr(env, MIPSInstr_LI(mask, 0xffffffff)); 1104 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 1105 MIPSRH_Reg(mask))); 1106 1107 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 1108 MIPSRH_Reg(tLo_1))); 1109 1110 return r_dst; 1111 } 1112 1113 if (e->Iex.Binop.op == Iop_CmpF64) { 1114 HReg r_srcL, r_srcR; 1115 if (mode64) { 1116 r_srcL = iselFltExpr(env, e->Iex.Binop.arg1); 1117 r_srcR = iselFltExpr(env, e->Iex.Binop.arg2); 1118 } else { 1119 r_srcL = iselDblExpr(env, e->Iex.Binop.arg1); 1120 r_srcR = iselDblExpr(env, e->Iex.Binop.arg2); 1121 } 1122 HReg tmp = newVRegI(env); 1123 HReg r_ccMIPS = newVRegI(env); 1124 HReg r_ccIR = newVRegI(env); 1125 HReg r_ccIR_b0 = newVRegI(env); 1126 HReg r_ccIR_b2 = newVRegI(env); 1127 HReg r_ccIR_b6 = newVRegI(env); 1128 1129 /* Create in dst, the IRCmpF64Result encoded result. */ 1130 /* chech for EQ */ 1131 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmp, r_srcL, r_srcR)); 1132 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccMIPS, tmp, 1133 MIPSRH_Imm(False, 1))); 1134 /* chech for UN */ 1135 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmp, r_srcL, r_srcR)); 1136 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS, 1137 MIPSRH_Reg(tmp))); 1138 /* chech for LT */ 1139 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmp, r_srcL, r_srcR)); 1140 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, 1141 tmp, MIPSRH_Imm(False, 2))); 1142 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS, 1143 MIPSRH_Reg(tmp))); 1144 /* chech for GT */ 1145 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_NGT, 1146 tmp, r_srcL, r_srcR)); 1147 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, tmp, 1148 MIPSRH_Imm(False, 3))); 1149 1150 addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp))); 1151 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, 1152 MIPSRH_Imm(False, 8))); 1153 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS, 1154 MIPSRH_Reg(tmp))); 1155 /* Map compare result from MIPS to IR, 1156 conforming to CmpF64 definition. 1157 FP cmp result | MIPS | IR 1158 -------------------------- 1159 UN | 0x1 | 0x45 1160 EQ | 0x2 | 0x40 1161 GT | 0x4 | 0x00 1162 LT | 0x8 | 0x01 1163 */ 1164 1165 /* r_ccIR_b0 = r_ccMIPS[0] | r_ccMIPS[3] */ 1166 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS, 1167 MIPSRH_Imm(False, 0x3))); 1168 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS, 1169 MIPSRH_Reg(r_ccIR_b0))); 1170 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0, 1171 MIPSRH_Imm(False, 0x1))); 1172 1173 /* r_ccIR_b2 = r_ccMIPS[0] */ 1174 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS, 1175 MIPSRH_Imm(False, 0x2))); 1176 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2, 1177 MIPSRH_Imm(False, 0x4))); 1178 1179 /* r_ccIR_b6 = r_ccMIPS[0] | r_ccMIPS[1] */ 1180 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6, 1181 r_ccMIPS, MIPSRH_Imm(False, 0x1))); 1182 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS, 1183 MIPSRH_Reg(r_ccIR_b6))); 1184 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6, 1185 MIPSRH_Imm(False, 0x6))); 1186 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6, 1187 MIPSRH_Imm(False, 0x40))); 1188 1189 /* r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 */ 1190 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0, 1191 MIPSRH_Reg(r_ccIR_b2))); 1192 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR, 1193 MIPSRH_Reg(r_ccIR_b6))); 1194 return r_ccIR; 1195 } 1196 1197 if (e->Iex.Binop.op == Iop_DivModU64to32 || 1198 e->Iex.Binop.op == Iop_DivModS64to32) { 1199 HReg tLo = newVRegI(env); 1200 HReg tHi = newVRegI(env); 1201 HReg mask = newVRegI(env); 1202 HReg tLo_1 = newVRegI(env); 1203 HReg tHi_1 = newVRegI(env); 1204 HReg r_dst = newVRegI(env); 1205 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32); 1206 1207 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1208 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1209 1210 addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR)); 1211 addInstr(env, MIPSInstr_Mfhi(tHi)); 1212 addInstr(env, MIPSInstr_Mflo(tLo)); 1213 1214 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi, 1215 MIPSRH_Imm(False, 32))); 1216 1217 addInstr(env, MIPSInstr_LI(mask, 0xffffffff)); 1218 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 1219 MIPSRH_Reg(mask))); 1220 1221 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 1222 MIPSRH_Reg(tLo_1))); 1223 1224 return r_dst; 1225 } 1226 1227 if (e->Iex.Binop.op == Iop_8HLto16 1228 || e->Iex.Binop.op == Iop_16HLto32) { 1229 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 1230 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 1231 HReg tLo_1 = newVRegI(env); 1232 HReg tHi_1 = newVRegI(env); 1233 HReg r_dst = newVRegI(env); 1234 UInt shift = 0; 1235 UInt mask = 0; 1236 switch (e->Iex.Binop.op) { 1237 case Iop_8HLto16: 1238 shift = 8; 1239 mask = 0xff; 1240 break; 1241 case Iop_16HLto32: 1242 shift = 16; 1243 mask = 0xffff; 1244 break; 1245 default: 1246 break; 1247 } 1248 1249 /* sll tHi_1, tHi, shift 1250 and tLo_1, tLo, mask 1251 or r_dst, tHi_1, tLo_1 */ 1252 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi, 1253 MIPSRH_Imm(False, shift))); 1254 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 1255 MIPSRH_Imm(False, mask))); 1256 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 1257 MIPSRH_Reg(tLo_1))); 1258 return r_dst; 1259 } 1260 1261 if (e->Iex.Binop.op == Iop_32HLto64) { 1262 vassert(mode64); 1263 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 1264 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 1265 HReg tLo_1 = newVRegI(env); 1266 HReg tHi_1 = newVRegI(env); 1267 HReg r_dst = newVRegI(env); 1268 HReg mask = newVRegI(env); 1269 1270 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi, 1271 MIPSRH_Imm(False, 32))); 1272 1273 addInstr(env, MIPSInstr_LI(mask, 0xffffffff)); 1274 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo, 1275 MIPSRH_Reg(mask))); 1276 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1, 1277 MIPSRH_Reg(tLo_1))); 1278 1279 return r_dst; 1280 } 1281 1282 if (e->Iex.Binop.op == Iop_F32toI64S) { 1283 vassert(mode64); 1284 HReg valS = newVRegI(env); 1285 HReg tmpF = newVRegF(env); 1286 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); 1287 1288 /* CVTLS tmpF, valF */ 1289 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 1290 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpF, valF)); 1291 set_MIPS_rounding_default(env); 1292 1293 /* Doubleword Move from Floating Point 1294 dmfc1 valS, tmpF */ 1295 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF)); 1296 1297 return valS; 1298 } 1299 1300 if (e->Iex.Binop.op == Iop_F64toI32S) { 1301 HReg valD; 1302 if (mode64) 1303 valD = iselFltExpr(env, e->Iex.Binop.arg2); 1304 else 1305 valD = iselDblExpr(env, e->Iex.Binop.arg2); 1306 HReg valS = newVRegF(env); 1307 HReg r_dst = newVRegI(env); 1308 1309 /* CVTWD valS, valD */ 1310 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 1311 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD)); 1312 set_MIPS_rounding_default(env); 1313 1314 /* Move Word From Floating Point 1315 mfc1 r_dst, valS */ 1316 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS)); 1317 1318 return r_dst; 1319 } 1320 1321 /* -------- DSP ASE -------- */ 1322 /* All used cases involving host-side helper calls. */ 1323 void* fn = NULL; 1324 switch (e->Iex.Binop.op) { 1325 case Iop_HAdd8Ux4: 1326 fn = &h_generic_calc_HAdd8Ux4; break; 1327 case Iop_HSub8Ux4: 1328 fn = &h_generic_calc_HSub8Ux4; break; 1329 case Iop_HSub16Sx2: 1330 fn = &h_generic_calc_HSub16Sx2; break; 1331 case Iop_QSub8Ux4: 1332 fn = &h_generic_calc_QSub8Ux4; break; 1333 default: 1334 break; 1335 } 1336 1337 /* What's the retloc? */ 1338 RetLoc rloc = mk_RetLoc_INVALID(); 1339 if (ty == Ity_I32) { 1340 rloc = mk_RetLoc_simple(RLPri_Int); 1341 } 1342 else if (ty == Ity_I64) { 1343 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) : 1344 mk_RetLoc_simple(RLPri_2Int); 1345 } 1346 else { 1347 goto irreducible; 1348 } 1349 1350 if (fn) { 1351 HReg regL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1352 HReg regR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1353 HReg res = newVRegI(env); 1354 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL)); 1355 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR5(env->mode64), regR)); 1356 argiregs |= (1 << 4); 1357 argiregs |= (1 << 5); 1358 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL, 1359 (Addr)fn, 1360 argiregs, rloc)); 1361 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64))); 1362 return res; 1363 } 1364 break; 1365 } 1366 1367 /* --------- UNARY OP --------- */ 1368 case Iex_Unop: { 1369 IROp op_unop = e->Iex.Unop.op; 1370 1371 switch (op_unop) { 1372 case Iop_1Sto8: 1373 case Iop_1Sto16: 1374 case Iop_1Sto32: 1375 case Iop_8Sto16: 1376 case Iop_8Sto32: 1377 case Iop_16Sto32: 1378 case Iop_16Sto64: 1379 case Iop_8Sto64: 1380 case Iop_1Sto64: { 1381 HReg r_dst = newVRegI(env); 1382 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1383 Bool sz32; 1384 UShort amt; 1385 switch (op_unop) { 1386 case Iop_1Sto8: 1387 amt = 31; 1388 sz32 = True; 1389 break; 1390 case Iop_1Sto16: 1391 amt = 31; 1392 sz32 = True; 1393 break; 1394 case Iop_1Sto32: 1395 amt = 31; 1396 sz32 = True; 1397 break; 1398 case Iop_16Sto32: 1399 amt = 16; 1400 sz32 = True; 1401 break; 1402 case Iop_16Sto64: 1403 amt = 48; 1404 sz32 = False; 1405 break; 1406 case Iop_8Sto16: 1407 amt = 24; 1408 sz32 = True; 1409 break; 1410 case Iop_8Sto32: 1411 amt = 24; 1412 sz32 = True; 1413 break; 1414 case Iop_8Sto64: 1415 amt = 56; 1416 sz32 = False; 1417 break; 1418 case Iop_1Sto64: 1419 amt = 63; 1420 sz32 = False; 1421 break; 1422 default: 1423 vassert(0); 1424 } 1425 1426 addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src, 1427 MIPSRH_Imm(False, amt))); 1428 addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst, 1429 MIPSRH_Imm(False, amt))); 1430 return r_dst; 1431 } 1432 1433 /* not(x) = nor(x,x) */ 1434 case Iop_Not1: { 1435 HReg r_dst = newVRegI(env); 1436 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg); 1437 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL); 1438 1439 addInstr(env, MIPSInstr_LI(r_dst, 0x1)); 1440 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR)); 1441 return r_dst; 1442 } 1443 1444 case Iop_Not8: 1445 case Iop_Not16: 1446 case Iop_Not32: 1447 case Iop_Not64: { 1448 HReg r_dst = newVRegI(env); 1449 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg); 1450 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL); 1451 1452 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR)); 1453 return r_dst; 1454 } 1455 1456 case Iop_ReinterpF32asI32: { 1457 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg); 1458 HReg r_dst = newVRegI(env); 1459 1460 /* Move Word From Floating Point 1461 mfc1 r_dst, fr_src */ 1462 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, fr_src)); 1463 1464 return r_dst; 1465 } 1466 1467 case Iop_ReinterpF64asI64: { 1468 vassert(mode64); 1469 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg); 1470 HReg r_dst = newVRegI(env); 1471 1472 /* Doubleword Move from Floating Point 1473 mfc1 r_dst, fr_src */ 1474 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, r_dst, fr_src)); 1475 1476 return r_dst; 1477 } 1478 1479 case Iop_F64toI32S: { 1480 HReg valD; 1481 if (mode64) 1482 valD = iselFltExpr(env, e->Iex.Binop.arg2); 1483 else 1484 valD = iselDblExpr(env, e->Iex.Binop.arg2); 1485 HReg valS = newVRegF(env); 1486 HReg r_dst = newVRegI(env); 1487 1488 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 1489 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD)); 1490 set_MIPS_rounding_default(env); 1491 1492 /* Move Word From Floating Point 1493 mfc1 r_dst, valS */ 1494 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS)); 1495 1496 return r_dst; 1497 } 1498 1499 case Iop_16to8: 1500 case Iop_32to1: 1501 case Iop_32to8: 1502 case Iop_32to16: 1503 return iselWordExpr_R(env, e->Iex.Unop.arg); 1504 1505 case Iop_32HIto16: { 1506 HReg r_dst = newVRegI(env); 1507 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1508 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 1509 r_dst, r_src, MIPSRH_Imm(False, 16))); 1510 return r_dst; 1511 } 1512 1513 case Iop_64to1: 1514 case Iop_64to8: { 1515 vassert(mode64); 1516 HReg r_src, r_dst; 1517 UShort mask = (op_unop == Iop_64to1) ? 0x1 : 0xFF; 1518 r_dst = newVRegI(env); 1519 r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1520 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src, 1521 MIPSRH_Imm(False, mask))); 1522 return r_dst; 1523 } 1524 1525 case Iop_16HIto8: { 1526 HReg r_dst = newVRegI(env); 1527 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1528 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 1529 r_dst, r_src, MIPSRH_Imm(False, 8))); 1530 return r_dst; 1531 } 1532 1533 case Iop_1Uto8: 1534 case Iop_1Uto32: 1535 case Iop_1Uto64: 1536 case Iop_8Uto16: 1537 case Iop_8Uto32: 1538 case Iop_8Uto64: 1539 case Iop_16Uto32: 1540 case Iop_16Uto64: { 1541 HReg r_dst = newVRegI(env); 1542 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1543 UShort mask = 0; 1544 switch (op_unop) { 1545 case Iop_1Uto64: 1546 vassert(mode64); 1547 case Iop_1Uto8: 1548 case Iop_1Uto32: 1549 mask = toUShort(0x1); 1550 break; 1551 case Iop_8Uto64: 1552 vassert(mode64); 1553 case Iop_8Uto16: 1554 case Iop_8Uto32: 1555 mask = toUShort(0xFF); 1556 break; 1557 case Iop_16Uto64: 1558 vassert(mode64); 1559 case Iop_16Uto32: 1560 mask = toUShort(0xFFFF); 1561 break; 1562 default: 1563 vassert(0); 1564 break; 1565 } 1566 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src, 1567 MIPSRH_Imm(False, mask))); 1568 return r_dst; 1569 } 1570 1571 case Iop_32Uto64: { 1572 HReg r_dst = newVRegI(env); 1573 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1574 vassert(mode64); 1575 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False /*!32bit shift */, 1576 r_dst, r_src, MIPSRH_Imm(False, 32))); 1577 addInstr(env, MIPSInstr_Shft(Mshft_SRL, False /*!32bit shift */, 1578 r_dst, r_dst, MIPSRH_Imm(False, 32))); 1579 return r_dst; 1580 } 1581 1582 case Iop_64HIto32: { 1583 if (env->mode64) { 1584 HReg r_dst = newVRegI(env); 1585 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1586 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False /*64bit shift */, 1587 r_dst, r_src, MIPSRH_Imm(True, 32))); 1588 return r_dst; 1589 } else { 1590 HReg rHi, rLo; 1591 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1592 return rHi; 1593 } 1594 } 1595 1596 case Iop_64to32: { 1597 if (env->mode64) { 1598 HReg r_dst = newVRegI(env); 1599 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg); 1600 return r_dst; 1601 } else { 1602 HReg rHi, rLo; 1603 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1604 return rLo; 1605 } 1606 } 1607 1608 case Iop_64to16: { 1609 vassert(env->mode64); 1610 HReg r_dst = newVRegI(env); 1611 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg); 1612 return r_dst; 1613 } 1614 1615 case Iop_32Sto64: { 1616 HReg r_dst = newVRegI(env); 1617 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1618 vassert(mode64); 1619 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*!32bit shift */, 1620 r_dst, r_src, MIPSRH_Imm(True, 0))); 1621 return r_dst; 1622 } 1623 1624 case Iop_CmpNEZ8: 1625 case Iop_CmpNEZ16: { 1626 HReg r_dst = newVRegI(env); 1627 HReg tmp = newVRegI(env); 1628 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1629 UShort mask = (op_unop == Iop_CmpNEZ8) ? 0xFF : 0xFFFF; 1630 1631 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src, 1632 MIPSRH_Imm(False, mask))); 1633 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp, 1634 hregMIPS_GPR0(mode64), MIPScc_NE)); 1635 return r_dst; 1636 } 1637 1638 case Iop_CmpNEZ32: { 1639 HReg r_dst = newVRegI(env); 1640 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1641 1642 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src, 1643 hregMIPS_GPR0(mode64), MIPScc_NE)); 1644 return r_dst; 1645 } 1646 1647 case Iop_CmpwNEZ32: { 1648 HReg r_dst = newVRegI(env); 1649 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1650 1651 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64), 1652 MIPSRH_Reg(r_src))); 1653 1654 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst, 1655 MIPSRH_Reg(r_src))); 1656 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst, 1657 MIPSRH_Imm(False, 31))); 1658 return r_dst; 1659 } 1660 1661 case Iop_Left8: 1662 case Iop_Left16: 1663 case Iop_Left32: 1664 case Iop_Left64: { 1665 if (op_unop == Iop_Left64 && !mode64) 1666 goto irreducible; 1667 HReg r_dst = newVRegI(env); 1668 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1669 MIPSAluOp op = (op_unop == Iop_Left64) ? Malu_DSUB : Malu_SUB; 1670 addInstr(env, MIPSInstr_Alu(op, r_dst, 1671 hregMIPS_GPR0(mode64), 1672 MIPSRH_Reg(r_src))); 1673 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst, 1674 MIPSRH_Reg(r_src))); 1675 return r_dst; 1676 } 1677 1678 case Iop_Clz64: 1679 vassert(mode64); 1680 case Iop_Clz32: { 1681 HReg r_dst = newVRegI(env); 1682 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1683 MIPSUnaryOp op = (op_unop == Iop_Clz64) ? Mun_DCLZ : Mun_CLZ; 1684 addInstr(env, MIPSInstr_Unary(op, r_dst, r_src)); 1685 return r_dst; 1686 } 1687 1688 case Iop_CmpNEZ64: { 1689 HReg hi, lo; 1690 HReg r_dst = newVRegI(env); 1691 HReg r_src; 1692 if (env->mode64) { 1693 r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1694 } else { 1695 r_src = newVRegI(env); 1696 iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg); 1697 addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi))); 1698 } 1699 addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src, 1700 hregMIPS_GPR0(mode64), MIPScc_NE)); 1701 return r_dst; 1702 } 1703 1704 case Iop_CmpwNEZ64: { 1705 HReg tmp1; 1706 HReg tmp2 = newVRegI(env); 1707 vassert(env->mode64); 1708 tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg); 1709 1710 addInstr(env, MIPSInstr_Alu(Malu_DSUB, tmp2, hregMIPS_GPR0(mode64), 1711 MIPSRH_Reg(tmp1))); 1712 1713 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1))); 1714 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2, 1715 MIPSRH_Imm (False, 63))); 1716 return tmp2; 1717 } 1718 1719 case Iop_128HIto64: { 1720 vassert(mode64); 1721 HReg rHi, rLo; 1722 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1723 return rHi; /* and abandon rLo .. poor wee thing :-) */ 1724 } 1725 1726 case Iop_128to64: { 1727 vassert(mode64); 1728 HReg rHi, rLo; 1729 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg); 1730 return rLo; /* and abandon rLo .. poor wee thing :-) */ 1731 } 1732 1733 default: 1734 break; 1735 } 1736 1737 /* -------- DSP ASE -------- */ 1738 /* All Unop cases involving host-side helper calls. */ 1739 void* fn = NULL; 1740 switch (e->Iex.Unop.op) { 1741 case Iop_CmpNEZ16x2: 1742 fn = &h_generic_calc_CmpNEZ16x2; break; 1743 case Iop_CmpNEZ8x4: 1744 fn = &h_generic_calc_CmpNEZ8x4; break; 1745 default: 1746 break; 1747 } 1748 1749 RetLoc rloc = mk_RetLoc_INVALID(); 1750 if (ty == Ity_I32) { 1751 rloc = mk_RetLoc_simple(RLPri_Int); 1752 } 1753 else if (ty == Ity_I64) { 1754 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) : 1755 mk_RetLoc_simple(RLPri_2Int); 1756 } 1757 else { 1758 goto irreducible; 1759 } 1760 1761 if (fn) { 1762 HReg regL = iselWordExpr_R(env, e->Iex.Unop.arg); 1763 HReg res = newVRegI(env); 1764 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL)); 1765 argiregs |= (1 << 4); 1766 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL, 1767 (Addr)fn, 1768 argiregs, rloc)); 1769 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64))); 1770 return res; 1771 } 1772 1773 break; 1774 } 1775 1776 /* --------- GET --------- */ 1777 case Iex_Get: { 1778 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 1779 || ((ty == Ity_I64) && mode64)) { 1780 HReg r_dst = newVRegI(env); 1781 1782 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 1783 GuestStatePointer(mode64)); 1784 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr, 1785 mode64)); 1786 return r_dst; 1787 } 1788 break; 1789 } 1790 1791 /* --------- ITE --------- */ 1792 case Iex_ITE: { 1793 if ((ty == Ity_I8 || ty == Ity_I16 || 1794 ty == Ity_I32 || ((ty == Ity_I64))) && 1795 typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) { 1796 HReg r_dst = iselWordExpr_R(env, e->Iex.ITE.iffalse); 1797 HReg r1 = iselWordExpr_R(env, e->Iex.ITE.iftrue); 1798 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond); 1799 /* 1800 * r_dst = r0 1801 * movn r_dst, r1, r_cond 1802 */ 1803 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, r1, r_cond)); 1804 return r_dst; 1805 } 1806 break; 1807 } 1808 1809 /* --------- LITERAL --------- */ 1810 /* 32/16/8-bit literals */ 1811 case Iex_Const: { 1812 Long l; 1813 HReg r_dst = newVRegI(env); 1814 IRConst *con = e->Iex.Const.con; 1815 switch (con->tag) { 1816 case Ico_U64: 1817 if (!mode64) 1818 goto irreducible; 1819 l = (Long) con->Ico.U64; 1820 break; 1821 case Ico_U32: 1822 l = (Long) (Int) con->Ico.U32; 1823 break; 1824 case Ico_U16: 1825 l = (Long) (Int) (Short) con->Ico.U16; 1826 break; 1827 case Ico_U8: 1828 l = (Long) (Int) (Char) con->Ico.U8; 1829 break; 1830 default: 1831 vpanic("iselIntExpr_R.const(mips)"); 1832 } 1833 addInstr(env, MIPSInstr_LI(r_dst, (ULong) l)); 1834 return r_dst; 1835 } 1836 1837 /* --------- CCALL --------- */ 1838 case Iex_CCall: { 1839 HReg r_dst = newVRegI(env); 1840 vassert(ty == e->Iex.CCall.retty); 1841 1842 /* be very restrictive for now. Only 32/64-bit ints allowed for 1843 args, and 64 and 32 bits for return type. Don't forget to change 1844 the RetLoc if more return types are allowed in future. */ 1845 if (e->Iex.CCall.retty != Ity_I64 && e->Iex.CCall.retty != Ity_I32) 1846 goto irreducible; 1847 1848 /* Marshal args, do the call, clear stack. */ 1849 UInt addToSp = 0; 1850 RetLoc rloc = mk_RetLoc_INVALID(); 1851 doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee, 1852 e->Iex.CCall.retty, e->Iex.CCall.args ); 1853 1854 vassert(is_sane_RetLoc(rloc)); 1855 vassert(rloc.pri == RLPri_Int); 1856 vassert(addToSp == 0); 1857 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64))); 1858 return r_dst; 1859 } 1860 1861 default: 1862 break; 1863 } /* end switch(e->tag) */ 1864 1865 /* We get here if no pattern matched. */ 1866 irreducible: 1867 vex_printf("--------------->\n"); 1868 if (e->tag == Iex_RdTmp) 1869 vex_printf("Iex_RdTmp \n"); 1870 ppIRExpr(e); 1871 1872 vpanic("iselWordExpr_R(mips): cannot reduce tree"); 1873} 1874 1875/* --------------------- RH --------------------- */ 1876 1877/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH 1878 (reg-or-halfword-immediate). It's important to specify whether the 1879 immediate is to be regarded as signed or not. If yes, this will 1880 never return -32768 as an immediate; this guaranteed that all 1881 signed immediates that are return can have their sign inverted if 1882 need be. */ 1883 1884static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e) 1885{ 1886 MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e); 1887 /* sanity checks ... */ 1888 switch (ri->tag) { 1889 case Mrh_Imm: 1890 vassert(ri->Mrh.Imm.syned == syned); 1891 if (syned) 1892 vassert(ri->Mrh.Imm.imm16 != 0x8000); 1893 return ri; 1894 case Mrh_Reg: 1895 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64)); 1896 vassert(hregIsVirtual(ri->Mrh.Reg.reg)); 1897 return ri; 1898 default: 1899 vpanic("iselIntExpr_RH: unknown mips RH tag"); 1900 } 1901} 1902 1903/* DO NOT CALL THIS DIRECTLY ! */ 1904static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e) 1905{ 1906 ULong u; 1907 Long l; 1908 IRType ty = typeOfIRExpr(env->type_env, e); 1909 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || 1910 ((ty == Ity_I64) && env->mode64)); 1911 1912 /* special case: immediate */ 1913 if (e->tag == Iex_Const) { 1914 IRConst *con = e->Iex.Const.con; 1915 /* What value are we aiming to generate? */ 1916 switch (con->tag) { 1917 /* Note: Not sign-extending - we carry 'syned' around */ 1918 case Ico_U64: 1919 vassert(env->mode64); 1920 u = con->Ico.U64; 1921 break; 1922 case Ico_U32: 1923 u = 0xFFFFFFFF & con->Ico.U32; 1924 break; 1925 case Ico_U16: 1926 u = 0x0000FFFF & con->Ico.U16; 1927 break; 1928 case Ico_U8: 1929 u = 0x000000FF & con->Ico.U8; 1930 break; 1931 default: 1932 vpanic("iselIntExpr_RH.Iex_Const(mips)"); 1933 } 1934 l = (Long) u; 1935 /* Now figure out if it's representable. */ 1936 if (!syned && u <= 65535) { 1937 return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF)); 1938 } 1939 if (syned && l >= -32767 && l <= 32767) { 1940 return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF)); 1941 } 1942 /* no luck; use the Slow Way. */ 1943 } 1944 /* default case: calculate into a register and return that */ 1945 return MIPSRH_Reg(iselWordExpr_R(env, e)); 1946} 1947 1948/* --------------------- RH5u --------------------- */ 1949 1950/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter 1951 being an immediate in the range 1 .. 31 inclusive. Used for doing 1952 shift amounts. */ 1953 1954static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e) 1955{ 1956 MIPSRH *ri; 1957 ri = iselWordExpr_RH5u_wrk(env, e); 1958 /* sanity checks ... */ 1959 switch (ri->tag) { 1960 case Mrh_Imm: 1961 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31); 1962 vassert(!ri->Mrh.Imm.syned); 1963 return ri; 1964 case Mrh_Reg: 1965 vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32); 1966 vassert(hregIsVirtual(ri->Mrh.Reg.reg)); 1967 return ri; 1968 default: 1969 vpanic("iselIntExpr_RH5u: unknown mips RH tag"); 1970 } 1971} 1972 1973/* DO NOT CALL THIS DIRECTLY ! */ 1974static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e) 1975{ 1976 IRType ty = typeOfIRExpr(env->type_env, e); 1977 vassert(ty == Ity_I8); 1978 1979 /* special case: immediate */ 1980 if (e->tag == Iex_Const 1981 && e->Iex.Const.con->tag == Ico_U8 1982 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) { 1983 return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8); 1984 } 1985 1986 /* default case: calculate into a register and return that */ 1987 return MIPSRH_Reg(iselWordExpr_R(env, e)); 1988} 1989 1990/* --------------------- RH6u --------------------- */ 1991 1992/* Only used in 64-bit mode. */ 1993static MIPSRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e ) 1994{ 1995 MIPSRH *ri; 1996 ri = iselWordExpr_RH6u_wrk(env, e); 1997 /* sanity checks ... */ 1998 switch (ri->tag) { 1999 case Mrh_Imm: 2000 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 63); 2001 vassert(!ri->Mrh.Imm.syned); 2002 return ri; 2003 case Mrh_Reg: 2004 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64)); 2005 vassert(hregIsVirtual(ri->Mrh.Reg.reg)); 2006 return ri; 2007 default: 2008 vpanic("iselIntExpr_RH6u: unknown mips64 RI tag"); 2009 } 2010} 2011 2012/* DO NOT CALL THIS DIRECTLY ! */ 2013static MIPSRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e ) 2014{ 2015 IRType ty = typeOfIRExpr(env->type_env, e); 2016 vassert(ty == Ity_I8); 2017 2018 /* special case: immediate */ 2019 if (e->tag == Iex_Const 2020 && e->Iex.Const.con->tag == Ico_U8 2021 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 63) 2022 { 2023 return MIPSRH_Imm(False /*unsigned */ , 2024 e->Iex.Const.con->Ico.U8); 2025 } 2026 2027 /* default case: calculate into a register and return that */ 2028 return MIPSRH_Reg(iselWordExpr_R(env, e)); 2029} 2030 2031/* --------------------- CONDCODE --------------------- */ 2032 2033/* Generate code to evaluated a bit-typed expression, returning the 2034 condition code which would correspond when the expression would 2035 notionally have returned 1. */ 2036 2037static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e) 2038{ 2039 MIPSCondCode cc = iselCondCode_wrk(env,e); 2040 vassert(cc != MIPScc_NV); 2041 return cc; 2042} 2043 2044/* DO NOT CALL THIS DIRECTLY ! */ 2045static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e) 2046{ 2047 vassert(e); 2048 vassert(typeOfIRExpr(env->type_env, e) == Ity_I1); 2049 /* Cmp*32*(x,y) ? */ 2050 if (e->Iex.Binop.op == Iop_CmpEQ32 2051 || e->Iex.Binop.op == Iop_CmpNE32 2052 || e->Iex.Binop.op == Iop_CmpNE64 2053 || e->Iex.Binop.op == Iop_CmpLT32S 2054 || e->Iex.Binop.op == Iop_CmpLT32U 2055 || e->Iex.Binop.op == Iop_CmpLT64U 2056 || e->Iex.Binop.op == Iop_CmpLE32S 2057 || e->Iex.Binop.op == Iop_CmpLE64S 2058 || e->Iex.Binop.op == Iop_CmpLT64S 2059 || e->Iex.Binop.op == Iop_CmpEQ64 2060 || e->Iex.Binop.op == Iop_CasCmpEQ32 2061 || e->Iex.Binop.op == Iop_CasCmpEQ64) { 2062 2063 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S 2064 || e->Iex.Binop.op == Iop_CmpLE32S 2065 || e->Iex.Binop.op == Iop_CmpLT64S 2066 || e->Iex.Binop.op == Iop_CmpLE64S); 2067 Bool size32; 2068 HReg dst = newVRegI(env); 2069 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 2070 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2); 2071 2072 MIPSCondCode cc; 2073 2074 switch (e->Iex.Binop.op) { 2075 case Iop_CmpEQ32: 2076 case Iop_CasCmpEQ32: 2077 cc = MIPScc_EQ; 2078 size32 = True; 2079 break; 2080 case Iop_CmpNE32: 2081 cc = MIPScc_NE; 2082 size32 = True; 2083 break; 2084 case Iop_CmpNE64: 2085 cc = MIPScc_NE; 2086 size32 = True; 2087 break; 2088 case Iop_CmpLT32S: 2089 cc = MIPScc_LT; 2090 size32 = True; 2091 break; 2092 case Iop_CmpLT32U: 2093 cc = MIPScc_LO; 2094 size32 = True; 2095 break; 2096 case Iop_CmpLT64U: 2097 cc = MIPScc_LO; 2098 size32 = False; 2099 break; 2100 case Iop_CmpLE32S: 2101 cc = MIPScc_LE; 2102 size32 = True; 2103 break; 2104 case Iop_CmpLE64S: 2105 cc = MIPScc_LE; 2106 size32 = False; 2107 break; 2108 case Iop_CmpLT64S: 2109 cc = MIPScc_LT; 2110 size32 = False; 2111 break; 2112 case Iop_CmpEQ64: 2113 case Iop_CasCmpEQ64: 2114 cc = MIPScc_EQ; 2115 size32 = False; 2116 break; 2117 default: 2118 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64"); 2119 break; 2120 } 2121 2122 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc)); 2123 /* Store result to guest_COND */ 2124 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64)); 2125 2126 addInstr(env, MIPSInstr_Store(4, 2127 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64), 2128 am_addr->Mam.IR.base), 2129 dst, mode64)); 2130 return cc; 2131 } 2132 if (e->Iex.Binop.op == Iop_Not1) { 2133 HReg r_dst = newVRegI(env); 2134 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg); 2135 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL); 2136 2137 addInstr(env, MIPSInstr_LI(r_dst, 0x1)); 2138 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR)); 2139 /* Store result to guest_COND */ 2140 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64)); 2141 2142 addInstr(env, MIPSInstr_Store(4, 2143 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64), 2144 am_addr->Mam.IR.base), 2145 r_dst, mode64)); 2146 return MIPScc_NE; 2147 } 2148 if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) { 2149 HReg r_dst = iselWordExpr_R_wrk(env, e); 2150 /* Store result to guest_COND */ 2151 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64)); 2152 2153 addInstr(env, MIPSInstr_Store(4, 2154 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64), 2155 am_addr->Mam.IR.base), 2156 r_dst, mode64)); 2157 return MIPScc_EQ; 2158 } 2159 2160 vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag); 2161 ppIRExpr(e); 2162 vpanic("iselCondCode(mips)"); 2163} 2164 2165/*---------------------------------------------------------*/ 2166/*--- ISEL: Integer expressions (128 bit) ---*/ 2167/*---------------------------------------------------------*/ 2168 2169/* 64-bit mode ONLY: compute a 128-bit value into a register pair, 2170 which is returned as the first two parameters. As with 2171 iselWordExpr_R, these may be either real or virtual regs; in any 2172 case they must not be changed by subsequent code emitted by the 2173 caller. */ 2174 2175static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 2176{ 2177 vassert(env->mode64); 2178 iselInt128Expr_wrk(rHi, rLo, env, e); 2179 vassert(hregClass(*rHi) == HRcGPR(env->mode64)); 2180 vassert(hregIsVirtual(*rHi)); 2181 vassert(hregClass(*rLo) == HRcGPR(env->mode64)); 2182 vassert(hregIsVirtual(*rLo)); 2183} 2184 2185/* DO NOT CALL THIS DIRECTLY ! */ 2186static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, 2187 IRExpr * e) 2188{ 2189 vassert(e); 2190 vassert(typeOfIRExpr(env->type_env, e) == Ity_I128); 2191 2192 /* read 128-bit IRTemp */ 2193 if (e->tag == Iex_RdTmp) { 2194 lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp); 2195 return; 2196 } 2197 2198 /* --------- BINARY ops --------- */ 2199 if (e->tag == Iex_Binop) { 2200 switch (e->Iex.Binop.op) { 2201 /* 64 x 64 -> 128 multiply */ 2202 case Iop_MullU64: 2203 case Iop_MullS64: { 2204 HReg tLo = newVRegI(env); 2205 HReg tHi = newVRegI(env); 2206 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64); 2207 HReg r_dst = newVRegI(env); 2208 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 2209 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2210 addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ , 2211 r_dst, r_srcL, r_srcR)); 2212 addInstr(env, MIPSInstr_Mfhi(tHi)); 2213 addInstr(env, MIPSInstr_Mflo(tLo)); 2214 *rHi = tHi; 2215 *rLo = tLo; 2216 return; 2217 } 2218 2219 /* 64HLto128(e1,e2) */ 2220 case Iop_64HLto128: 2221 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 2222 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 2223 return; 2224 2225 case Iop_DivModS64to64: { 2226 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 2227 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2228 HReg tLo = newVRegI(env); 2229 HReg tHi = newVRegI(env); 2230 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64); 2231 2232 addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR)); 2233 addInstr(env, MIPSInstr_Mfhi(tHi)); 2234 addInstr(env, MIPSInstr_Mflo(tLo)); 2235 *rHi = tHi; 2236 *rLo = tLo; 2237 return; 2238 } 2239 2240 case Iop_DivModU128to64: 2241 case Iop_DivModS128to64: { 2242 vassert(mode64); 2243 HReg rHi1, rLo1; 2244 iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1); 2245 2246 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2247 HReg tLo = newVRegI(env); 2248 HReg tHi = newVRegI(env); 2249 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64); 2250 2251 addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR)); 2252 addInstr(env, MIPSInstr_Mfhi(tHi)); 2253 addInstr(env, MIPSInstr_Mflo(tLo)); 2254 *rHi = tHi; 2255 *rLo = tLo; 2256 return; 2257 } 2258 2259 default: 2260 break; 2261 } 2262 } 2263 vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag); 2264 ppIRExpr(e); 2265 vpanic("iselInt128Expr(mips64)"); 2266} 2267 2268/*---------------------------------------------------------*/ 2269/*--- ISEL: Integer expressions (64 bit) ---*/ 2270/*---------------------------------------------------------*/ 2271 2272/* 32-bit mode ONLY. Compute a 64-bit value into the register 2273 * pair HI, LO. HI and LO must not be changed by subsequent 2274 * code emitted by the caller. */ 2275 2276static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 2277{ 2278 vassert(!env->mode64); 2279 iselInt64Expr_wrk(rHi, rLo, env, e); 2280 vassert(hregClass(*rHi) == HRcInt32); 2281 vassert(hregIsVirtual(*rHi)); 2282 vassert(hregClass(*rLo) == HRcInt32); 2283 vassert(hregIsVirtual(*rLo)); 2284} 2285 2286/* DO NOT CALL THIS DIRECTLY ! */ 2287static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e) 2288{ 2289 vassert(e); 2290 vassert(typeOfIRExpr(env->type_env, e) == Ity_I64); 2291 2292 /* read 64-bit IRTemp */ 2293 if (e->tag == Iex_RdTmp) { 2294 lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp); 2295 return; 2296 } 2297 /* 64-bit load */ 2298 if (e->tag == Iex_Load) { 2299 HReg tLo = newVRegI(env); 2300 HReg tHi = newVRegI(env); 2301 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr); 2302 addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64)); 2303 addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64)); 2304 *rHi = tHi; 2305 *rLo = tLo; 2306 return; 2307 } 2308 2309 /* 64-bit literal */ 2310 if (e->tag == Iex_Const) { 2311 ULong w64 = e->Iex.Const.con->Ico.U64; 2312 UInt wHi = toUInt(w64 >> 32); 2313 UInt wLo = toUInt(w64); 2314 HReg tLo = newVRegI(env); 2315 HReg tHi = newVRegI(env); 2316 vassert(e->Iex.Const.con->tag == Ico_U64); 2317 2318 if (wLo == wHi) { 2319 /* Save a precious Int register in this special case. */ 2320 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo)); 2321 *rHi = tLo; 2322 *rLo = tLo; 2323 } else { 2324 addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi)); 2325 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo)); 2326 *rHi = tHi; 2327 *rLo = tLo; 2328 } 2329 2330 return; 2331 } 2332 2333 /* 64-bit GET */ 2334 if (e->tag == Iex_Get) { 2335 HReg tLo = newVRegI(env); 2336 HReg tHi = newVRegI(env); 2337 2338 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 2339 GuestStatePointer(mode64)); 2340 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64)); 2341 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64)); 2342 *rHi = tHi; 2343 *rLo = tLo; 2344 return; 2345 } 2346 2347 /* 64-bit ITE */ 2348 if (e->tag == Iex_ITE) { 2349 vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1); 2350 HReg expr0Lo, expr0Hi; 2351 HReg expr1Lo, expr1Hi; 2352 HReg desLo = newVRegI(env); 2353 HReg desHi = newVRegI(env); 2354 HReg cond = iselWordExpr_R(env, e->Iex.ITE.cond); 2355 2356 /* expr0Hi:expr0Lo = iffalse */ 2357 /* expr1Hi:expr1Lo = iftrue */ 2358 iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.ITE.iffalse); 2359 iselInt64Expr(&expr1Hi, &expr1Lo, env, e->Iex.ITE.iftrue); 2360 2361 /* move desLo, expr0Lo 2362 * move desHi, expr0Hi 2363 * movn desLo, expr1Lo, cond 2364 * movn desHi, expr1Hi, cond */ 2365 addInstr(env, mk_iMOVds_RR(desLo, expr0Lo)); 2366 addInstr(env, mk_iMOVds_RR(desHi, expr0Hi)); 2367 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desLo, expr1Lo, cond)); 2368 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desHi, expr1Hi, cond)); 2369 2370 *rHi = desHi; 2371 *rLo = desLo; 2372 return; 2373 } 2374 2375 /* --------- BINARY ops --------- */ 2376 if (e->tag == Iex_Binop) { 2377 IROp op_binop = e->Iex.Binop.op; 2378 switch (op_binop) { 2379 /* 32 x 32 -> 64 multiply */ 2380 /* Add64 */ 2381 case Iop_Add64: { 2382 HReg xLo, xHi, yLo, yHi, carryBit; 2383 2384 HReg tHi = newVRegI(env); 2385 HReg tHi1 = newVRegI(env); 2386 HReg tLo = newVRegI(env); 2387 2388 carryBit = newVRegI(env); 2389 2390 Bool size32 = True; 2391 MIPSCondCode cc = MIPScc_LO; 2392 2393 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 2394 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 2395 addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo))); 2396 2397 /* Check carry. */ 2398 addInstr(env, MIPSInstr_Cmp(False, size32, carryBit, tLo, xLo, cc)); 2399 2400 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi1, xHi, MIPSRH_Reg(yHi))); 2401 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, tHi1, 2402 MIPSRH_Reg(carryBit))); 2403 2404 *rHi = tHi; 2405 *rLo = tLo; 2406 return; 2407 } 2408 case Iop_Sub64: { 2409 HReg xLo, xHi, yLo, yHi, borrow; 2410 Bool size32 = True; 2411 MIPSCondCode cc = MIPScc_LO; 2412 2413 HReg tHi = newVRegI(env); 2414 HReg tLo = newVRegI(env); 2415 2416 borrow = newVRegI(env); 2417 2418 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 2419 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 2420 2421 addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, xLo, MIPSRH_Reg(yLo))); 2422 2423 /* Check if borrow is nedded. */ 2424 addInstr(env, MIPSInstr_Cmp(False, size32, borrow, xLo, yLo, cc)); 2425 2426 addInstr(env, MIPSInstr_Alu(Malu_ADD, yHi, yHi, 2427 MIPSRH_Reg(borrow))); 2428 addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, xHi, MIPSRH_Reg(yHi))); 2429 2430 *rHi = tHi; 2431 *rLo = tLo; 2432 return; 2433 } 2434 case Iop_MullU32: 2435 case Iop_MullS32: { 2436 HReg tLo = newVRegI(env); 2437 HReg tHi = newVRegI(env); 2438 HReg r_dst = newVRegI(env); 2439 Bool syned = toBool(op_binop == Iop_MullS32); 2440 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 2441 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2442 2443 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */, 2444 True /*widen */ , True, 2445 r_dst, r_srcL, r_srcR)); 2446 addInstr(env, MIPSInstr_Mfhi(tHi)); 2447 addInstr(env, MIPSInstr_Mflo(tLo)); 2448 *rHi = tHi; 2449 *rLo = tLo; 2450 2451 return; 2452 } 2453 case Iop_DivModS64to32: 2454 case Iop_DivModU64to32: { 2455 HReg r_sHi, r_sLo; 2456 HReg tLo = newVRegI(env); 2457 HReg tHi = newVRegI(env); 2458 Bool syned = toBool(op_binop == Iop_DivModS64to32); 2459 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2460 2461 iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1); 2462 addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR)); 2463 addInstr(env, MIPSInstr_Mfhi(tHi)); 2464 addInstr(env, MIPSInstr_Mflo(tLo)); 2465 *rHi = tHi; 2466 *rLo = tLo; 2467 2468 return; 2469 } 2470 2471 /* 32HLto64(e1,e2) */ 2472 case Iop_32HLto64: 2473 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 2474 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 2475 2476 return; 2477 /* Or64/And64/Xor64 */ 2478 case Iop_Or64: 2479 case Iop_And64: 2480 case Iop_Xor64: { 2481 HReg xLo, xHi, yLo, yHi; 2482 HReg tLo = newVRegI(env); 2483 HReg tHi = newVRegI(env); 2484 MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR : 2485 (op_binop == Iop_And64) ? Malu_AND : Malu_XOR; 2486 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 2487 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 2488 addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi))); 2489 addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo))); 2490 *rHi = tHi; 2491 *rLo = tLo; 2492 return; 2493 } 2494 2495 case Iop_Shr64: { 2496#if defined (_MIPSEL) 2497 /* 64-bit logical shift right based on what gcc generates: 2498 <shift>: 2499 nor v0, zero, a2 2500 sll a3, a1, 0x1 2501 sllv a3, a3, v0 2502 srlv v0, a0, a2 2503 srlv v1, a1, a2 2504 andi a0, a2, 0x20 2505 or v0, a3, v0 2506 movn v0, v1, a0 2507 jr ra 2508 movn v1, zero, a0 2509 */ 2510 HReg a0, a1; 2511 HReg a0tmp = newVRegI(env); 2512 HReg a2 = newVRegI(env); 2513 HReg a3 = newVRegI(env); 2514 HReg v0 = newVRegI(env); 2515 HReg v1 = newVRegI(env); 2516 HReg zero = newVRegI(env); 2517 MIPSRH *sa = NULL; 2518 2519 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1); 2520 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); 2521 2522 if (sa->tag == Mrh_Imm) { 2523 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); 2524 } 2525 else { 2526 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, 2527 MIPSRH_Imm(False, 0x3f))); 2528 } 2529 2530 addInstr(env, MIPSInstr_LI(zero, 0x00000000)); 2531 /* nor v0, zero, a2 */ 2532 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); 2533 /* sll a3, a1, 0x1 */ 2534 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2535 a3, a1, MIPSRH_Imm(False, 0x1))); 2536 /* sllv a3, a3, v0 */ 2537 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2538 a3, a3, MIPSRH_Reg(v0))); 2539 /* srlv v0, a0, a2 */ 2540 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2541 v0, a0, MIPSRH_Reg(a2))); 2542 /* srlv v1, a1, a2 */ 2543 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2544 v1, a1, MIPSRH_Reg(a2))); 2545 /* andi a0, a2, 0x20 */ 2546 addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2, 2547 MIPSRH_Imm(False, 0x20))); 2548 /* or v0, a3, v0 */ 2549 addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0))); 2550 2551 /* movn v0, v1, a0 */ 2552 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp)); 2553 /* movn v1, zero, a0 */ 2554 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, zero, a0tmp)); 2555 2556 *rHi = v1; 2557 *rLo = v0; 2558 return; 2559#elif defined (_MIPSEB) 2560 /* 64-bit logical shift right based on what gcc generates: 2561 <shift>: 2562 nor v0, zero, a2 2563 sll a3, a0, 0x1 2564 sllv a3, a3, v0 2565 srlv v1, a1, a2 2566 andi v0, a2, 0x20 2567 or v1, a3, v1 2568 srlv a2, a0, a2 2569 movn v1, a2, v0 2570 movn a2, zero, v0 2571 jr ra 2572 move v0, a2 2573 */ 2574 HReg a0, a1; 2575 HReg a2 = newVRegI(env); 2576 HReg a2tmp = newVRegI(env); 2577 HReg a3 = newVRegI(env); 2578 HReg v0 = newVRegI(env); 2579 HReg v1 = newVRegI(env); 2580 HReg zero = newVRegI(env); 2581 MIPSRH *sa = NULL; 2582 2583 iselInt64Expr(&a0, &a1, env, e->Iex.Binop.arg1); 2584 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); 2585 2586 if (sa->tag == Mrh_Imm) { 2587 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); 2588 } 2589 else { 2590 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, 2591 MIPSRH_Imm(False, 0x3f))); 2592 } 2593 2594 addInstr(env, MIPSInstr_LI(zero, 0x00000000)); 2595 /* nor v0, zero, a2 */ 2596 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); 2597 /* sll a3, a0, 0x1 */ 2598 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2599 a3, a0, MIPSRH_Imm(False, 0x1))); 2600 /* sllv a3, a3, v0 */ 2601 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2602 a3, a3, MIPSRH_Reg(v0))); 2603 /* srlv v1, a1, a2 */ 2604 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2605 v1, a1, MIPSRH_Reg(a2))); 2606 /* andi v0, a2, 0x20 */ 2607 addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2, 2608 MIPSRH_Imm(False, 0x20))); 2609 /* or v1, a3, v1 */ 2610 addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1))); 2611 /* srlv a2, a0, a2 */ 2612 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2613 a2tmp, a0, MIPSRH_Reg(a2))); 2614 2615 /* movn v1, a2, v0 */ 2616 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2tmp, v0)); 2617 /* movn a2, zero, v0 */ 2618 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2tmp, zero, v0)); 2619 /* move v0, a2 */ 2620 addInstr(env, mk_iMOVds_RR(v0, a2tmp)); 2621 2622 *rHi = v0; 2623 *rLo = v1; 2624 return; 2625#endif 2626 } 2627 2628 case Iop_Shl64: { 2629 /* 64-bit shift left based on what gcc generates: 2630 <shift>: 2631 nor v0,zero,a2 2632 srl a3,a0,0x1 2633 srlv a3,a3,v0 2634 sllv v1,a1,a2 2635 andi v0,a2,0x20 2636 or v1,a3,v1 2637 sllv a2,a0,a2 2638 movn v1,a2,v0 2639 movn a2,zero,v0 2640 jr ra 2641 move v0,a2 2642 */ 2643 HReg a0, a1; 2644 HReg a2 = newVRegI(env); 2645 HReg a3 = newVRegI(env); 2646 HReg v0 = newVRegI(env); 2647 HReg v1 = newVRegI(env); 2648 HReg zero = newVRegI(env); 2649 MIPSRH *sa = NULL; 2650 2651 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1); 2652 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); 2653 2654 if (sa->tag == Mrh_Imm) { 2655 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); 2656 } 2657 else { 2658 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, 2659 MIPSRH_Imm(False, 0x3f))); 2660 } 2661 2662 addInstr(env, MIPSInstr_LI(zero, 0x00000000)); 2663 /* nor v0, zero, a2 */ 2664 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); 2665 /* srl a3, a0, 0x1 */ 2666 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2667 a3, a0, MIPSRH_Imm(False, 0x1))); 2668 /* srlv a3, a3, v0 */ 2669 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2670 a3, a3, MIPSRH_Reg(v0))); 2671 /* sllv v1, a1, a2 */ 2672 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2673 v1, a1, MIPSRH_Reg(a2))); 2674 /* andi v0, a2, 0x20 */ 2675 addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2, 2676 MIPSRH_Imm(False, 0x20))); 2677 /* or v1, a3, v1 */ 2678 addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1))); 2679 /* sllv a2, a0, a2 */ 2680 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2681 a2, a0, MIPSRH_Reg(a2))); 2682 2683 /* movn v1, a2, v0 */ 2684 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2, v0)); 2685 /* movn a2, zero, v0 */ 2686 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2, zero, v0)); 2687 addInstr(env, mk_iMOVds_RR(v0, a2)); 2688 2689 *rHi = v1; 2690 *rLo = v0; 2691 return; 2692 } 2693 2694 case Iop_Sar64: { 2695 /* 64-bit arithmetic shift right based on what gcc generates: 2696 <shift>: 2697 nor v0, zero, a2 2698 sll a3, a1, 0x1 2699 sllv a3, a3, v0 2700 srlv v0, a0, a2 2701 srav v1, a1, a2 2702 andi a0, a2, 0x20 2703 sra a1, a1, 0x1f 2704 or v0, a3, v0 2705 movn v0, v1, a0 2706 jr ra 2707 movn v1, a1, a0 2708 */ 2709 HReg a0, a1; 2710 HReg a0tmp = newVRegI(env); 2711 HReg a1tmp = newVRegI(env); 2712 HReg a2 = newVRegI(env); 2713 HReg a3 = newVRegI(env); 2714 HReg v0 = newVRegI(env); 2715 HReg v1 = newVRegI(env); 2716 HReg zero = newVRegI(env); 2717 MIPSRH *sa = NULL; 2718 2719 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1); 2720 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); 2721 2722 if (sa->tag == Mrh_Imm) { 2723 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16)); 2724 } 2725 else { 2726 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg, 2727 MIPSRH_Imm(False, 0x3f))); 2728 } 2729 2730 addInstr(env, MIPSInstr_LI(zero, 0x00000000)); 2731 /* nor v0, zero, a2 */ 2732 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2))); 2733 /* sll a3, a1, 0x1 */ 2734 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2735 a3, a1, MIPSRH_Imm(False, 0x1))); 2736 /* sllv a3, a3, v0 */ 2737 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */, 2738 a3, a3, MIPSRH_Reg(v0))); 2739 /* srlv v0, a0, a2 */ 2740 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */, 2741 v0, a0, MIPSRH_Reg(a2))); 2742 /* srav v1, a1, a2 */ 2743 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */, 2744 v1, a1, MIPSRH_Reg(a2))); 2745 /* andi a0, a2, 0x20 */ 2746 addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2, 2747 MIPSRH_Imm(False, 0x20))); 2748 /* sra a1, a1, 0x1f */ 2749 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */, 2750 a1tmp, a1, MIPSRH_Imm(False, 0x1f))); 2751 /* or v0, a3, v0 */ 2752 addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0))); 2753 2754 /* movn v0, v1, a0 */ 2755 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp)); 2756 /* movn v1, a1, a0 */ 2757 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a1tmp, a0tmp)); 2758 2759 *rHi = v1; 2760 *rLo = v0; 2761 return; 2762 } 2763 2764 case Iop_F32toI64S: { 2765 HReg tmpD = newVRegD(env); 2766 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); 2767 HReg tLo = newVRegI(env); 2768 HReg tHi = newVRegI(env); 2769 MIPSAMode *am_addr; 2770 2771 /* CVTLS tmpD, valF */ 2772 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 2773 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF)); 2774 set_MIPS_rounding_default(env); 2775 2776 sub_from_sp(env, 16); /* Move SP down 16 bytes */ 2777 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2778 2779 /* store as F64 */ 2780 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD, 2781 am_addr)); 2782 /* load as 2xI32 */ 2783#if defined (_MIPSEL) 2784 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64)); 2785 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr), 2786 mode64)); 2787#elif defined (_MIPSEB) 2788 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64)); 2789 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr), 2790 mode64)); 2791#endif 2792 2793 /* Reset SP */ 2794 add_to_sp(env, 16); 2795 2796 *rHi = tHi; 2797 *rLo = tLo; 2798 2799 return; 2800 } 2801 2802 default: 2803 break; 2804 } 2805 } 2806 2807 /* --------- UNARY ops --------- */ 2808 if (e->tag == Iex_Unop) { 2809 switch (e->Iex.Unop.op) { 2810 case Iop_1Sto64: { 2811 HReg tLo = newVRegI(env); 2812 HReg tHi = newVRegI(env); 2813 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2814 HReg tmp = newVRegI(env); 2815 2816 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src, 2817 MIPSRH_Imm(False, 31))); 2818 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp, 2819 MIPSRH_Imm(False, 31))); 2820 2821 addInstr(env, mk_iMOVds_RR(tHi, tmp)); 2822 addInstr(env, mk_iMOVds_RR(tLo, tmp)); 2823 2824 *rHi = tHi; 2825 *rLo = tLo; 2826 return; 2827 } 2828 2829 /* 32Sto64(e) */ 2830 case Iop_32Sto64: { 2831 HReg tLo = newVRegI(env); 2832 HReg tHi = newVRegI(env); 2833 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2834 addInstr(env, mk_iMOVds_RR(tHi, src)); 2835 addInstr(env, mk_iMOVds_RR(tLo, src)); 2836 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi, 2837 MIPSRH_Imm(False, 31))); 2838 *rHi = tHi; 2839 *rLo = tLo; 2840 return; 2841 } 2842 2843 /* 8Uto64(e) */ 2844 case Iop_8Uto64: { 2845 HReg tLo = newVRegI(env); 2846 HReg tHi = newVRegI(env); 2847 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2848 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo, src, 2849 MIPSRH_Imm(False, 0xFF))); 2850 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64), 2851 MIPSRH_Reg(hregMIPS_GPR0(mode64)))); 2852 *rHi = tHi; 2853 *rLo = tLo; 2854 return; 2855 } 2856 2857 /* 32Uto64(e) */ 2858 case Iop_32Uto64: { 2859 HReg tLo = newVRegI(env); 2860 HReg tHi = newVRegI(env); 2861 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2862 addInstr(env, mk_iMOVds_RR(tLo, src)); 2863 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64), 2864 MIPSRH_Reg(hregMIPS_GPR0(mode64)))); 2865 *rHi = tHi; 2866 *rLo = tLo; 2867 return; 2868 } 2869 2870 case Iop_Left64: { 2871 HReg yHi, yLo; 2872 HReg tHi = newVRegI(env); 2873 HReg tLo = newVRegI(env); 2874 HReg tmp = newVRegI(env); 2875 HReg tmp1 = newVRegI(env); 2876 HReg tmp2 = newVRegI(env); 2877 HReg zero = newVRegI(env); 2878 MIPSCondCode cc = MIPScc_LO; 2879 2880 /* yHi:yLo = arg */ 2881 iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg); 2882 /* zero = 0 */ 2883 addInstr(env, MIPSInstr_LI(zero, 0x00000000)); 2884 2885 /* tmp2:tmp1 = 0 - (yHi:yLo)*/ 2886 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, zero, MIPSRH_Reg(yLo))); 2887 addInstr(env, MIPSInstr_Cmp(False, True, tmp1, zero, tmp2, cc)); 2888 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, zero, MIPSRH_Reg(yHi))); 2889 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp1, tmp, MIPSRH_Reg(tmp1))); 2890 2891 /* So now we have tmp2:tmp1 = -arg. To finish off, or 'arg' 2892 back in, so as to give the final result 2893 tHi:tLo = arg | -arg. */ 2894 addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, yHi, MIPSRH_Reg(tmp1))); 2895 addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, yLo, MIPSRH_Reg(tmp2))); 2896 *rHi = tHi; 2897 *rLo = tLo; 2898 return; 2899 } 2900 2901 case Iop_CmpwNEZ64: { 2902 HReg srcLo, srcHi; 2903 HReg tmp1 = newVRegI(env); 2904 HReg tmp2 = newVRegI(env); 2905 /* srcHi:srcLo = arg */ 2906 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg); 2907 /* tmp1 = srcHi | srcLo */ 2908 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo, 2909 MIPSRH_Reg(srcHi))); 2910 /* tmp2 = (tmp1 | -tmp1) >>s 31 */ 2911 2912 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64), 2913 MIPSRH_Reg(tmp1))); 2914 2915 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1))); 2916 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2, 2917 MIPSRH_Imm(False, 31))); 2918 *rHi = tmp2; 2919 *rLo = tmp2; 2920 return; 2921 2922 } 2923 case Iop_ReinterpF64asI64: { 2924 HReg tLo = newVRegI(env); 2925 HReg tHi = newVRegI(env); 2926 MIPSAMode *am_addr; 2927 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg); 2928 2929 sub_from_sp(env, 16); /* Move SP down 16 bytes */ 2930 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 2931 2932 /* store as F64 */ 2933 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, 2934 am_addr)); 2935 /* load as 2xI32 */ 2936#if defined (_MIPSEL) 2937 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64)); 2938 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr), 2939 mode64)); 2940#elif defined (_MIPSEB) 2941 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64)); 2942 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr), 2943 mode64)); 2944#endif 2945 2946 /* Reset SP */ 2947 add_to_sp(env, 16); 2948 2949 *rHi = tHi; 2950 *rLo = tLo; 2951 return; 2952 } 2953 2954 default: 2955 vex_printf("UNARY: No such op: "); 2956 ppIROp(e->Iex.Unop.op); 2957 vex_printf("\n"); 2958 break; 2959 } 2960 } 2961 2962 vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag); 2963 ppIRExpr(e); 2964 vpanic("iselInt64Expr(mips)"); 2965} 2966 2967/*---------------------------------------------------------*/ 2968/*--- ISEL: Floating point expressions (32 bit) ---*/ 2969/*---------------------------------------------------------*/ 2970 2971/* Nothing interesting here; really just wrappers for 2972 64-bit stuff. */ 2973static HReg iselFltExpr(ISelEnv * env, IRExpr * e) 2974{ 2975 HReg r = iselFltExpr_wrk(env, e); 2976 vassert(hregIsVirtual(r)); 2977 return r; 2978} 2979 2980/* DO NOT CALL THIS DIRECTLY */ 2981static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e) 2982{ 2983 IRType ty = typeOfIRExpr(env->type_env, e); 2984 vassert(ty == Ity_F32 || (ty == Ity_F64 && fp_mode64)); 2985 2986 if (e->tag == Iex_RdTmp) { 2987 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 2988 } 2989 2990 if (e->tag == Iex_Load) { 2991 vassert(e->Iex.Load.ty == Ity_F32 2992 || (e->Iex.Load.ty == Ity_F64 && fp_mode64)); 2993 HReg r_dst; 2994 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty); 2995 if (e->Iex.Load.ty == Ity_F64) { 2996 r_dst = newVRegD(env); 2997 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr)); 2998 } else { 2999 r_dst = newVRegF(env); 3000 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr)); 3001 } 3002 return r_dst; 3003 } 3004 3005 if (e->tag == Iex_Get) { 3006 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 3007 GuestStatePointer(mode64)); 3008 HReg r_dst; 3009 if (e->Iex.Load.ty == Ity_F64) { 3010 r_dst = newVRegD(env); 3011 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr)); 3012 } else { 3013 r_dst = newVRegF(env); 3014 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr)); 3015 } 3016 return r_dst; 3017 } 3018 3019 if (e->tag == Iex_Unop) { 3020 switch (e->Iex.Unop.op) { 3021 case Iop_ReinterpI32asF32: { 3022 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg); 3023 HReg r_dst = newVRegF(env); 3024 3025 /* Move Word to Floating Point 3026 mtc1 r_dst, valS */ 3027 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, fr_src)); 3028 3029 return r_dst; 3030 } 3031 case Iop_F32toF64: { 3032 vassert(fp_mode64); 3033 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3034 HReg dst = newVRegD(env); 3035 3036 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src)); 3037 return dst; 3038 } 3039 case Iop_ReinterpI64asF64: { 3040 HReg r_dst; 3041 if (mode64) { 3042 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg); 3043 r_dst = newVRegF(env); 3044 /* Move Doubleword to Floating Point 3045 dmtc1 r_dst, fr_src */ 3046 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src)); 3047 } else { 3048 HReg Hi, Lo; 3049 r_dst = newVRegD(env); 3050 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg); 3051 r_dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */ 3052 } 3053 return r_dst; 3054 } 3055 case Iop_I32StoF64: { 3056 vassert(fp_mode64); 3057 HReg dst = newVRegF(env); 3058 HReg tmp = newVRegF(env); 3059 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 3060 3061 /* Move Word to Floating Point 3062 mtc1 tmp, r_src */ 3063 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src)); 3064 3065 /* and do convert */ 3066 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp)); 3067 3068 return dst; 3069 } 3070 case Iop_AbsF32: 3071 case Iop_AbsF64: { 3072 Bool sz32 = e->Iex.Unop.op == Iop_AbsF32; 3073 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3074 HReg dst = newVRegF(env); 3075 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src)); 3076 return dst; 3077 } 3078 case Iop_NegF32: 3079 case Iop_NegF64: { 3080 Bool sz32 = e->Iex.Unop.op == Iop_NegF32; 3081 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3082 HReg dst = newVRegF(env); 3083 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src)); 3084 return dst; 3085 } 3086 case Iop_RoundF64toF64_ZERO: { 3087 vassert(mode64); 3088 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3089 HReg dst = newVRegF(env); 3090 addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, dst, src)); 3091 return dst; 3092 } 3093 case Iop_RoundF64toF64_NEAREST: { 3094 vassert(mode64); 3095 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3096 HReg dst = newVRegF(env); 3097 addInstr(env, MIPSInstr_FpConvert(Mfp_ROUNDLD, dst, src)); 3098 return dst; 3099 } 3100 case Iop_RoundF64toF64_NegINF: { 3101 vassert(mode64); 3102 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3103 HReg dst = newVRegF(env); 3104 addInstr(env, MIPSInstr_FpConvert(Mfp_FLOORLD, dst, src)); 3105 return dst; 3106 } 3107 case Iop_RoundF64toF64_PosINF: { 3108 vassert(mode64); 3109 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3110 HReg dst = newVRegF(env); 3111 addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, dst, src)); 3112 return dst; 3113 } 3114 3115 default: 3116 break; 3117 } 3118 } 3119 3120 if (e->tag == Iex_Triop) { 3121 switch (e->Iex.Triop.details->op) { 3122 case Iop_DivF32: 3123 case Iop_DivF64: 3124 case Iop_MulF32: 3125 case Iop_MulF64: 3126 case Iop_AddF32: 3127 case Iop_AddF64: 3128 case Iop_SubF32: 3129 case Iop_SubF64: { 3130 MIPSFpOp op = 0; 3131 HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2); 3132 HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3); 3133 HReg dst = newVRegF(env); 3134 switch (e->Iex.Triop.details->op) { 3135 case Iop_DivF32: 3136 op = Mfp_DIVS; 3137 break; 3138 case Iop_DivF64: 3139 vassert(fp_mode64); 3140 op = Mfp_DIVD; 3141 break; 3142 case Iop_MulF32: 3143 op = Mfp_MULS; 3144 break; 3145 case Iop_MulF64: 3146 vassert(fp_mode64); 3147 op = Mfp_MULD; 3148 break; 3149 case Iop_AddF32: 3150 op = Mfp_ADDS; 3151 break; 3152 case Iop_AddF64: 3153 vassert(fp_mode64); 3154 op = Mfp_ADDD; 3155 break; 3156 case Iop_SubF32: 3157 op = Mfp_SUBS; 3158 break; 3159 case Iop_SubF64: 3160 vassert(fp_mode64); 3161 op = Mfp_SUBD; 3162 break; 3163 default: 3164 vassert(0); 3165 } 3166 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1); 3167 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR)); 3168 set_MIPS_rounding_default(env); 3169 return dst; 3170 } 3171 default: 3172 break; 3173 } 3174 } 3175 3176 if (e->tag == Iex_Binop) { 3177 switch (e->Iex.Binop.op) { 3178 case Iop_F64toF32: { 3179 HReg valD; 3180 if (mode64) 3181 valD = iselFltExpr(env, e->Iex.Binop.arg2); 3182 else 3183 valD = iselDblExpr(env, e->Iex.Binop.arg2); 3184 HReg valS = newVRegF(env); 3185 3186 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3187 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD)); 3188 set_MIPS_rounding_default(env); 3189 return valS; 3190 } 3191 3192 case Iop_RoundF32toInt: { 3193 HReg valS = newVRegF(env); 3194 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); 3195 3196 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3197 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF)); 3198 set_MIPS_rounding_default(env); 3199 return valS; 3200 } 3201 3202 case Iop_RoundF64toInt: { 3203 HReg valS = newVRegF(env); 3204 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2); 3205 3206 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3207 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, valS, valF)); 3208 set_MIPS_rounding_default(env); 3209 return valS; 3210 } 3211 3212 case Iop_I32StoF32: { 3213 HReg r_dst = newVRegF(env); 3214 HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2); 3215 HReg tmp = newVRegF(env); 3216 3217 /* Move Word to Floating Point 3218 mtc1 tmp, fr_src */ 3219 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, fr_src)); 3220 3221 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3222 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp)); 3223 set_MIPS_rounding_default(env); 3224 3225 return r_dst; 3226 } 3227 3228 case Iop_I64StoF64: { 3229 HReg r_dst = newVRegF(env); 3230 MIPSAMode *am_addr; 3231 HReg tmp, fr_src; 3232 if (mode64) { 3233 tmp = newVRegF(env); 3234 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2); 3235 /* Move SP down 8 bytes */ 3236 sub_from_sp(env, 8); 3237 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 3238 3239 /* store as I64 */ 3240 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64)); 3241 3242 /* load as Ity_F64 */ 3243 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr)); 3244 3245 /* Reset SP */ 3246 add_to_sp(env, 8); 3247 } else { 3248 HReg Hi, Lo; 3249 tmp = newVRegD(env); 3250 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2); 3251 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */ 3252 } 3253 3254 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3255 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp)); 3256 set_MIPS_rounding_default(env); 3257 3258 return r_dst; 3259 } 3260 3261 case Iop_I64StoF32: { 3262 HReg r_dst = newVRegF(env); 3263 MIPSAMode *am_addr; 3264 HReg fr_src, tmp; 3265 if (mode64) { 3266 tmp = newVRegF(env); 3267 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2); 3268 /* Move SP down 8 bytes */ 3269 sub_from_sp(env, 8); 3270 am_addr = MIPSAMode_IR(0, StackPointer(mode64)); 3271 3272 /* store as I64 */ 3273 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64)); 3274 3275 /* load as Ity_F64 */ 3276 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr)); 3277 3278 /* Reset SP */ 3279 add_to_sp(env, 8); 3280 } else { 3281 HReg Hi, Lo; 3282 tmp = newVRegD(env); 3283 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2); 3284 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */ 3285 } 3286 3287 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3288 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSL, r_dst, tmp)); 3289 set_MIPS_rounding_default(env); 3290 3291 return r_dst; 3292 } 3293 3294 case Iop_SqrtF32: 3295 case Iop_SqrtF64: { 3296 Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32; 3297 HReg src = iselFltExpr(env, e->Iex.Binop.arg2); 3298 HReg dst = newVRegF(env); 3299 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3300 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst, 3301 src)); 3302 set_MIPS_rounding_default(env); 3303 return dst; 3304 } 3305 3306 default: 3307 break; 3308 } 3309 } 3310 3311 if (e->tag == Iex_Qop) { 3312 switch (e->Iex.Qop.details->op) { 3313 case Iop_MAddF32: 3314 case Iop_MAddF64: 3315 case Iop_MSubF32: 3316 case Iop_MSubF64: { 3317 MIPSFpOp op = 0; 3318 switch (e->Iex.Qop.details->op) { 3319 case Iop_MAddF32: 3320 op = Mfp_MADDS; 3321 break; 3322 case Iop_MAddF64: 3323 op = Mfp_MADDD; 3324 break; 3325 case Iop_MSubF32: 3326 op = Mfp_MSUBS; 3327 break; 3328 case Iop_MSubF64: 3329 op = Mfp_MSUBD; 3330 break; 3331 default: 3332 vassert(0); 3333 } 3334 HReg dst = newVRegF(env); 3335 HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2); 3336 HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3); 3337 HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4); 3338 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1); 3339 addInstr(env, MIPSInstr_FpTernary(op, dst, 3340 src1, src2, src3)); 3341 set_MIPS_rounding_default(env); 3342 return dst; 3343 } 3344 3345 default: 3346 break; 3347 } 3348 } 3349 3350 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) { 3351 /* This is quite subtle. The only way to do the relevant 3352 truncation is to do a single-precision store and then a 3353 double precision load to get it back into a register. The 3354 problem is, if the data is then written to memory a second 3355 time, as in 3356 3357 STbe(...) = TruncF64asF32(...) 3358 3359 then will the second truncation further alter the value? The 3360 answer is no: flds (as generated here) followed by fsts 3361 (generated for the STbe) is the identity function on 32-bit 3362 floats, so we are safe. 3363 3364 Another upshot of this is that if iselStmt can see the 3365 entirety of 3366 3367 STbe(...) = TruncF64asF32(arg) 3368 3369 then it can short circuit having to deal with TruncF64asF32 3370 individually; instead just compute arg into a 64-bit FP 3371 register and do 'fsts' (since that itself does the 3372 truncation). 3373 3374 We generate pretty poor code here (should be ok both for 3375 32-bit and 64-bit mode); but it is expected that for the most 3376 part the latter optimisation will apply and hence this code 3377 will not often be used. 3378 */ 3379 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg); 3380 HReg fdst = newVRegF(env); 3381 MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64)); 3382 3383 sub_from_sp(env, 16); 3384 /* store as F32, hence truncating */ 3385 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1)); 3386 /* and reload. Good huh?! (sigh) */ 3387 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1)); 3388 add_to_sp(env, 16); 3389 return fdst; 3390 } 3391 3392 /* --------- ITE --------- */ 3393 if (e->tag == Iex_ITE) { 3394 if (ty == Ity_F64 3395 && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) { 3396 vassert(mode64); 3397 HReg r0 = iselFltExpr(env, e->Iex.ITE.iffalse); 3398 HReg r1 = iselFltExpr(env, e->Iex.ITE.iftrue); 3399 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond); 3400 HReg r_dst = newVRegF(env); 3401 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0)); 3402 addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1, 3403 r_cond)); 3404 return r_dst; 3405 } 3406 } 3407 3408 vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag); 3409 ppIRExpr(e); 3410 vpanic("iselFltExpr_wrk(mips)"); 3411} 3412 3413static HReg iselDblExpr(ISelEnv * env, IRExpr * e) 3414{ 3415 HReg r = iselDblExpr_wrk(env, e); 3416 vassert(hregClass(r) == HRcFlt64); 3417 vassert(hregIsVirtual(r)); 3418 return r; 3419} 3420 3421/* DO NOT CALL THIS DIRECTLY */ 3422static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e) 3423{ 3424 IRType ty = typeOfIRExpr(env->type_env, e); 3425 vassert(e); 3426 vassert(ty == Ity_F64); 3427 3428 if (e->tag == Iex_RdTmp) { 3429 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 3430 } 3431 3432 /* --------- LOAD --------- */ 3433 if (e->tag == Iex_Load) { 3434 HReg r_dst = newVRegD(env); 3435 MIPSAMode *am_addr; 3436 vassert(e->Iex.Load.ty == Ity_F64); 3437 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty); 3438 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr)); 3439 return r_dst; 3440 } 3441 3442 /* --------- GET --------- */ 3443 if (e->tag == Iex_Get) { 3444 3445 HReg r_dst = newVRegD(env); 3446 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset, 3447 GuestStatePointer(mode64)); 3448 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr)); 3449 return r_dst; 3450 } 3451 3452 if (e->tag == Iex_Unop) { 3453 MIPSFpOp fpop = Mfp_INVALID; 3454 switch (e->Iex.Unop.op) { 3455 case Iop_NegF64: 3456 fpop = Mfp_NEGD; 3457 break; 3458 case Iop_AbsF64: 3459 fpop = Mfp_ABSD; 3460 break; 3461 case Iop_F32toF64: { 3462 vassert(!mode64); 3463 HReg src = iselFltExpr(env, e->Iex.Unop.arg); 3464 HReg dst = newVRegD(env); 3465 3466 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src)); 3467 return dst; 3468 } 3469 case Iop_ReinterpI64asF64: { 3470 HReg Hi, Lo; 3471 HReg dst = newVRegD(env); 3472 3473 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg); 3474 3475 dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */ 3476 return dst; 3477 } 3478 case Iop_I32StoF64: { 3479 vassert(!mode64); 3480 HReg dst = newVRegD(env); 3481 HReg tmp = newVRegF(env); 3482 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 3483 3484 /* Move Word to Floating Point 3485 mtc1 tmp, r_src */ 3486 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src)); 3487 3488 /* and do convert */ 3489 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp)); 3490 3491 return dst; 3492 } 3493 default: 3494 break; 3495 } 3496 3497 if (fpop != Mfp_INVALID) { 3498 HReg src = iselDblExpr(env, e->Iex.Unop.arg); 3499 HReg dst = newVRegD(env); 3500 addInstr(env, MIPSInstr_FpUnary(fpop, dst, src)); 3501 return dst; 3502 } 3503 } 3504 3505 if (e->tag == Iex_Binop) { 3506 switch (e->Iex.Binop.op) { 3507 case Iop_RoundF64toInt: { 3508 HReg src = iselDblExpr(env, e->Iex.Binop.arg2); 3509 HReg dst = newVRegD(env); 3510 3511 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3512 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src)); 3513 set_MIPS_rounding_default(env); 3514 3515 return dst; 3516 } 3517 3518 case Iop_SqrtF64: { 3519 HReg src = iselDblExpr(env, e->Iex.Binop.arg2); 3520 HReg dst = newVRegD(env); 3521 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1); 3522 addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src)); 3523 set_MIPS_rounding_default(env); 3524 return dst; 3525 } 3526 3527 default: 3528 break; 3529 3530 } 3531 } 3532 3533 if (e->tag == Iex_Triop) { 3534 switch (e->Iex.Triop.details->op) { 3535 case Iop_DivF64: 3536 case Iop_DivF32: 3537 case Iop_MulF64: 3538 case Iop_AddF64: 3539 case Iop_SubF64: { 3540 MIPSFpOp op = 0; 3541 HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2); 3542 HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3); 3543 HReg dst = newVRegD(env); 3544 switch (e->Iex.Triop.details->op) { 3545 case Iop_DivF64: 3546 op = Mfp_DIVD; 3547 break; 3548 case Iop_DivF32: 3549 op = Mfp_DIVS; 3550 break; 3551 case Iop_MulF64: 3552 op = Mfp_MULD; 3553 break; 3554 case Iop_AddF64: 3555 op = Mfp_ADDD; 3556 break; 3557 case Iop_SubF64: 3558 op = Mfp_SUBD; 3559 break; 3560 default: 3561 vassert(0); 3562 } 3563 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1); 3564 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR)); 3565 set_MIPS_rounding_default(env); 3566 return dst; 3567 } 3568 default: 3569 break; 3570 } 3571 } 3572 3573 if (e->tag == Iex_Qop) { 3574 switch (e->Iex.Qop.details->op) { 3575 case Iop_MAddF32: 3576 case Iop_MAddF64: 3577 case Iop_MSubF32: 3578 case Iop_MSubF64: { 3579 MIPSFpOp op = 0; 3580 switch (e->Iex.Qop.details->op) { 3581 case Iop_MAddF32: 3582 op = Mfp_MADDS; 3583 break; 3584 case Iop_MAddF64: 3585 op = Mfp_MADDD; 3586 break; 3587 case Iop_MSubF32: 3588 op = Mfp_MSUBS; 3589 break; 3590 case Iop_MSubF64: 3591 op = Mfp_MSUBD; 3592 break; 3593 default: 3594 vassert(0); 3595 } 3596 HReg dst = newVRegD(env); 3597 HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2); 3598 HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3); 3599 HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4); 3600 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1); 3601 addInstr(env, MIPSInstr_FpTernary(op, dst, 3602 src1, src2, src3)); 3603 set_MIPS_rounding_default(env); 3604 return dst; 3605 } 3606 3607 default: 3608 break; 3609 } 3610 } 3611 3612 /* --------- ITE --------- */ 3613 if (e->tag == Iex_ITE) { 3614 if (ty == Ity_F64 3615 && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) { 3616 HReg r0 = iselDblExpr(env, e->Iex.ITE.iffalse); 3617 HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue); 3618 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond); 3619 HReg r_dst = newVRegD(env); 3620 3621 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0)); 3622 addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1, 3623 r_cond)); 3624 return r_dst; 3625 } 3626 } 3627 3628 vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag); 3629 ppIRExpr(e); 3630 vpanic("iselDblExpr_wrk(mips)"); 3631} 3632 3633/*---------------------------------------------------------*/ 3634/*--- ISEL: Statements ---*/ 3635/*---------------------------------------------------------*/ 3636 3637static void iselStmt(ISelEnv * env, IRStmt * stmt) 3638{ 3639 if (vex_traceflags & VEX_TRACE_VCODE) { 3640 vex_printf("\n-- "); 3641 3642 ppIRStmt(stmt); 3643 vex_printf("\n"); 3644 } 3645 3646 switch (stmt->tag) { 3647 /* --------- STORE --------- */ 3648 case Ist_Store: { 3649 MIPSAMode *am_addr; 3650 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 3651 3652 /*constructs addressing mode from address provided */ 3653 am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd); 3654 3655 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 || 3656 (mode64 && (tyd == Ity_I64))) { 3657 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data); 3658 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)), 3659 am_addr, r_src, mode64)); 3660 return; 3661 } 3662 if (!mode64 && (tyd == Ity_I64)) { 3663 HReg vHi, vLo; 3664 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr); 3665 3666 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data); 3667 3668 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 3669 MIPSAMode_IR(0, r_addr), vHi, mode64)); 3670 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 3671 MIPSAMode_IR(4, r_addr), vLo, mode64)); 3672 return; 3673 } 3674 if (tyd == Ity_F32) { 3675 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data); 3676 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src, 3677 am_addr)); 3678 return; 3679 } 3680 if (tyd == Ity_F64 && mode64) { 3681 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data); 3682 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, 3683 am_addr)); 3684 return; 3685 } 3686 if (!mode64 && (tyd == Ity_F64)) { 3687 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data); 3688 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, 3689 am_addr)); 3690 return; 3691 } 3692 3693 break; 3694 } 3695 3696 /* --------- PUT --------- */ 3697 case Ist_Put: { 3698 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 3699 3700 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || 3701 (ty == Ity_I64 && mode64)) { 3702 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data); 3703 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 3704 GuestStatePointer(mode64)); 3705 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)), 3706 am_addr, r_src, mode64)); 3707 return; 3708 } 3709 3710 if (ty == Ity_I64 && !mode64) { 3711 HReg vHi, vLo; 3712 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 3713 GuestStatePointer(mode64)); 3714 MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4, 3715 GuestStatePointer(mode64)); 3716 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data); 3717 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 3718 am_addr, vLo, mode64)); 3719 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)), 3720 am_addr4, vHi, mode64)); 3721 return; 3722 3723 } 3724 3725 if (ty == Ity_F32) { 3726 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data); 3727 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 3728 GuestStatePointer(mode64)); 3729 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src, 3730 am_addr)); 3731 return; 3732 } 3733 3734 if (ty == Ity_F64) { 3735 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data); 3736 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset, 3737 GuestStatePointer(mode64)); 3738 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src, 3739 am_addr)); 3740 return; 3741 } 3742 break; 3743 } 3744 3745 /* --------- TMP --------- */ 3746 case Ist_WrTmp: { 3747 IRTemp tmp = stmt->Ist.WrTmp.tmp; 3748 IRType ty = typeOfIRTemp(env->type_env, tmp); 3749 3750 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) { 3751 HReg r_dst = lookupIRTemp(env, tmp); 3752 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data); 3753 addInstr(env, mk_iMOVds_RR(r_dst, r_src)); 3754 return; 3755 } 3756 3757 if (ty == Ity_I64) { 3758 if (mode64) { 3759 HReg r_dst = lookupIRTemp(env, tmp); 3760 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data); 3761 addInstr(env, mk_iMOVds_RR(r_dst, r_src)); 3762 return; 3763 } else { 3764 HReg rHi, rLo, dstHi, dstLo; 3765 iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data); 3766 lookupIRTemp64(&dstHi, &dstLo, env, tmp); 3767 addInstr(env, mk_iMOVds_RR(dstHi, rHi)); 3768 addInstr(env, mk_iMOVds_RR(dstLo, rLo)); 3769 return; 3770 } 3771 } 3772 3773 if (mode64 && ty == Ity_I128) { 3774 HReg rHi, rLo, dstHi, dstLo; 3775 iselInt128Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data); 3776 lookupIRTempPair(&dstHi, &dstLo, env, tmp); 3777 addInstr(env, mk_iMOVds_RR(dstHi, rHi)); 3778 addInstr(env, mk_iMOVds_RR(dstLo, rLo)); 3779 return; 3780 } 3781 3782 if (ty == Ity_F32) { 3783 HReg fr_dst = lookupIRTemp(env, tmp); 3784 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data); 3785 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src)); 3786 return; 3787 } 3788 3789 if (ty == Ity_F64) { 3790 if (mode64) { 3791 HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data); 3792 HReg dst = lookupIRTemp(env, tmp); 3793 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src)); 3794 return; 3795 } else { 3796 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data); 3797 HReg dst = lookupIRTemp(env, tmp); 3798 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src)); 3799 return; 3800 } 3801 } 3802 break; 3803 } 3804 3805 /* --------- Call to DIRTY helper --------- */ 3806 case Ist_Dirty: { 3807 IRDirty *d = stmt->Ist.Dirty.details; 3808 3809 /* Figure out the return type, if any. */ 3810 IRType retty = Ity_INVALID; 3811 if (d->tmp != IRTemp_INVALID) 3812 retty = typeOfIRTemp(env->type_env, d->tmp); 3813 3814 /* Throw out any return types we don't know about. */ 3815 Bool retty_ok = False; 3816 switch (retty) { 3817 case Ity_INVALID: /* Function doesn't return anything. */ 3818 case Ity_V128: 3819 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8: 3820 retty_ok = True; break; 3821 default: 3822 break; 3823 } 3824 3825 if (!retty_ok) 3826 break; /* will go to stmt_fail: */ 3827 3828 /* Marshal args, do the call, clear stack, set the return value 3829 to 0x555..555 if this is a conditional call that returns a 3830 value and the call is skipped. */ 3831 UInt addToSp = 0; 3832 RetLoc rloc = mk_RetLoc_INVALID(); 3833 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args ); 3834 vassert(is_sane_RetLoc(rloc)); 3835 3836 /* Now figure out what to do with the returned value, if any. */ 3837 switch (retty) { 3838 case Ity_INVALID: { 3839 /* No return value. Nothing to do. */ 3840 vassert(d->tmp == IRTemp_INVALID); 3841 vassert(rloc.pri == RLPri_None); 3842 vassert(addToSp == 0); 3843 return; 3844 } 3845 case Ity_I32: case Ity_I16: case Ity_I8: { 3846 /* The returned value is in $v0. Park it in the register 3847 associated with tmp. */ 3848 HReg r_dst = lookupIRTemp(env, d->tmp); 3849 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64))); 3850 vassert(rloc.pri == RLPri_Int); 3851 vassert(addToSp == 0); 3852 return; 3853 } 3854 case Ity_I64: { 3855 if (mode64) { 3856 /* The returned value is in $v0. Park it in the register 3857 associated with tmp. */ 3858 HReg r_dst = lookupIRTemp(env, d->tmp); 3859 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64))); 3860 vassert(rloc.pri == RLPri_Int); 3861 vassert(addToSp == 0); 3862 return; 3863 } else { 3864 HReg rHi = newVRegI(env); 3865 HReg rLo = newVRegI(env); 3866 HReg dstHi, dstLo; 3867 addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64))); 3868 addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64))); 3869 lookupIRTemp64(&dstHi, &dstLo, env, d->tmp); 3870 addInstr(env, mk_iMOVds_RR(dstHi, rHi)); 3871 addInstr(env, mk_iMOVds_RR(dstLo, rLo)); 3872 return; 3873 } 3874 } 3875 case Ity_V128: { 3876 /* ATC. The code that this produces really 3877 needs to be looked at, to verify correctness. 3878 I don't think this can ever happen though, since the 3879 MIPS front end never produces 128-bit loads/stores. */ 3880 vassert(0); 3881 vassert(rloc.pri == RLPri_V128SpRel); 3882 vassert(addToSp >= 16); 3883 HReg dst = lookupIRTemp(env, d->tmp); 3884 MIPSAMode* am = MIPSAMode_IR(rloc.spOff, StackPointer(mode64)); 3885 addInstr(env, MIPSInstr_Load(mode64 ? 8 : 4, dst, am, mode64)); 3886 add_to_sp(env, addToSp); 3887 return; 3888 3889 } 3890 default: 3891 /*NOTREACHED*/ 3892 vassert(0); 3893 } 3894 } 3895 3896 /* --------- Load Linked or Store Conditional --------- */ 3897 case Ist_LLSC: { 3898 /* Temporary solution; this need to be rewritten again for MIPS. 3899 On MIPS you can not read from address that is locked with LL 3900 before SC. If you read from address that is locked than SC will 3901 fall. */ 3902 IRTemp res = stmt->Ist.LLSC.result; 3903 IRType tyRes = typeOfIRTemp(env->type_env, res); 3904 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr); 3905 3906 if (!mode64 && (tyAddr != Ity_I32)) 3907 goto stmt_fail; 3908 3909 if (stmt->Ist.LLSC.storedata == NULL) { 3910 /* LL */ 3911 MIPSAMode *r_addr; 3912 /* constructs addressing mode from address provided */ 3913 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr); 3914 3915 HReg r_dst = lookupIRTemp(env, res); 3916 if (tyRes == Ity_I32) { 3917 addInstr(env, MIPSInstr_LoadL(4, r_dst, r_addr, mode64)); 3918 return; 3919 } else if (tyRes == Ity_I64 && mode64) { 3920 addInstr(env, MIPSInstr_LoadL(8, r_dst, r_addr, mode64)); 3921 return; 3922 } 3923 } else { 3924 /* SC */ 3925 MIPSAMode *r_addr; 3926 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr); 3927 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata); 3928 HReg r_dst = lookupIRTemp(env, res); 3929 IRType tyData = typeOfIRExpr(env->type_env, 3930 stmt->Ist.LLSC.storedata); 3931 3932 if (tyData == Ity_I32) { 3933 addInstr(env, mk_iMOVds_RR(r_dst, r_src)); 3934 addInstr(env, MIPSInstr_StoreC(4, r_addr, r_dst, mode64)); 3935 return; 3936 } else if (tyData == Ity_I64 && mode64) { 3937 addInstr(env, mk_iMOVds_RR(r_dst, r_src)); 3938 addInstr(env, MIPSInstr_StoreC(8, r_addr, r_dst, mode64)); 3939 return; 3940 } 3941 } 3942 goto stmt_fail; 3943 /* NOTREACHED */} 3944 3945 case Ist_CAS: 3946 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) { 3947 IRCAS *cas = stmt->Ist.CAS.details; 3948 HReg old = lookupIRTemp(env, cas->oldLo); 3949 HReg addr = iselWordExpr_R(env, cas->addr); 3950 HReg expd = iselWordExpr_R(env, cas->expdLo); 3951 HReg data = iselWordExpr_R(env, cas->dataLo); 3952 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) { 3953 addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64)); 3954 } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) { 3955 addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64)); 3956 } 3957 } 3958 return; 3959 3960 /* --------- INSTR MARK --------- */ 3961 /* Doesn't generate any executable code ... */ 3962 case Ist_IMark: 3963 return; 3964 3965 /* --------- ABI HINT --------- */ 3966 /* These have no meaning (denotation in the IR) and so we ignore 3967 them ... if any actually made it this far. */ 3968 case Ist_AbiHint: 3969 return; 3970 3971 /* --------- NO-OP --------- */ 3972 /* Fairly self-explanatory, wouldn't you say? */ 3973 case Ist_NoOp: 3974 return; 3975 3976 /* --------- EXIT --------- */ 3977 case Ist_Exit: { 3978 IRConst* dst = stmt->Ist.Exit.dst; 3979 if (!mode64 && dst->tag != Ico_U32) 3980 vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value"); 3981 if (mode64 && dst->tag != Ico_U64) 3982 vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value"); 3983 3984 MIPSCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard); 3985 MIPSAMode* amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP, 3986 GuestStatePointer(mode64)); 3987 3988 /* Case: boring transfer to known address */ 3989 if (stmt->Ist.Exit.jk == Ijk_Boring 3990 || stmt->Ist.Exit.jk == Ijk_Call 3991 /* || stmt->Ist.Exit.jk == Ijk_Ret */) { 3992 if (env->chainingAllowed) { 3993 /* .. almost always true .. */ 3994 /* Skip the event check at the dst if this is a forwards 3995 edge. */ 3996 Bool toFastEP 3997 = mode64 3998 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga) 3999 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga); 4000 if (0) vex_printf("%s", toFastEP ? "Y" : ","); 4001 addInstr(env, MIPSInstr_XDirect( 4002 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64 4003 : (Addr64)stmt->Ist.Exit.dst->Ico.U32, 4004 amPC, cc, toFastEP)); 4005 } else { 4006 /* .. very occasionally .. */ 4007 /* We can't use chaining, so ask for an assisted transfer, 4008 as that's the only alternative that is allowable. */ 4009 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst)); 4010 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring)); 4011 } 4012 return; 4013 } 4014 4015 /* Case: assisted transfer to arbitrary address */ 4016 switch (stmt->Ist.Exit.jk) { 4017 /* Keep this list in sync with that in iselNext below */ 4018 case Ijk_ClientReq: 4019 case Ijk_EmFail: 4020 case Ijk_EmWarn: 4021 case Ijk_NoDecode: 4022 case Ijk_NoRedir: 4023 case Ijk_SigBUS: 4024 case Ijk_Yield: 4025 case Ijk_SigTRAP: 4026 case Ijk_SigFPE_IntDiv: 4027 case Ijk_SigFPE_IntOvf: 4028 case Ijk_Sys_syscall: 4029 case Ijk_InvalICache: 4030 { 4031 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst)); 4032 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, 4033 stmt->Ist.Exit.jk)); 4034 return; 4035 } 4036 default: 4037 break; 4038 } 4039 4040 /* Do we ever expect to see any other kind? */ 4041 goto stmt_fail; 4042 } 4043 4044 default: 4045 break; 4046 } 4047 4048 stmt_fail: 4049 vex_printf("stmt_fail tag: 0x%x\n", stmt->tag); 4050 ppIRStmt(stmt); 4051 vpanic("iselStmt:\n"); 4052} 4053 4054/*---------------------------------------------------------*/ 4055/*--- ISEL: Basic block terminators (Nexts) ---*/ 4056/*---------------------------------------------------------*/ 4057 4058static void iselNext ( ISelEnv* env, 4059 IRExpr* next, IRJumpKind jk, Int offsIP ) 4060{ 4061 if (vex_traceflags & VEX_TRACE_VCODE) { 4062 vex_printf( "\n-- PUT(%d) = ", offsIP); 4063 ppIRExpr( next ); 4064 vex_printf( "; exit-"); 4065 ppIRJumpKind(jk); 4066 vex_printf( "\n"); 4067 } 4068 4069 /* Case: boring transfer to known address */ 4070 if (next->tag == Iex_Const) { 4071 IRConst* cdst = next->Iex.Const.con; 4072 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32)); 4073 if (jk == Ijk_Boring || jk == Ijk_Call) { 4074 /* Boring transfer to known address */ 4075 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64)); 4076 if (env->chainingAllowed) { 4077 /* .. almost always true .. */ 4078 /* Skip the event check at the dst if this is a forwards 4079 edge. */ 4080 Bool toFastEP 4081 = env->mode64 4082 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga) 4083 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga); 4084 if (0) vex_printf("%s", toFastEP ? "X" : "."); 4085 addInstr(env, MIPSInstr_XDirect( 4086 env->mode64 ? (Addr64)cdst->Ico.U64 4087 : (Addr64)cdst->Ico.U32, 4088 amPC, MIPScc_AL, toFastEP)); 4089 } else { 4090 /* .. very occasionally .. */ 4091 /* We can't use chaining, so ask for an assisted transfer, 4092 as that's the only alternative that is allowable. */ 4093 HReg r = iselWordExpr_R(env, next); 4094 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, 4095 Ijk_Boring)); 4096 } 4097 return; 4098 } 4099 } 4100 4101 /* Case: call/return (==boring) transfer to any address */ 4102 switch (jk) { 4103 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: { 4104 HReg r = iselWordExpr_R(env, next); 4105 MIPSAMode* amPC = MIPSAMode_IR(offsIP, 4106 GuestStatePointer(env->mode64)); 4107 if (env->chainingAllowed) { 4108 addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL)); 4109 } else { 4110 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, 4111 Ijk_Boring)); 4112 } 4113 return; 4114 } 4115 default: 4116 break; 4117 } 4118 4119 /* Case: assisted transfer to arbitrary address */ 4120 switch (jk) { 4121 /* Keep this list in sync with that for Ist_Exit above */ 4122 case Ijk_ClientReq: 4123 case Ijk_EmFail: 4124 case Ijk_EmWarn: 4125 case Ijk_NoDecode: 4126 case Ijk_NoRedir: 4127 case Ijk_SigBUS: 4128 case Ijk_SigILL: 4129 case Ijk_SigTRAP: 4130 case Ijk_SigFPE_IntDiv: 4131 case Ijk_SigFPE_IntOvf: 4132 case Ijk_Sys_syscall: 4133 case Ijk_InvalICache: { 4134 HReg r = iselWordExpr_R(env, next); 4135 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64)); 4136 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk)); 4137 return; 4138 } 4139 default: 4140 break; 4141 } 4142 4143 vex_printf("\n-- PUT(%d) = ", offsIP); 4144 ppIRExpr(next ); 4145 vex_printf("; exit-"); 4146 ppIRJumpKind(jk); 4147 vex_printf("\n"); 4148 vassert(0); /* are we expecting any other kind? */ 4149} 4150 4151/*---------------------------------------------------------*/ 4152/*--- Insn selector top-level ---*/ 4153/*---------------------------------------------------------*/ 4154 4155/* Translate an entire BB to mips code. */ 4156HInstrArray *iselSB_MIPS ( const IRSB* bb, 4157 VexArch arch_host, 4158 const VexArchInfo* archinfo_host, 4159 const VexAbiInfo* vbi, 4160 Int offs_Host_EvC_Counter, 4161 Int offs_Host_EvC_FailAddr, 4162 Bool chainingAllowed, 4163 Bool addProfInc, 4164 Addr max_ga ) 4165{ 4166 Int i, j; 4167 HReg hreg, hregHI; 4168 ISelEnv* env; 4169 UInt hwcaps_host = archinfo_host->hwcaps; 4170 MIPSAMode *amCounter, *amFailAddr; 4171 4172 /* sanity ... */ 4173 vassert(arch_host == VexArchMIPS32 || arch_host == VexArchMIPS64); 4174 vassert(VEX_PRID_COMP_MIPS == hwcaps_host 4175 || VEX_PRID_COMP_BROADCOM == hwcaps_host 4176 || VEX_PRID_COMP_NETLOGIC); 4177 4178 /* Check that the host's endianness is as expected. */ 4179 vassert(archinfo_host->endness == VexEndnessLE 4180 || archinfo_host->endness == VexEndnessBE); 4181 4182 mode64 = arch_host != VexArchMIPS32; 4183#if (__mips_fpr==64) 4184 fp_mode64 = ((VEX_MIPS_REV(hwcaps_host) == VEX_PRID_CPU_32FPR) 4185 || arch_host == VexArchMIPS64); 4186#endif 4187 4188 /* Make up an initial environment to use. */ 4189 env = LibVEX_Alloc_inline(sizeof(ISelEnv)); 4190 env->vreg_ctr = 0; 4191 env->mode64 = mode64; 4192 env->fp_mode64 = fp_mode64; 4193 4194 /* Set up output code array. */ 4195 env->code = newHInstrArray(); 4196 4197 /* Copy BB's type env. */ 4198 env->type_env = bb->tyenv; 4199 4200 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 4201 change as we go along. */ 4202 env->n_vregmap = bb->tyenv->types_used; 4203 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 4204 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 4205 4206 /* and finally ... */ 4207 env->hwcaps = hwcaps_host; 4208 env->chainingAllowed = chainingAllowed; 4209 env->hwcaps = hwcaps_host; 4210 env->max_ga = max_ga; 4211 4212 /* For each IR temporary, allocate a suitably-kinded virtual 4213 register. */ 4214 j = 0; 4215 for (i = 0; i < env->n_vregmap; i++) { 4216 hregHI = hreg = INVALID_HREG; 4217 switch (bb->tyenv->types[i]) { 4218 case Ity_I1: 4219 case Ity_I8: 4220 case Ity_I16: 4221 case Ity_I32: 4222 if (mode64) { 4223 hreg = mkHReg(True, HRcInt64, 0, j++); 4224 break; 4225 } else { 4226 hreg = mkHReg(True, HRcInt32, 0, j++); 4227 break; 4228 } 4229 case Ity_I64: 4230 if (mode64) { 4231 hreg = mkHReg(True, HRcInt64, 0, j++); 4232 break; 4233 } else { 4234 hreg = mkHReg(True, HRcInt32, 0, j++); 4235 hregHI = mkHReg(True, HRcInt32, 0, j++); 4236 break; 4237 } 4238 case Ity_I128: 4239 vassert(mode64); 4240 hreg = mkHReg(True, HRcInt64, 0, j++); 4241 hregHI = mkHReg(True, HRcInt64, 0, j++); 4242 break; 4243 case Ity_F32: 4244 if (mode64) { 4245 hreg = mkHReg(True, HRcFlt64, 0, j++); 4246 break; 4247 } else { 4248 hreg = mkHReg(True, HRcFlt32, 0, j++); 4249 break; 4250 } 4251 case Ity_F64: 4252 hreg = mkHReg(True, HRcFlt64, 0, j++); 4253 break; 4254 default: 4255 ppIRType(bb->tyenv->types[i]); 4256 vpanic("iselBB(mips): IRTemp type"); 4257 break; 4258 } 4259 env->vregmap[i] = hreg; 4260 env->vregmapHI[i] = hregHI; 4261 } 4262 env->vreg_ctr = j; 4263 4264 /* The very first instruction must be an event check. */ 4265 amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, GuestStatePointer(mode64)); 4266 amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, GuestStatePointer(mode64)); 4267 addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr)); 4268 4269 /* Possibly a block counter increment (for profiling). At this 4270 point we don't know the address of the counter, so just pretend 4271 it is zero. It will have to be patched later, but before this 4272 translation is used, by a call to LibVEX_patchProfCtr. */ 4273 if (addProfInc) { 4274 addInstr(env, MIPSInstr_ProfInc()); 4275 } 4276 4277 /* Ok, finally we can iterate over the statements. */ 4278 for (i = 0; i < bb->stmts_used; i++) 4279 iselStmt(env, bb->stmts[i]); 4280 4281 iselNext(env, bb->next, bb->jumpkind, bb->offsIP); 4282 4283 /* record the number of vregs we used. */ 4284 env->code->n_vregs = env->vreg_ctr; 4285 return env->code; 4286 4287} 4288 4289/*---------------------------------------------------------------*/ 4290/*--- end host_mips_isel.c ---*/ 4291/*---------------------------------------------------------------*/ 4292