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