1 2 /*---------------------------------------------------------------*/ 3 /*--- begin host_ppc_isel.c ---*/ 4 /*---------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2004-2010 OpenWorks LLP 11 info (at) open-works.net 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 Neither the names of the U.S. Department of Energy nor the 31 University of California nor the names of its contributors may be 32 used to endorse or promote products derived from this software 33 without prior written permission. 34 */ 35 36 #include "libvex_basictypes.h" 37 #include "libvex_ir.h" 38 #include "libvex.h" 39 40 #include "ir_match.h" 41 #include "main_util.h" 42 #include "main_globals.h" 43 #include "host_generic_regs.h" 44 #include "host_ppc_defs.h" 45 46 /* GPR register class for ppc32/64 */ 47 #define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32) 48 49 50 /*---------------------------------------------------------*/ 51 /*--- Register Usage Conventions ---*/ 52 /*---------------------------------------------------------*/ 53 /* 54 Integer Regs 55 ------------ 56 GPR0 Reserved 57 GPR1 Stack Pointer 58 GPR2 not used - TOC pointer 59 GPR3:10 Allocateable 60 GPR11 if mode64: not used - calls by ptr / env ptr for some langs 61 GPR12 if mode64: not used - exceptions / global linkage code 62 GPR13 not used - Thread-specific pointer 63 GPR14:28 Allocateable 64 GPR29 Unused by us (reserved for the dispatcher) 65 GPR30 AltiVec temp spill register 66 GPR31 GuestStatePointer 67 68 Of Allocateable regs: 69 if (mode64) 70 GPR3:10 Caller-saved regs 71 else 72 GPR3:12 Caller-saved regs 73 GPR14:29 Callee-saved regs 74 75 GPR3 [Return | Parameter] - carrying reg 76 GPR4:10 Parameter-carrying regs 77 78 79 Floating Point Regs 80 ------------------- 81 FPR0:31 Allocateable 82 83 FPR0 Caller-saved - scratch reg 84 if (mode64) 85 FPR1:13 Caller-saved - param & return regs 86 else 87 FPR1:8 Caller-saved - param & return regs 88 FPR9:13 Caller-saved regs 89 FPR14:31 Callee-saved regs 90 91 92 Vector Regs (on processors with the VMX feature) 93 ----------- 94 VR0-VR1 Volatile scratch registers 95 VR2-VR13 Volatile vector parameters registers 96 VR14-VR19 Volatile scratch registers 97 VR20-VR31 Non-volatile registers 98 VRSAVE Non-volatile 32-bit register 99 */ 100 101 102 /*---------------------------------------------------------*/ 103 /*--- PPC FP Status & Control Register Conventions ---*/ 104 /*---------------------------------------------------------*/ 105 /* 106 Vex-generated code expects to run with the FPU set as follows: all 107 exceptions masked. The rounding mode is set appropriately before 108 each floating point insn emitted (or left unchanged if known to be 109 correct already). There are a few fp insns (fmr,fneg,fabs,fnabs), 110 which are unaffected by the rm and so the rounding mode is not set 111 prior to them. 112 113 At least on MPC7447A (Mac Mini), frsqrte is also not affected by 114 rounding mode. At some point the ppc docs get sufficiently vague 115 that the only way to find out is to write test programs. 116 */ 117 /* Notes on the FP instruction set, 6 Feb 06. 118 119 What exns -> CR1 ? Sets FPRF ? Observes RM ? 120 ------------------------------------------------------------- 121 122 fmr[.] if . n n 123 fneg[.] if . n n 124 fabs[.] if . n n 125 fnabs[.] if . n n 126 127 fadd[.] if . y y 128 fadds[.] if . y y 129 fcfid[.] (i64->dbl) if . y y 130 fcmpo (cmp, result n n n 131 fcmpu to crfD) n n n 132 fctid[.] (dbl->i64) if . ->undef y 133 fctidz[.] (dbl->i64) if . ->undef rounds-to-zero 134 fctiw[.] (dbl->i32) if . ->undef y 135 fctiwz[.] (dbl->i32) if . ->undef rounds-to-zero 136 fdiv[.] if . y y 137 fdivs[.] if . y y 138 fmadd[.] if . y y 139 fmadds[.] if . y y 140 fmsub[.] if . y y 141 fmsubs[.] if . y y 142 fmul[.] if . y y 143 fmuls[.] if . y y 144 145 (note: for fnm*, rounding happens before final negation) 146 fnmadd[.] if . y y 147 fnmadds[.] if . y y 148 fnmsub[.] if . y y 149 fnmsubs[.] if . y y 150 151 fre[.] if . y y 152 fres[.] if . y y 153 154 frsqrte[.] if . y apparently not 155 156 fsqrt[.] if . y y 157 fsqrts[.] if . y y 158 fsub[.] if . y y 159 fsubs[.] if . y y 160 161 162 fpscr: bits 30-31 (ibm) is RM 163 24-29 (ibm) are exnmasks/non-IEEE bit, all zero 164 15-19 (ibm) is FPRF: class, <, =, >, UNord 165 166 ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF 167 in future) 168 169 mcrfs - move fpscr field to CR field 170 mtfsfi[.] - 4 bit imm moved to fpscr field 171 mtfsf[.] - move frS[low 1/2] to fpscr but using 8-bit field mask 172 mtfsb1[.] - set given fpscr bit 173 mtfsb0[.] - clear given fpscr bit 174 mffs[.] - move all fpscr to frD[low 1/2] 175 176 For [.] presumably cr1 is set with exn summary bits, as per 177 main FP insns 178 179 A single precision store truncates/denormalises the in-register value, 180 but does not round it. This is so that flds followed by fsts is 181 always the identity. 182 */ 183 184 185 /*---------------------------------------------------------*/ 186 /*--- misc helpers ---*/ 187 /*---------------------------------------------------------*/ 188 189 /* These are duplicated in guest-ppc/toIR.c */ 190 static IRExpr* unop ( IROp op, IRExpr* a ) 191 { 192 return IRExpr_Unop(op, a); 193 } 194 195 static IRExpr* mkU32 ( UInt i ) 196 { 197 return IRExpr_Const(IRConst_U32(i)); 198 } 199 200 static IRExpr* bind ( Int binder ) 201 { 202 return IRExpr_Binder(binder); 203 } 204 205 206 /*---------------------------------------------------------*/ 207 /*--- ISelEnv ---*/ 208 /*---------------------------------------------------------*/ 209 210 /* This carries around: 211 212 - A mapping from IRTemp to IRType, giving the type of any IRTemp we 213 might encounter. This is computed before insn selection starts, 214 and does not change. 215 216 - A mapping from IRTemp to HReg. This tells the insn selector 217 which virtual register(s) are associated with each IRTemp 218 temporary. This is computed before insn selection starts, and 219 does not change. We expect this mapping to map precisely the 220 same set of IRTemps as the type mapping does. 221 222 - vregmap holds the primary register for the IRTemp. 223 - vregmapHI holds the secondary register for the IRTemp, 224 if any is needed. That's only for Ity_I64 temps 225 in 32 bit mode or Ity_I128 temps in 64-bit mode. 226 227 - The name of the vreg in which we stash a copy of the link reg, 228 so helper functions don't kill it. 229 230 - The code array, that is, the insns selected so far. 231 232 - A counter, for generating new virtual registers. 233 234 - The host subarchitecture we are selecting insns for. 235 This is set at the start and does not change. 236 237 - A Bool to tell us if the host is 32 or 64bit. 238 This is set at the start and does not change. 239 240 - An IRExpr*, which may be NULL, holding the IR expression (an 241 IRRoundingMode-encoded value) to which the FPU's rounding mode 242 was most recently set. Setting to NULL is always safe. Used to 243 avoid redundant settings of the FPU's rounding mode, as 244 described in set_FPU_rounding_mode below. 245 246 - A VexMiscInfo*, needed for knowing how to generate 247 function calls for this target 248 */ 249 250 typedef 251 struct { 252 IRTypeEnv* type_env; 253 254 HReg* vregmap; 255 HReg* vregmapHI; 256 Int n_vregmap; 257 258 HReg savedLR; 259 260 HInstrArray* code; 261 262 Int vreg_ctr; 263 264 /* 27 Jan 06: Not currently used, but should be */ 265 UInt hwcaps; 266 267 Bool mode64; 268 269 IRExpr* previous_rm; 270 271 VexAbiInfo* vbi; 272 } 273 ISelEnv; 274 275 276 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp ) 277 { 278 vassert(tmp >= 0); 279 vassert(tmp < env->n_vregmap); 280 return env->vregmap[tmp]; 281 } 282 283 static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO, 284 ISelEnv* env, IRTemp tmp ) 285 { 286 vassert(!env->mode64); 287 vassert(tmp >= 0); 288 vassert(tmp < env->n_vregmap); 289 vassert(env->vregmapHI[tmp] != INVALID_HREG); 290 *vrLO = env->vregmap[tmp]; 291 *vrHI = env->vregmapHI[tmp]; 292 } 293 294 static void addInstr ( ISelEnv* env, PPCInstr* instr ) 295 { 296 addHInstr(env->code, instr); 297 if (vex_traceflags & VEX_TRACE_VCODE) { 298 ppPPCInstr(instr, env->mode64); 299 vex_printf("\n"); 300 } 301 } 302 303 static HReg newVRegI ( ISelEnv* env ) 304 { 305 HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64), 306 True/*virtual reg*/); 307 env->vreg_ctr++; 308 return reg; 309 } 310 311 static HReg newVRegF ( ISelEnv* env ) 312 { 313 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/); 314 env->vreg_ctr++; 315 return reg; 316 } 317 318 static HReg newVRegV ( ISelEnv* env ) 319 { 320 HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/); 321 env->vreg_ctr++; 322 return reg; 323 } 324 325 326 /*---------------------------------------------------------*/ 327 /*--- ISEL: Forward declarations ---*/ 328 /*---------------------------------------------------------*/ 329 330 /* These are organised as iselXXX and iselXXX_wrk pairs. The 331 iselXXX_wrk do the real work, but are not to be called directly. 332 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then 333 checks that all returned registers are virtual. You should not 334 call the _wrk version directly. 335 336 'Word' refers to the size of the native machine word, that is, 337 32-bit int in 32-bit mode and 64-bit int in 64-bit mode. '2Word' 338 therefore refers to a double-width (64/128-bit) quantity in two 339 integer registers. 340 */ 341 /* 32-bit mode: compute an I8/I16/I32 into a GPR. 342 64-bit mode: compute an I8/I16/I32/I64 into a GPR. */ 343 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e ); 344 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e ); 345 346 /* 32-bit mode: Compute an I8/I16/I32 into a RH 347 (reg-or-halfword-immediate). 348 64-bit mode: Compute an I8/I16/I32/I64 into a RH 349 (reg-or-halfword-immediate). 350 It's important to specify whether the immediate is to be regarded 351 as signed or not. If yes, this will never return -32768 as an 352 immediate; this guaranteed that all signed immediates that are 353 return can have their sign inverted if need be. 354 */ 355 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, 356 Bool syned, IRExpr* e ); 357 static PPCRH* iselWordExpr_RH ( ISelEnv* env, 358 Bool syned, IRExpr* e ); 359 360 /* 32-bit mode: compute an I32 into a RI (reg or 32-bit immediate). 361 64-bit mode: compute an I64 into a RI (reg or 64-bit immediate). */ 362 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e ); 363 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e ); 364 365 /* In 32 bit mode ONLY, compute an I8 into a 366 reg-or-5-bit-unsigned-immediate, the latter being an immediate in 367 the range 1 .. 31 inclusive. Used for doing shift amounts. */ 368 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e ); 369 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e ); 370 371 /* In 64-bit mode ONLY, compute an I8 into a 372 reg-or-6-bit-unsigned-immediate, the latter being an immediate in 373 the range 1 .. 63 inclusive. Used for doing shift amounts. */ 374 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e ); 375 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e ); 376 377 /* 32-bit mode: compute an I32 into an AMode. 378 64-bit mode: compute an I64 into an AMode. 379 380 Requires to know (xferTy) the type of data to be loaded/stored 381 using this amode. That is so that, for 64-bit code generation, any 382 PPCAMode_IR returned will have an index (immediate offset) field 383 that is guaranteed to be 4-aligned, if there is any chance that the 384 amode is to be used in ld/ldu/lda/std/stdu. 385 386 Since there are no such restrictions on 32-bit insns, xferTy is 387 ignored for 32-bit code generation. */ 388 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy ); 389 static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy ); 390 391 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */ 392 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, 393 ISelEnv* env, IRExpr* e ); 394 static void iselInt64Expr ( HReg* rHi, HReg* rLo, 395 ISelEnv* env, IRExpr* e ); 396 397 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */ 398 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, 399 ISelEnv* env, IRExpr* e ); 400 static void iselInt128Expr ( HReg* rHi, HReg* rLo, 401 ISelEnv* env, IRExpr* e ); 402 403 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ); 404 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e ); 405 406 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ); 407 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ); 408 409 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ); 410 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ); 411 412 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ); 413 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e ); 414 415 416 /*---------------------------------------------------------*/ 417 /*--- ISEL: Misc helpers ---*/ 418 /*---------------------------------------------------------*/ 419 420 /* Make an int reg-reg move. */ 421 422 static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src ) 423 { 424 vassert(hregClass(r_dst) == hregClass(r_src)); 425 vassert(hregClass(r_src) == HRcInt32 || 426 hregClass(r_src) == HRcInt64); 427 return PPCInstr_Alu(Palu_OR, r_dst, r_src, PPCRH_Reg(r_src)); 428 } 429 430 /* Advance/retreat %r1 by n. */ 431 432 static void add_to_sp ( ISelEnv* env, UInt n ) 433 { 434 HReg sp = StackFramePtr(env->mode64); 435 vassert(n < 256 && (n%16) == 0); 436 addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp, 437 PPCRH_Imm(True,toUShort(n)) )); 438 } 439 440 static void sub_from_sp ( ISelEnv* env, UInt n ) 441 { 442 HReg sp = StackFramePtr(env->mode64); 443 vassert(n < 256 && (n%16) == 0); 444 addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp, 445 PPCRH_Imm(True,toUShort(n)) )); 446 } 447 448 /* 449 returns a quadword aligned address on the stack 450 - copies SP, adds 16bytes, aligns to quadword. 451 use sub_from_sp(32) before calling this, 452 as expects to have 32 bytes to play with. 453 */ 454 static HReg get_sp_aligned16 ( ISelEnv* env ) 455 { 456 HReg r = newVRegI(env); 457 HReg align16 = newVRegI(env); 458 addInstr(env, mk_iMOVds_RR(r, StackFramePtr(env->mode64))); 459 // add 16 460 addInstr(env, PPCInstr_Alu( Palu_ADD, r, r, 461 PPCRH_Imm(True,toUShort(16)) )); 462 // mask to quadword 463 addInstr(env, 464 PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64)); 465 addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16))); 466 return r; 467 } 468 469 470 471 /* Load 2*I32 regs to fp reg */ 472 static HReg mk_LoadRR32toFPR ( ISelEnv* env, 473 HReg r_srcHi, HReg r_srcLo ) 474 { 475 HReg fr_dst = newVRegF(env); 476 PPCAMode *am_addr0, *am_addr1; 477 478 vassert(!env->mode64); 479 vassert(hregClass(r_srcHi) == HRcInt32); 480 vassert(hregClass(r_srcLo) == HRcInt32); 481 482 sub_from_sp( env, 16 ); // Move SP down 16 bytes 483 am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 484 am_addr1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 485 486 // store hi,lo as Ity_I32's 487 addInstr(env, PPCInstr_Store( 4, am_addr0, r_srcHi, env->mode64 )); 488 addInstr(env, PPCInstr_Store( 4, am_addr1, r_srcLo, env->mode64 )); 489 490 // load as float 491 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0)); 492 493 add_to_sp( env, 16 ); // Reset SP 494 return fr_dst; 495 } 496 497 /* Load I64 reg to fp reg */ 498 static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src ) 499 { 500 HReg fr_dst = newVRegF(env); 501 PPCAMode *am_addr0; 502 503 vassert(env->mode64); 504 vassert(hregClass(r_src) == HRcInt64); 505 506 sub_from_sp( env, 16 ); // Move SP down 16 bytes 507 am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 508 509 // store as Ity_I64 510 addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 )); 511 512 // load as float 513 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0)); 514 515 add_to_sp( env, 16 ); // Reset SP 516 return fr_dst; 517 } 518 519 520 /* Given an amode, return one which references 4 bytes further 521 along. */ 522 523 static PPCAMode* advance4 ( ISelEnv* env, PPCAMode* am ) 524 { 525 PPCAMode* am4 = dopyPPCAMode( am ); 526 if (am4->tag == Pam_IR 527 && am4->Pam.IR.index + 4 <= 32767) { 528 am4->Pam.IR.index += 4; 529 } else { 530 vpanic("advance4(ppc,host)"); 531 } 532 return am4; 533 } 534 535 536 /* Given a guest-state array descriptor, an index expression and a 537 bias, generate a PPCAMode pointing at the relevant piece of 538 guest state. */ 539 static 540 PPCAMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr, 541 IRExpr* off, Int bias ) 542 { 543 HReg rtmp, roff; 544 Int elemSz = sizeofIRType(descr->elemTy); 545 Int nElems = descr->nElems; 546 Int shift = 0; 547 548 /* Throw out any cases we don't need. In theory there might be a 549 day where we need to handle others, but not today. */ 550 551 if (nElems != 16 && nElems != 32) 552 vpanic("genGuestArrayOffset(ppc host)(1)"); 553 554 switch (elemSz) { 555 case 4: shift = 2; break; 556 case 8: shift = 3; break; 557 default: vpanic("genGuestArrayOffset(ppc host)(2)"); 558 } 559 560 if (bias < -100 || bias > 100) /* somewhat arbitrarily */ 561 vpanic("genGuestArrayOffset(ppc host)(3)"); 562 if (descr->base < 0 || descr->base > 4000) /* somewhat arbitrarily */ 563 vpanic("genGuestArrayOffset(ppc host)(4)"); 564 565 /* Compute off into a reg, %off. Then return: 566 567 addi %tmp, %off, bias (if bias != 0) 568 andi %tmp, nElems-1 569 sldi %tmp, shift 570 addi %tmp, %tmp, base 571 ... Baseblockptr + %tmp ... 572 */ 573 roff = iselWordExpr_R(env, off); 574 rtmp = newVRegI(env); 575 addInstr(env, PPCInstr_Alu( 576 Palu_ADD, 577 rtmp, roff, 578 PPCRH_Imm(True/*signed*/, toUShort(bias)))); 579 addInstr(env, PPCInstr_Alu( 580 Palu_AND, 581 rtmp, rtmp, 582 PPCRH_Imm(False/*unsigned*/, toUShort(nElems-1)))); 583 addInstr(env, PPCInstr_Shft( 584 Pshft_SHL, 585 env->mode64 ? False : True/*F:64-bit, T:32-bit shift*/, 586 rtmp, rtmp, 587 PPCRH_Imm(False/*unsigned*/, toUShort(shift)))); 588 addInstr(env, PPCInstr_Alu( 589 Palu_ADD, 590 rtmp, rtmp, 591 PPCRH_Imm(True/*signed*/, toUShort(descr->base)))); 592 return 593 PPCAMode_RR( GuestStatePtr(env->mode64), rtmp ); 594 } 595 596 597 /*---------------------------------------------------------*/ 598 /*--- ISEL: Function call helpers ---*/ 599 /*---------------------------------------------------------*/ 600 601 /* Used only in doHelperCall. See big comment in doHelperCall re 602 handling of register-parameter args. This function figures out 603 whether evaluation of an expression might require use of a fixed 604 register. If in doubt return True (safe but suboptimal). 605 */ 606 static 607 Bool mightRequireFixedRegs ( IRExpr* e ) 608 { 609 switch (e->tag) { 610 case Iex_RdTmp: case Iex_Const: case Iex_Get: 611 return False; 612 default: 613 return True; 614 } 615 } 616 617 618 /* Do a complete function call. guard is a Ity_Bit expression 619 indicating whether or not the call happens. If guard==NULL, the 620 call is unconditional. */ 621 622 static 623 void doHelperCall ( ISelEnv* env, 624 Bool passBBP, 625 IRExpr* guard, IRCallee* cee, IRExpr** args ) 626 { 627 PPCCondCode cc; 628 HReg argregs[PPC_N_REGPARMS]; 629 HReg tmpregs[PPC_N_REGPARMS]; 630 Bool go_fast; 631 Int n_args, i, argreg; 632 UInt argiregs; 633 ULong target; 634 Bool mode64 = env->mode64; 635 636 /* Do we need to force use of an odd-even reg pair for 64-bit 637 args? */ 638 Bool regalign_int64s 639 = (!mode64) && env->vbi->host_ppc32_regalign_int64_args; 640 641 /* Marshal args for a call and do the call. 642 643 If passBBP is True, %rbp (the baseblock pointer) is to be passed 644 as the first arg. 645 646 This function only deals with a tiny set of possibilities, which 647 cover all helpers in practice. The restrictions are that only 648 arguments in registers are supported, hence only PPC_N_REGPARMS x 649 (mode32:32 | mode64:64) integer bits in total can be passed. 650 In fact the only supported arg type is (mode32:I32 | mode64:I64). 651 652 Generating code which is both efficient and correct when 653 parameters are to be passed in registers is difficult, for the 654 reasons elaborated in detail in comments attached to 655 doHelperCall() in priv/host-x86/isel.c. Here, we use a variant 656 of the method described in those comments. 657 658 The problem is split into two cases: the fast scheme and the 659 slow scheme. In the fast scheme, arguments are computed 660 directly into the target (real) registers. This is only safe 661 when we can be sure that computation of each argument will not 662 trash any real registers set by computation of any other 663 argument. 664 665 In the slow scheme, all args are first computed into vregs, and 666 once they are all done, they are moved to the relevant real 667 regs. This always gives correct code, but it also gives a bunch 668 of vreg-to-rreg moves which are usually redundant but are hard 669 for the register allocator to get rid of. 670 671 To decide which scheme to use, all argument expressions are 672 first examined. If they are all so simple that it is clear they 673 will be evaluated without use of any fixed registers, use the 674 fast scheme, else use the slow scheme. Note also that only 675 unconditional calls may use the fast scheme, since having to 676 compute a condition expression could itself trash real 677 registers. 678 679 Note this requires being able to examine an expression and 680 determine whether or not evaluation of it might use a fixed 681 register. That requires knowledge of how the rest of this insn 682 selector works. Currently just the following 3 are regarded as 683 safe -- hopefully they cover the majority of arguments in 684 practice: IRExpr_Tmp IRExpr_Const IRExpr_Get. 685 */ 686 687 /* Note that the cee->regparms field is meaningless on PPC32/64 host 688 (since there is only one calling convention) and so we always 689 ignore it. */ 690 691 n_args = 0; 692 for (i = 0; args[i]; i++) 693 n_args++; 694 695 if (PPC_N_REGPARMS < n_args + (passBBP ? 1 : 0)) { 696 vpanic("doHelperCall(PPC): cannot currently handle > 8 args"); 697 // PPC_N_REGPARMS 698 } 699 700 argregs[0] = hregPPC_GPR3(mode64); 701 argregs[1] = hregPPC_GPR4(mode64); 702 argregs[2] = hregPPC_GPR5(mode64); 703 argregs[3] = hregPPC_GPR6(mode64); 704 argregs[4] = hregPPC_GPR7(mode64); 705 argregs[5] = hregPPC_GPR8(mode64); 706 argregs[6] = hregPPC_GPR9(mode64); 707 argregs[7] = hregPPC_GPR10(mode64); 708 argiregs = 0; 709 710 tmpregs[0] = tmpregs[1] = tmpregs[2] = 711 tmpregs[3] = tmpregs[4] = tmpregs[5] = 712 tmpregs[6] = tmpregs[7] = INVALID_HREG; 713 714 /* First decide which scheme (slow or fast) is to be used. First 715 assume the fast scheme, and select slow if any contraindications 716 (wow) appear. */ 717 718 go_fast = True; 719 720 if (guard) { 721 if (guard->tag == Iex_Const 722 && guard->Iex.Const.con->tag == Ico_U1 723 && guard->Iex.Const.con->Ico.U1 == True) { 724 /* unconditional */ 725 } else { 726 /* Not manifestly unconditional -- be conservative. */ 727 go_fast = False; 728 } 729 } 730 731 if (go_fast) { 732 for (i = 0; i < n_args; i++) { 733 if (mightRequireFixedRegs(args[i])) { 734 go_fast = False; 735 break; 736 } 737 } 738 } 739 740 /* At this point the scheme to use has been established. Generate 741 code to get the arg values into the argument rregs. */ 742 743 if (go_fast) { 744 745 /* FAST SCHEME */ 746 argreg = 0; 747 if (passBBP) { 748 argiregs |= (1 << (argreg+3)); 749 addInstr(env, mk_iMOVds_RR( argregs[argreg], 750 GuestStatePtr(mode64) )); 751 argreg++; 752 } 753 754 for (i = 0; i < n_args; i++) { 755 vassert(argreg < PPC_N_REGPARMS); 756 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 || 757 typeOfIRExpr(env->type_env, args[i]) == Ity_I64); 758 if (!mode64) { 759 if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { 760 argiregs |= (1 << (argreg+3)); 761 addInstr(env, 762 mk_iMOVds_RR( argregs[argreg], 763 iselWordExpr_R(env, args[i]) )); 764 } else { // Ity_I64 765 HReg rHi, rLo; 766 if (regalign_int64s && (argreg%2) == 1) 767 // ppc32 ELF abi spec for passing LONG_LONG 768 argreg++; // XXX: odd argreg => even rN 769 vassert(argreg < PPC_N_REGPARMS-1); 770 iselInt64Expr(&rHi,&rLo, env, args[i]); 771 argiregs |= (1 << (argreg+3)); 772 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi )); 773 argiregs |= (1 << (argreg+3)); 774 addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo)); 775 } 776 } else { // mode64 777 argiregs |= (1 << (argreg+3)); 778 addInstr(env, mk_iMOVds_RR( argregs[argreg], 779 iselWordExpr_R(env, args[i]) )); 780 } 781 argreg++; 782 } 783 784 /* Fast scheme only applies for unconditional calls. Hence: */ 785 cc.test = Pct_ALWAYS; 786 787 } else { 788 789 /* SLOW SCHEME; move via temporaries */ 790 argreg = 0; 791 792 if (passBBP) { 793 /* This is pretty stupid; better to move directly to r3 794 after the rest of the args are done. */ 795 tmpregs[argreg] = newVRegI(env); 796 addInstr(env, mk_iMOVds_RR( tmpregs[argreg], 797 GuestStatePtr(mode64) )); 798 argreg++; 799 } 800 801 for (i = 0; i < n_args; i++) { 802 vassert(argreg < PPC_N_REGPARMS); 803 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 || 804 typeOfIRExpr(env->type_env, args[i]) == Ity_I64); 805 if (!mode64) { 806 if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { 807 tmpregs[argreg] = iselWordExpr_R(env, args[i]); 808 } else { // Ity_I64 809 HReg rHi, rLo; 810 if (regalign_int64s && (argreg%2) == 1) 811 // ppc32 ELF abi spec for passing LONG_LONG 812 argreg++; // XXX: odd argreg => even rN 813 vassert(argreg < PPC_N_REGPARMS-1); 814 iselInt64Expr(&rHi,&rLo, env, args[i]); 815 tmpregs[argreg++] = rHi; 816 tmpregs[argreg] = rLo; 817 } 818 } else { // mode64 819 tmpregs[argreg] = iselWordExpr_R(env, args[i]); 820 } 821 argreg++; 822 } 823 824 /* Now we can compute the condition. We can't do it earlier 825 because the argument computations could trash the condition 826 codes. Be a bit clever to handle the common case where the 827 guard is 1:Bit. */ 828 cc.test = Pct_ALWAYS; 829 if (guard) { 830 if (guard->tag == Iex_Const 831 && guard->Iex.Const.con->tag == Ico_U1 832 && guard->Iex.Const.con->Ico.U1 == True) { 833 /* unconditional -- do nothing */ 834 } else { 835 cc = iselCondCode( env, guard ); 836 } 837 } 838 839 /* Move the args to their final destinations. */ 840 for (i = 0; i < argreg; i++) { 841 if (tmpregs[i] == INVALID_HREG) // Skip invalid regs 842 continue; 843 /* None of these insns, including any spill code that might 844 be generated, may alter the condition codes. */ 845 argiregs |= (1 << (i+3)); 846 addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) ); 847 } 848 849 } 850 851 target = mode64 ? Ptr_to_ULong(cee->addr) : 852 toUInt(Ptr_to_ULong(cee->addr)); 853 854 /* Finally, the call itself. */ 855 addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs )); 856 } 857 858 859 /*---------------------------------------------------------*/ 860 /*--- ISEL: FP rounding mode helpers ---*/ 861 /*---------------------------------------------------------*/ 862 863 ///* Set FPU's rounding mode to the default */ 864 //static 865 //void set_FPU_rounding_default ( ISelEnv* env ) 866 //{ 867 // HReg fr_src = newVRegF(env); 868 // HReg r_src = newVRegI(env); 869 // 870 // /* Default rounding mode = 0x0 871 // Only supporting the rounding-mode bits - the rest of FPSCR is 0x0 872 // - so we can set the whole register at once (faster) 873 // note: upper 32 bits ignored by FpLdFPSCR 874 // */ 875 // addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64)); 876 // if (env->mode64) { 877 // fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64 878 // } else { 879 // fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64 880 // } 881 // addInstr(env, PPCInstr_FpLdFPSCR( fr_src )); 882 //} 883 884 /* Convert IR rounding mode to PPC encoding */ 885 static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR ) 886 { 887 /* 888 rounding mode | PPC | IR 889 ------------------------ 890 to nearest | 00 | 00 891 to zero | 01 | 11 892 to +infinity | 10 | 10 893 to -infinity | 11 | 01 894 */ 895 HReg r_rmPPC = newVRegI(env); 896 HReg r_tmp1 = newVRegI(env); 897 898 vassert(hregClass(r_rmIR) == HRcGPR(env->mode64)); 899 900 // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3 901 // 902 // slwi tmp1, r_rmIR, 1 903 // xor tmp1, r_rmIR, tmp1 904 // andi r_rmPPC, tmp1, 3 905 906 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 907 r_tmp1, r_rmIR, PPCRH_Imm(False,1))); 908 909 addInstr(env, PPCInstr_Alu( Palu_XOR, r_tmp1, r_rmIR, 910 PPCRH_Reg(r_tmp1) )); 911 912 addInstr(env, PPCInstr_Alu( Palu_AND, r_rmPPC, r_tmp1, 913 PPCRH_Imm(False,3) )); 914 915 return r_rmPPC; 916 } 917 918 919 /* Set the FPU's rounding mode: 'mode' is an I32-typed expression 920 denoting a value in the range 0 .. 3, indicating a round mode 921 encoded as per type IRRoundingMode. Set the PPC FPSCR to have the 922 same rounding. 923 924 For speed & simplicity, we're setting the *entire* FPSCR here. 925 926 Setting the rounding mode is expensive. So this function tries to 927 avoid repeatedly setting the rounding mode to the same thing by 928 first comparing 'mode' to the 'mode' tree supplied in the previous 929 call to this function, if any. (The previous value is stored in 930 env->previous_rm.) If 'mode' is a single IR temporary 't' and 931 env->previous_rm is also just 't', then the setting is skipped. 932 933 This is safe because of the SSA property of IR: an IR temporary can 934 only be defined once and so will have the same value regardless of 935 where it appears in the block. Cool stuff, SSA. 936 937 A safety condition: all attempts to set the RM must be aware of 938 this mechanism - by being routed through the functions here. 939 940 Of course this only helps if blocks where the RM is set more than 941 once and it is set to the same value each time, *and* that value is 942 held in the same IR temporary each time. In order to assure the 943 latter as much as possible, the IR optimiser takes care to do CSE 944 on any block with any sign of floating point activity. 945 */ 946 static 947 void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode ) 948 { 949 HReg fr_src = newVRegF(env); 950 HReg r_src; 951 952 vassert(typeOfIRExpr(env->type_env,mode) == Ity_I32); 953 954 /* Do we need to do anything? */ 955 if (env->previous_rm 956 && env->previous_rm->tag == Iex_RdTmp 957 && mode->tag == Iex_RdTmp 958 && env->previous_rm->Iex.RdTmp.tmp == mode->Iex.RdTmp.tmp) { 959 /* no - setting it to what it was before. */ 960 vassert(typeOfIRExpr(env->type_env, env->previous_rm) == Ity_I32); 961 return; 962 } 963 964 /* No luck - we better set it, and remember what we set it to. */ 965 env->previous_rm = mode; 966 967 /* Only supporting the rounding-mode bits - the rest of FPSCR is 968 0x0 - so we can set the whole register at once (faster). */ 969 970 // Resolve rounding mode and convert to PPC representation 971 r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode) ); 972 // gpr -> fpr 973 if (env->mode64) { 974 fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64 975 } else { 976 fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64 977 } 978 979 // Move to FPSCR 980 addInstr(env, PPCInstr_FpLdFPSCR( fr_src )); 981 } 982 983 984 /*---------------------------------------------------------*/ 985 /*--- ISEL: vector helpers ---*/ 986 /*---------------------------------------------------------*/ 987 988 /* Generate all-zeroes into a new vector register. 989 */ 990 static HReg generate_zeroes_V128 ( ISelEnv* env ) 991 { 992 HReg dst = newVRegV(env); 993 addInstr(env, PPCInstr_AvBinary(Pav_XOR, dst, dst, dst)); 994 return dst; 995 } 996 997 /* Generate all-ones into a new vector register. 998 */ 999 static HReg generate_ones_V128 ( ISelEnv* env ) 1000 { 1001 HReg dst = newVRegV(env); 1002 PPCVI5s * src = PPCVI5s_Imm(-1); 1003 addInstr(env, PPCInstr_AvSplat(8, dst, src)); 1004 return dst; 1005 } 1006 1007 1008 /* 1009 Generates code for AvSplat 1010 - takes in IRExpr* of type 8|16|32 1011 returns vector reg of duplicated lanes of input 1012 - uses AvSplat(imm) for imms up to simm6. 1013 otherwise must use store reg & load vector 1014 */ 1015 static HReg mk_AvDuplicateRI( ISelEnv* env, IRExpr* e ) 1016 { 1017 HReg r_src; 1018 HReg dst = newVRegV(env); 1019 PPCRI* ri = iselWordExpr_RI(env, e); 1020 IRType ty = typeOfIRExpr(env->type_env,e); 1021 UInt sz = (ty == Ity_I8) ? 8 : (ty == Ity_I16) ? 16 : 32; 1022 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32); 1023 1024 /* special case: immediate */ 1025 if (ri->tag == Pri_Imm) { 1026 Int simm32 = (Int)ri->Pri.Imm; 1027 1028 /* figure out if it's do-able with imm splats. */ 1029 if (simm32 >= -32 && simm32 <= 31) { 1030 Char simm6 = (Char)simm32; 1031 if (simm6 > 15) { /* 16:31 inclusive */ 1032 HReg v1 = newVRegV(env); 1033 HReg v2 = newVRegV(env); 1034 addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16))); 1035 addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6-16))); 1036 addInstr(env, 1037 (sz== 8) ? PPCInstr_AvBin8x16(Pav_SUBU, dst, v2, v1) : 1038 (sz==16) ? PPCInstr_AvBin16x8(Pav_SUBU, dst, v2, v1) 1039 : PPCInstr_AvBin32x4(Pav_SUBU, dst, v2, v1) ); 1040 return dst; 1041 } 1042 if (simm6 < -16) { /* -32:-17 inclusive */ 1043 HReg v1 = newVRegV(env); 1044 HReg v2 = newVRegV(env); 1045 addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16))); 1046 addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6+16))); 1047 addInstr(env, 1048 (sz== 8) ? PPCInstr_AvBin8x16(Pav_ADDU, dst, v2, v1) : 1049 (sz==16) ? PPCInstr_AvBin16x8(Pav_ADDU, dst, v2, v1) 1050 : PPCInstr_AvBin32x4(Pav_ADDU, dst, v2, v1) ); 1051 return dst; 1052 } 1053 /* simplest form: -16:15 inclusive */ 1054 addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6))); 1055 return dst; 1056 } 1057 1058 /* no luck; use the Slow way. */ 1059 r_src = newVRegI(env); 1060 addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64)); 1061 } 1062 else { 1063 r_src = ri->Pri.Reg; 1064 } 1065 1066 /* default case: store r_src in lowest lane of 16-aligned mem, 1067 load vector, splat lowest lane to dst */ 1068 { 1069 /* CAB: Maybe faster to store r_src multiple times (sz dependent), 1070 and simply load the vector? */ 1071 HReg r_aligned16; 1072 HReg v_src = newVRegV(env); 1073 PPCAMode *am_off12; 1074 1075 sub_from_sp( env, 32 ); // Move SP down 1076 /* Get a 16-aligned address within our stack space */ 1077 r_aligned16 = get_sp_aligned16( env ); 1078 am_off12 = PPCAMode_IR( 12, r_aligned16 ); 1079 1080 /* Store r_src in low word of 16-aligned mem */ 1081 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, env->mode64 )); 1082 1083 /* Load src to vector[low lane] */ 1084 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, v_src, am_off12 ) ); 1085 add_to_sp( env, 32 ); // Reset SP 1086 1087 /* Finally, splat v_src[low_lane] to dst */ 1088 addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Reg(v_src))); 1089 return dst; 1090 } 1091 } 1092 1093 1094 /* for each lane of vSrc: lane == nan ? laneX = all 1's : all 0's */ 1095 static HReg isNan ( ISelEnv* env, HReg vSrc ) 1096 { 1097 HReg zeros, msk_exp, msk_mnt, expt, mnts, vIsNan; 1098 1099 vassert(hregClass(vSrc) == HRcVec128); 1100 1101 zeros = mk_AvDuplicateRI(env, mkU32(0)); 1102 msk_exp = mk_AvDuplicateRI(env, mkU32(0x7F800000)); 1103 msk_mnt = mk_AvDuplicateRI(env, mkU32(0x7FFFFF)); 1104 expt = newVRegV(env); 1105 mnts = newVRegV(env); 1106 vIsNan = newVRegV(env); 1107 1108 /* 32bit float => sign(1) | exponent(8) | mantissa(23) 1109 nan => exponent all ones, mantissa > 0 */ 1110 1111 addInstr(env, PPCInstr_AvBinary(Pav_AND, expt, vSrc, msk_exp)); 1112 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, expt, expt, msk_exp)); 1113 addInstr(env, PPCInstr_AvBinary(Pav_AND, mnts, vSrc, msk_mnt)); 1114 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPGTU, mnts, mnts, zeros)); 1115 addInstr(env, PPCInstr_AvBinary(Pav_AND, vIsNan, expt, mnts)); 1116 return vIsNan; 1117 } 1118 1119 1120 /*---------------------------------------------------------*/ 1121 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/ 1122 /*---------------------------------------------------------*/ 1123 1124 /* Select insns for an integer-typed expression, and add them to the 1125 code list. Return a reg holding the result. This reg will be a 1126 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you 1127 want to modify it, ask for a new vreg, copy it in there, and modify 1128 the copy. The register allocator will do its best to map both 1129 vregs to the same real register, so the copies will often disappear 1130 later in the game. 1131 1132 This should handle expressions of 64, 32, 16 and 8-bit type. 1133 All results are returned in a (mode64 ? 64bit : 32bit) register. 1134 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits 1135 are arbitrary, so you should mask or sign extend partial values 1136 if necessary. 1137 */ 1138 1139 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e ) 1140 { 1141 HReg r = iselWordExpr_R_wrk(env, e); 1142 /* sanity checks ... */ 1143 # if 0 1144 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 1145 # endif 1146 1147 vassert(hregClass(r) == HRcGPR(env->mode64)); 1148 vassert(hregIsVirtual(r)); 1149 return r; 1150 } 1151 1152 /* DO NOT CALL THIS DIRECTLY ! */ 1153 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e ) 1154 { 1155 Bool mode64 = env->mode64; 1156 MatchInfo mi; 1157 DECLARE_PATTERN(p_32to1_then_1Uto8); 1158 1159 IRType ty = typeOfIRExpr(env->type_env,e); 1160 vassert(ty == Ity_I8 || ty == Ity_I16 || 1161 ty == Ity_I32 || ((ty == Ity_I64) && mode64)); 1162 1163 switch (e->tag) { 1164 1165 /* --------- TEMP --------- */ 1166 case Iex_RdTmp: 1167 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 1168 1169 /* --------- LOAD --------- */ 1170 case Iex_Load: { 1171 HReg r_dst; 1172 PPCAMode* am_addr; 1173 if (e->Iex.Load.end != Iend_BE) 1174 goto irreducible; 1175 r_dst = newVRegI(env); 1176 am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/ ); 1177 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)), 1178 r_dst, am_addr, mode64 )); 1179 return r_dst; 1180 /*NOTREACHED*/ 1181 } 1182 1183 /* --------- BINARY OP --------- */ 1184 case Iex_Binop: { 1185 PPCAluOp aluOp; 1186 PPCShftOp shftOp; 1187 1188 /* Is it an addition or logical style op? */ 1189 switch (e->Iex.Binop.op) { 1190 case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64: 1191 aluOp = Palu_ADD; break; 1192 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64: 1193 aluOp = Palu_SUB; break; 1194 case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64: 1195 aluOp = Palu_AND; break; 1196 case Iop_Or8: case Iop_Or16: case Iop_Or32: case Iop_Or64: 1197 aluOp = Palu_OR; break; 1198 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: case Iop_Xor64: 1199 aluOp = Palu_XOR; break; 1200 default: 1201 aluOp = Palu_INVALID; break; 1202 } 1203 /* For commutative ops we assume any literal 1204 values are on the second operand. */ 1205 if (aluOp != Palu_INVALID) { 1206 HReg r_dst = newVRegI(env); 1207 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1208 PPCRH* ri_srcR = NULL; 1209 /* get right arg into an RH, in the appropriate way */ 1210 switch (aluOp) { 1211 case Palu_ADD: case Palu_SUB: 1212 ri_srcR = iselWordExpr_RH(env, True/*signed*/, 1213 e->Iex.Binop.arg2); 1214 break; 1215 case Palu_AND: case Palu_OR: case Palu_XOR: 1216 ri_srcR = iselWordExpr_RH(env, False/*signed*/, 1217 e->Iex.Binop.arg2); 1218 break; 1219 default: 1220 vpanic("iselWordExpr_R_wrk-aluOp-arg2"); 1221 } 1222 addInstr(env, PPCInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR)); 1223 return r_dst; 1224 } 1225 1226 /* a shift? */ 1227 switch (e->Iex.Binop.op) { 1228 case Iop_Shl8: case Iop_Shl16: case Iop_Shl32: case Iop_Shl64: 1229 shftOp = Pshft_SHL; break; 1230 case Iop_Shr8: case Iop_Shr16: case Iop_Shr32: case Iop_Shr64: 1231 shftOp = Pshft_SHR; break; 1232 case Iop_Sar8: case Iop_Sar16: case Iop_Sar32: case Iop_Sar64: 1233 shftOp = Pshft_SAR; break; 1234 default: 1235 shftOp = Pshft_INVALID; break; 1236 } 1237 /* we assume any literal values are on the second operand. */ 1238 if (shftOp != Pshft_INVALID) { 1239 HReg r_dst = newVRegI(env); 1240 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1241 PPCRH* ri_srcR = NULL; 1242 /* get right arg into an RH, in the appropriate way */ 1243 switch (shftOp) { 1244 case Pshft_SHL: case Pshft_SHR: case Pshft_SAR: 1245 if (!mode64) 1246 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2); 1247 else 1248 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2); 1249 break; 1250 default: 1251 vpanic("iselIntExpr_R_wrk-shftOp-arg2"); 1252 } 1253 /* widen the left arg if needed */ 1254 if (shftOp == Pshft_SHR || shftOp == Pshft_SAR) { 1255 if (ty == Ity_I8 || ty == Ity_I16) { 1256 PPCRH* amt = PPCRH_Imm(False, 1257 toUShort(ty == Ity_I8 ? 24 : 16)); 1258 HReg tmp = newVRegI(env); 1259 addInstr(env, PPCInstr_Shft(Pshft_SHL, 1260 True/*32bit shift*/, 1261 tmp, r_srcL, amt)); 1262 addInstr(env, PPCInstr_Shft(shftOp, 1263 True/*32bit shift*/, 1264 tmp, tmp, amt)); 1265 r_srcL = tmp; 1266 vassert(0); /* AWAITING TEST CASE */ 1267 } 1268 } 1269 /* Only 64 expressions need 64bit shifts, 1270 32bit shifts are fine for all others */ 1271 if (ty == Ity_I64) { 1272 vassert(mode64); 1273 addInstr(env, PPCInstr_Shft(shftOp, False/*64bit shift*/, 1274 r_dst, r_srcL, ri_srcR)); 1275 } else { 1276 addInstr(env, PPCInstr_Shft(shftOp, True/*32bit shift*/, 1277 r_dst, r_srcL, ri_srcR)); 1278 } 1279 return r_dst; 1280 } 1281 1282 /* How about a div? */ 1283 if (e->Iex.Binop.op == Iop_DivS32 || 1284 e->Iex.Binop.op == Iop_DivU32) { 1285 Bool syned = toBool(e->Iex.Binop.op == Iop_DivS32); 1286 HReg r_dst = newVRegI(env); 1287 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1288 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1289 addInstr(env, PPCInstr_Div(syned, True/*32bit div*/, 1290 r_dst, r_srcL, r_srcR)); 1291 return r_dst; 1292 } 1293 if (e->Iex.Binop.op == Iop_DivS64 || 1294 e->Iex.Binop.op == Iop_DivU64) { 1295 Bool syned = toBool(e->Iex.Binop.op == Iop_DivS64); 1296 HReg r_dst = newVRegI(env); 1297 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1298 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1299 vassert(mode64); 1300 addInstr(env, PPCInstr_Div(syned, False/*64bit div*/, 1301 r_dst, r_srcL, r_srcR)); 1302 return r_dst; 1303 } 1304 1305 /* No? Anyone for a mul? */ 1306 if (e->Iex.Binop.op == Iop_Mul32 1307 || e->Iex.Binop.op == Iop_Mul64) { 1308 Bool syned = False; 1309 Bool sz32 = (e->Iex.Binop.op != Iop_Mul64); 1310 HReg r_dst = newVRegI(env); 1311 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1312 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1313 addInstr(env, PPCInstr_MulL(syned, False/*lo32*/, sz32, 1314 r_dst, r_srcL, r_srcR)); 1315 return r_dst; 1316 } 1317 1318 /* 32 x 32 -> 64 multiply */ 1319 if (mode64 1320 && (e->Iex.Binop.op == Iop_MullU32 1321 || e->Iex.Binop.op == Iop_MullS32)) { 1322 HReg tLo = newVRegI(env); 1323 HReg tHi = newVRegI(env); 1324 HReg r_dst = newVRegI(env); 1325 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32); 1326 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1327 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 1328 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 1329 False/*lo32*/, True/*32bit mul*/, 1330 tLo, r_srcL, r_srcR)); 1331 addInstr(env, PPCInstr_MulL(syned, 1332 True/*hi32*/, True/*32bit mul*/, 1333 tHi, r_srcL, r_srcR)); 1334 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/, 1335 r_dst, tHi, PPCRH_Imm(False,32))); 1336 addInstr(env, PPCInstr_Alu(Palu_OR, 1337 r_dst, r_dst, PPCRH_Reg(tLo))); 1338 return r_dst; 1339 } 1340 1341 /* El-mutanto 3-way compare? */ 1342 if (e->Iex.Binop.op == Iop_CmpORD32S 1343 || e->Iex.Binop.op == Iop_CmpORD32U) { 1344 Bool syned = toBool(e->Iex.Binop.op == Iop_CmpORD32S); 1345 HReg dst = newVRegI(env); 1346 HReg srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1347 PPCRH* srcR = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2); 1348 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/, 1349 7/*cr*/, srcL, srcR)); 1350 addInstr(env, PPCInstr_MfCR(dst)); 1351 addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst, 1352 PPCRH_Imm(False,7<<1))); 1353 return dst; 1354 } 1355 1356 if (e->Iex.Binop.op == Iop_CmpORD64S 1357 || e->Iex.Binop.op == Iop_CmpORD64U) { 1358 Bool syned = toBool(e->Iex.Binop.op == Iop_CmpORD64S); 1359 HReg dst = newVRegI(env); 1360 HReg srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 1361 PPCRH* srcR = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2); 1362 vassert(mode64); 1363 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/, 1364 7/*cr*/, srcL, srcR)); 1365 addInstr(env, PPCInstr_MfCR(dst)); 1366 addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst, 1367 PPCRH_Imm(False,7<<1))); 1368 return dst; 1369 } 1370 1371 if (e->Iex.Binop.op == Iop_Max32U) { 1372 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 1373 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2); 1374 HReg rdst = newVRegI(env); 1375 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7LT ); 1376 addInstr(env, mk_iMOVds_RR(rdst, r1)); 1377 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 1378 7/*cr*/, rdst, PPCRH_Reg(r2))); 1379 addInstr(env, PPCInstr_CMov(cc, rdst, PPCRI_Reg(r2))); 1380 return rdst; 1381 } 1382 1383 if (e->Iex.Binop.op == Iop_32HLto64) { 1384 HReg r_Hi = iselWordExpr_R(env, e->Iex.Binop.arg1); 1385 HReg r_Lo = iselWordExpr_R(env, e->Iex.Binop.arg2); 1386 HReg r_dst = newVRegI(env); 1387 HReg msk = newVRegI(env); 1388 vassert(mode64); 1389 /* r_dst = OR( r_Hi<<32, r_Lo ) */ 1390 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/, 1391 r_dst, r_Hi, PPCRH_Imm(False,32))); 1392 addInstr(env, PPCInstr_LI(msk, 0xFFFFFFFF, mode64)); 1393 addInstr(env, PPCInstr_Alu( Palu_AND, r_Lo, r_Lo, 1394 PPCRH_Reg(msk) )); 1395 addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst, 1396 PPCRH_Reg(r_Lo) )); 1397 return r_dst; 1398 } 1399 1400 if (e->Iex.Binop.op == Iop_CmpF64) { 1401 HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1); 1402 HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2); 1403 1404 HReg r_ccPPC = newVRegI(env); 1405 HReg r_ccIR = newVRegI(env); 1406 HReg r_ccIR_b0 = newVRegI(env); 1407 HReg r_ccIR_b2 = newVRegI(env); 1408 HReg r_ccIR_b6 = newVRegI(env); 1409 1410 addInstr(env, PPCInstr_FpCmp(r_ccPPC, fr_srcL, fr_srcR)); 1411 1412 /* Map compare result from PPC to IR, 1413 conforming to CmpF64 definition. */ 1414 /* 1415 FP cmp result | PPC | IR 1416 -------------------------- 1417 UN | 0x1 | 0x45 1418 EQ | 0x2 | 0x40 1419 GT | 0x4 | 0x00 1420 LT | 0x8 | 0x01 1421 */ 1422 1423 // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3] 1424 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/, 1425 r_ccIR_b0, r_ccPPC, 1426 PPCRH_Imm(False,0x3))); 1427 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR_b0, 1428 r_ccPPC, PPCRH_Reg(r_ccIR_b0))); 1429 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b0, 1430 r_ccIR_b0, PPCRH_Imm(False,0x1))); 1431 1432 // r_ccIR_b2 = r_ccPPC[0] 1433 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 1434 r_ccIR_b2, r_ccPPC, 1435 PPCRH_Imm(False,0x2))); 1436 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b2, 1437 r_ccIR_b2, PPCRH_Imm(False,0x4))); 1438 1439 // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1] 1440 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/, 1441 r_ccIR_b6, r_ccPPC, 1442 PPCRH_Imm(False,0x1))); 1443 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR_b6, 1444 r_ccPPC, PPCRH_Reg(r_ccIR_b6))); 1445 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 1446 r_ccIR_b6, r_ccIR_b6, 1447 PPCRH_Imm(False,0x6))); 1448 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b6, 1449 r_ccIR_b6, PPCRH_Imm(False,0x40))); 1450 1451 // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 1452 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR, 1453 r_ccIR_b0, PPCRH_Reg(r_ccIR_b2))); 1454 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR, 1455 r_ccIR, PPCRH_Reg(r_ccIR_b6))); 1456 return r_ccIR; 1457 } 1458 1459 if (e->Iex.Binop.op == Iop_F64toI32S) { 1460 /* This works in both mode64 and mode32. */ 1461 HReg r1 = StackFramePtr(env->mode64); 1462 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 1463 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2); 1464 HReg ftmp = newVRegF(env); 1465 HReg idst = newVRegI(env); 1466 1467 /* Set host rounding mode */ 1468 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 1469 1470 sub_from_sp( env, 16 ); 1471 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, True/*int32*/, 1472 ftmp, fsrc)); 1473 addInstr(env, PPCInstr_FpSTFIW(r1, ftmp)); 1474 addInstr(env, PPCInstr_Load(4, idst, zero_r1, mode64)); 1475 1476 /* in 64-bit mode we need to sign-widen idst. */ 1477 if (mode64) 1478 addInstr(env, PPCInstr_Unary(Pun_EXTSW, idst, idst)); 1479 1480 add_to_sp( env, 16 ); 1481 1482 ///* Restore default FPU rounding. */ 1483 //set_FPU_rounding_default( env ); 1484 return idst; 1485 } 1486 1487 if (e->Iex.Binop.op == Iop_F64toI64S) { 1488 if (mode64) { 1489 HReg r1 = StackFramePtr(env->mode64); 1490 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 1491 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2); 1492 HReg idst = newVRegI(env); 1493 HReg ftmp = newVRegF(env); 1494 1495 /* Set host rounding mode */ 1496 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 1497 1498 sub_from_sp( env, 16 ); 1499 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, 1500 ftmp, fsrc)); 1501 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1)); 1502 addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/)); 1503 add_to_sp( env, 16 ); 1504 1505 ///* Restore default FPU rounding. */ 1506 //set_FPU_rounding_default( env ); 1507 return idst; 1508 } 1509 } 1510 1511 break; 1512 } 1513 1514 /* --------- UNARY OP --------- */ 1515 case Iex_Unop: { 1516 IROp op_unop = e->Iex.Unop.op; 1517 1518 /* 1Uto8(32to1(expr32)) */ 1519 DEFINE_PATTERN(p_32to1_then_1Uto8, 1520 unop(Iop_1Uto8,unop(Iop_32to1,bind(0)))); 1521 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) { 1522 IRExpr* expr32 = mi.bindee[0]; 1523 HReg r_dst = newVRegI(env); 1524 HReg r_src = iselWordExpr_R(env, expr32); 1525 addInstr(env, PPCInstr_Alu(Palu_AND, r_dst, 1526 r_src, PPCRH_Imm(False,1))); 1527 return r_dst; 1528 } 1529 1530 /* 16Uto32(LDbe:I16(expr32)) */ 1531 { 1532 DECLARE_PATTERN(p_LDbe16_then_16Uto32); 1533 DEFINE_PATTERN(p_LDbe16_then_16Uto32, 1534 unop(Iop_16Uto32, 1535 IRExpr_Load(Iend_BE,Ity_I16,bind(0))) ); 1536 if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) { 1537 HReg r_dst = newVRegI(env); 1538 PPCAMode* amode 1539 = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/ ); 1540 addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64)); 1541 return r_dst; 1542 } 1543 } 1544 1545 switch (op_unop) { 1546 case Iop_8Uto16: 1547 case Iop_8Uto32: 1548 case Iop_8Uto64: 1549 case Iop_16Uto32: 1550 case Iop_16Uto64: { 1551 HReg r_dst = newVRegI(env); 1552 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1553 UShort mask = toUShort(op_unop==Iop_16Uto64 ? 0xFFFF : 1554 op_unop==Iop_16Uto32 ? 0xFFFF : 0xFF); 1555 addInstr(env, PPCInstr_Alu(Palu_AND,r_dst,r_src, 1556 PPCRH_Imm(False,mask))); 1557 return r_dst; 1558 } 1559 case Iop_32Uto64: { 1560 HReg r_dst = newVRegI(env); 1561 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1562 vassert(mode64); 1563 addInstr(env, 1564 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/, 1565 r_dst, r_src, PPCRH_Imm(False,32))); 1566 addInstr(env, 1567 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/, 1568 r_dst, r_dst, PPCRH_Imm(False,32))); 1569 return r_dst; 1570 } 1571 case Iop_8Sto16: 1572 case Iop_8Sto32: 1573 case Iop_16Sto32: { 1574 HReg r_dst = newVRegI(env); 1575 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1576 UShort amt = toUShort(op_unop==Iop_16Sto32 ? 16 : 24); 1577 addInstr(env, 1578 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 1579 r_dst, r_src, PPCRH_Imm(False,amt))); 1580 addInstr(env, 1581 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 1582 r_dst, r_dst, PPCRH_Imm(False,amt))); 1583 return r_dst; 1584 } 1585 case Iop_8Sto64: 1586 case Iop_16Sto64: { 1587 HReg r_dst = newVRegI(env); 1588 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1589 UShort amt = toUShort(op_unop==Iop_8Sto64 ? 56 : 1590 op_unop==Iop_16Sto64 ? 48 : 32); 1591 vassert(mode64); 1592 addInstr(env, 1593 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/, 1594 r_dst, r_src, PPCRH_Imm(False,amt))); 1595 addInstr(env, 1596 PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/, 1597 r_dst, r_dst, PPCRH_Imm(False,amt))); 1598 return r_dst; 1599 } 1600 case Iop_32Sto64: { 1601 HReg r_dst = newVRegI(env); 1602 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1603 vassert(mode64); 1604 /* According to the IBM docs, in 64 bit mode, srawi r,r,0 1605 sign extends the lower 32 bits into the upper 32 bits. */ 1606 addInstr(env, 1607 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 1608 r_dst, r_src, PPCRH_Imm(False,0))); 1609 return r_dst; 1610 } 1611 case Iop_Not8: 1612 case Iop_Not16: 1613 case Iop_Not32: 1614 case Iop_Not64: { 1615 HReg r_dst = newVRegI(env); 1616 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1617 addInstr(env, PPCInstr_Unary(Pun_NOT,r_dst,r_src)); 1618 return r_dst; 1619 } 1620 case Iop_64HIto32: { 1621 if (!mode64) { 1622 HReg rHi, rLo; 1623 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); 1624 return rHi; /* and abandon rLo .. poor wee thing :-) */ 1625 } else { 1626 HReg r_dst = newVRegI(env); 1627 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1628 addInstr(env, 1629 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/, 1630 r_dst, r_src, PPCRH_Imm(False,32))); 1631 return r_dst; 1632 } 1633 } 1634 case Iop_64to32: { 1635 if (!mode64) { 1636 HReg rHi, rLo; 1637 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); 1638 return rLo; /* similar stupid comment to the above ... */ 1639 } else { 1640 /* This is a no-op. */ 1641 return iselWordExpr_R(env, e->Iex.Unop.arg); 1642 } 1643 } 1644 case Iop_64to16: { 1645 if (mode64) { /* This is a no-op. */ 1646 return iselWordExpr_R(env, e->Iex.Unop.arg); 1647 } 1648 break; /* evidently not used in 32-bit mode */ 1649 } 1650 case Iop_16HIto8: 1651 case Iop_32HIto16: { 1652 HReg r_dst = newVRegI(env); 1653 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1654 UShort shift = toUShort(op_unop == Iop_16HIto8 ? 8 : 16); 1655 addInstr(env, 1656 PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/, 1657 r_dst, r_src, PPCRH_Imm(False,shift))); 1658 return r_dst; 1659 } 1660 case Iop_128HIto64: 1661 if (mode64) { 1662 HReg rHi, rLo; 1663 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg); 1664 return rHi; /* and abandon rLo .. poor wee thing :-) */ 1665 } 1666 break; 1667 case Iop_128to64: 1668 if (mode64) { 1669 HReg rHi, rLo; 1670 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg); 1671 return rLo; /* similar stupid comment to the above ... */ 1672 } 1673 break; 1674 case Iop_1Uto32: 1675 case Iop_1Uto8: { 1676 HReg r_dst = newVRegI(env); 1677 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg); 1678 addInstr(env, PPCInstr_Set(cond,r_dst)); 1679 return r_dst; 1680 } 1681 case Iop_1Sto8: 1682 case Iop_1Sto16: 1683 case Iop_1Sto32: { 1684 /* could do better than this, but for now ... */ 1685 HReg r_dst = newVRegI(env); 1686 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg); 1687 addInstr(env, PPCInstr_Set(cond,r_dst)); 1688 addInstr(env, 1689 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 1690 r_dst, r_dst, PPCRH_Imm(False,31))); 1691 addInstr(env, 1692 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 1693 r_dst, r_dst, PPCRH_Imm(False,31))); 1694 return r_dst; 1695 } 1696 case Iop_1Sto64: 1697 if (mode64) { 1698 /* could do better than this, but for now ... */ 1699 HReg r_dst = newVRegI(env); 1700 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg); 1701 addInstr(env, PPCInstr_Set(cond,r_dst)); 1702 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/, 1703 r_dst, r_dst, PPCRH_Imm(False,63))); 1704 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/, 1705 r_dst, r_dst, PPCRH_Imm(False,63))); 1706 return r_dst; 1707 } 1708 break; 1709 case Iop_Clz32: 1710 case Iop_Clz64: { 1711 HReg r_src, r_dst; 1712 PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 : 1713 Pun_CLZ64; 1714 if (op_unop == Iop_Clz64 && !mode64) 1715 goto irreducible; 1716 /* Count leading zeroes. */ 1717 r_dst = newVRegI(env); 1718 r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1719 addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src)); 1720 return r_dst; 1721 } 1722 1723 case Iop_Left8: 1724 case Iop_Left32: 1725 case Iop_Left64: { 1726 HReg r_src, r_dst; 1727 if (op_unop == Iop_Left64 && !mode64) 1728 goto irreducible; 1729 r_dst = newVRegI(env); 1730 r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1731 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src)); 1732 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src))); 1733 return r_dst; 1734 } 1735 1736 case Iop_CmpwNEZ32: { 1737 HReg r_dst = newVRegI(env); 1738 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1739 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src)); 1740 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src))); 1741 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 1742 r_dst, r_dst, PPCRH_Imm(False, 31))); 1743 return r_dst; 1744 } 1745 1746 case Iop_CmpwNEZ64: { 1747 HReg r_dst = newVRegI(env); 1748 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 1749 if (!mode64) goto irreducible; 1750 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src)); 1751 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src))); 1752 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/, 1753 r_dst, r_dst, PPCRH_Imm(False, 63))); 1754 return r_dst; 1755 } 1756 1757 case Iop_V128to32: { 1758 HReg r_aligned16; 1759 HReg dst = newVRegI(env); 1760 HReg vec = iselVecExpr(env, e->Iex.Unop.arg); 1761 PPCAMode *am_off0, *am_off12; 1762 sub_from_sp( env, 32 ); // Move SP down 32 bytes 1763 1764 // get a quadword aligned address within our stack space 1765 r_aligned16 = get_sp_aligned16( env ); 1766 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 1767 am_off12 = PPCAMode_IR( 12,r_aligned16 ); 1768 1769 // store vec, load low word to dst 1770 addInstr(env, 1771 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 )); 1772 addInstr(env, 1773 PPCInstr_Load( 4, dst, am_off12, mode64 )); 1774 1775 add_to_sp( env, 32 ); // Reset SP 1776 return dst; 1777 } 1778 1779 case Iop_V128to64: 1780 case Iop_V128HIto64: 1781 if (mode64) { 1782 HReg r_aligned16; 1783 HReg dst = newVRegI(env); 1784 HReg vec = iselVecExpr(env, e->Iex.Unop.arg); 1785 PPCAMode *am_off0, *am_off8; 1786 sub_from_sp( env, 32 ); // Move SP down 32 bytes 1787 1788 // get a quadword aligned address within our stack space 1789 r_aligned16 = get_sp_aligned16( env ); 1790 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 1791 am_off8 = PPCAMode_IR( 8 ,r_aligned16 ); 1792 1793 // store vec, load low word (+8) or high (+0) to dst 1794 addInstr(env, 1795 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 )); 1796 addInstr(env, 1797 PPCInstr_Load( 1798 8, dst, 1799 op_unop == Iop_V128HIto64 ? am_off0 : am_off8, 1800 mode64 )); 1801 1802 add_to_sp( env, 32 ); // Reset SP 1803 return dst; 1804 } 1805 break; 1806 case Iop_16to8: 1807 case Iop_32to8: 1808 case Iop_32to16: 1809 case Iop_64to8: 1810 /* These are no-ops. */ 1811 return iselWordExpr_R(env, e->Iex.Unop.arg); 1812 1813 /* ReinterpF64asI64(e) */ 1814 /* Given an IEEE754 double, produce an I64 with the same bit 1815 pattern. */ 1816 case Iop_ReinterpF64asI64: 1817 if (mode64) { 1818 PPCAMode *am_addr; 1819 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg); 1820 HReg r_dst = newVRegI(env); 1821 1822 sub_from_sp( env, 16 ); // Move SP down 16 bytes 1823 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) ); 1824 1825 // store as F64 1826 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8, 1827 fr_src, am_addr )); 1828 // load as Ity_I64 1829 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 )); 1830 1831 add_to_sp( env, 16 ); // Reset SP 1832 return r_dst; 1833 } 1834 break; 1835 1836 /* ReinterpF32asI32(e) */ 1837 /* Given an IEEE754 float, produce an I32 with the same bit 1838 pattern. */ 1839 case Iop_ReinterpF32asI32: { 1840 /* I believe this generates correct code for both 32- and 1841 64-bit hosts. */ 1842 PPCAMode *am_addr; 1843 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg); 1844 HReg r_dst = newVRegI(env); 1845 1846 sub_from_sp( env, 16 ); // Move SP down 16 bytes 1847 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) ); 1848 1849 // store as F32 1850 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4, 1851 fr_src, am_addr )); 1852 // load as Ity_I32 1853 addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 )); 1854 1855 add_to_sp( env, 16 ); // Reset SP 1856 return r_dst; 1857 } 1858 1859 default: 1860 break; 1861 } 1862 break; 1863 } 1864 1865 /* --------- GET --------- */ 1866 case Iex_Get: { 1867 if (ty == Ity_I8 || ty == Ity_I16 || 1868 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) { 1869 HReg r_dst = newVRegI(env); 1870 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 1871 GuestStatePtr(mode64) ); 1872 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)), 1873 r_dst, am_addr, mode64 )); 1874 return r_dst; 1875 } 1876 break; 1877 } 1878 1879 case Iex_GetI: { 1880 PPCAMode* src_am 1881 = genGuestArrayOffset( env, e->Iex.GetI.descr, 1882 e->Iex.GetI.ix, e->Iex.GetI.bias ); 1883 HReg r_dst = newVRegI(env); 1884 if (mode64 && ty == Ity_I64) { 1885 addInstr(env, PPCInstr_Load( toUChar(8), 1886 r_dst, src_am, mode64 )); 1887 return r_dst; 1888 } 1889 if ((!mode64) && ty == Ity_I32) { 1890 addInstr(env, PPCInstr_Load( toUChar(4), 1891 r_dst, src_am, mode64 )); 1892 return r_dst; 1893 } 1894 break; 1895 } 1896 1897 /* --------- CCALL --------- */ 1898 case Iex_CCall: { 1899 HReg r_dst = newVRegI(env); 1900 vassert(ty == Ity_I32); 1901 1902 /* be very restrictive for now. Only 32/64-bit ints allowed 1903 for args, and 32 bits for return type. */ 1904 if (e->Iex.CCall.retty != Ity_I32) 1905 goto irreducible; 1906 1907 /* Marshal args, do the call, clear stack. */ 1908 doHelperCall( env, False, NULL, 1909 e->Iex.CCall.cee, e->Iex.CCall.args ); 1910 1911 /* GPR3 now holds the destination address from Pin_Goto */ 1912 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64))); 1913 return r_dst; 1914 } 1915 1916 /* --------- LITERAL --------- */ 1917 /* 32/16/8-bit literals */ 1918 case Iex_Const: { 1919 Long l; 1920 HReg r_dst = newVRegI(env); 1921 IRConst* con = e->Iex.Const.con; 1922 switch (con->tag) { 1923 case Ico_U64: if (!mode64) goto irreducible; 1924 l = (Long) con->Ico.U64; break; 1925 case Ico_U32: l = (Long)(Int) con->Ico.U32; break; 1926 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break; 1927 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break; 1928 default: vpanic("iselIntExpr_R.const(ppc)"); 1929 } 1930 addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64)); 1931 return r_dst; 1932 } 1933 1934 /* --------- MULTIPLEX --------- */ 1935 case Iex_Mux0X: { 1936 if ((ty == Ity_I8 || ty == Ity_I16 || 1937 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) && 1938 typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) { 1939 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 1940 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond); 1941 HReg rX = iselWordExpr_R(env, e->Iex.Mux0X.exprX); 1942 PPCRI* r0 = iselWordExpr_RI(env, e->Iex.Mux0X.expr0); 1943 HReg r_dst = newVRegI(env); 1944 HReg r_tmp = newVRegI(env); 1945 addInstr(env, mk_iMOVds_RR(r_dst,rX)); 1946 addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp, 1947 r_cond, PPCRH_Imm(False,0xFF))); 1948 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 1949 7/*cr*/, r_tmp, PPCRH_Imm(False,0))); 1950 addInstr(env, PPCInstr_CMov(cc,r_dst,r0)); 1951 return r_dst; 1952 } 1953 break; 1954 } 1955 1956 default: 1957 break; 1958 } /* switch (e->tag) */ 1959 1960 1961 /* We get here if no pattern matched. */ 1962 irreducible: 1963 ppIRExpr(e); 1964 vpanic("iselIntExpr_R(ppc): cannot reduce tree"); 1965 } 1966 1967 1968 /*---------------------------------------------------------*/ 1969 /*--- ISEL: Integer expression auxiliaries ---*/ 1970 /*---------------------------------------------------------*/ 1971 1972 /* --------------------- AMODEs --------------------- */ 1973 1974 /* Return an AMode which computes the value of the specified 1975 expression, possibly also adding insns to the code list as a 1976 result. The expression may only be a word-size one. 1977 */ 1978 1979 static Bool uInt_fits_in_16_bits ( UInt u ) 1980 { 1981 /* Is u the same as the sign-extend of its lower 16 bits? */ 1982 Int i = u & 0xFFFF; 1983 i <<= 16; 1984 i >>= 16; 1985 return toBool(u == (UInt)i); 1986 } 1987 1988 static Bool uLong_fits_in_16_bits ( ULong u ) 1989 { 1990 /* Is u the same as the sign-extend of its lower 16 bits? */ 1991 Long i = u & 0xFFFFULL; 1992 i <<= 48; 1993 i >>= 48; 1994 return toBool(u == (ULong)i); 1995 } 1996 1997 static Bool uLong_is_4_aligned ( ULong u ) 1998 { 1999 return toBool((u & 3ULL) == 0); 2000 } 2001 2002 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am ) 2003 { 2004 Bool mode64 = env->mode64; 2005 switch (am->tag) { 2006 case Pam_IR: 2007 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus, 2008 somehow, but I think it's OK. */ 2009 return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) && 2010 hregIsVirtual(am->Pam.IR.base) && 2011 uInt_fits_in_16_bits(am->Pam.IR.index) ); 2012 case Pam_RR: 2013 return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) && 2014 hregIsVirtual(am->Pam.RR.base) && 2015 hregClass(am->Pam.RR.index) == HRcGPR(mode64) && 2016 hregIsVirtual(am->Pam.IR.index) ); 2017 default: 2018 vpanic("sane_AMode: unknown ppc amode tag"); 2019 } 2020 } 2021 2022 static 2023 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy ) 2024 { 2025 PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy); 2026 vassert(sane_AMode(env, am)); 2027 return am; 2028 } 2029 2030 /* DO NOT CALL THIS DIRECTLY ! */ 2031 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy ) 2032 { 2033 IRType ty = typeOfIRExpr(env->type_env,e); 2034 2035 if (env->mode64) { 2036 2037 /* If the data load/store type is I32 or I64, this amode might 2038 be destined for use in ld/ldu/lwa/st/stu. In which case 2039 insist that if it comes out as an _IR, the immediate must 2040 have its bottom two bits be zero. This does assume that for 2041 any other type (I8/I16/I128/F32/F64/V128) the amode will not 2042 be parked in any such instruction. But that seems a 2043 reasonable assumption. */ 2044 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64); 2045 2046 vassert(ty == Ity_I64); 2047 2048 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */ 2049 if (e->tag == Iex_Binop 2050 && e->Iex.Binop.op == Iop_Add64 2051 && e->Iex.Binop.arg2->tag == Iex_Const 2052 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64 2053 && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2 2054 ->Iex.Const.con->Ico.U64) 2055 : True) 2056 && uLong_fits_in_16_bits(e->Iex.Binop.arg2 2057 ->Iex.Const.con->Ico.U64)) { 2058 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64, 2059 iselWordExpr_R(env, e->Iex.Binop.arg1) ); 2060 } 2061 2062 /* Add64(expr,expr) */ 2063 if (e->tag == Iex_Binop 2064 && e->Iex.Binop.op == Iop_Add64) { 2065 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1); 2066 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2); 2067 return PPCAMode_RR( r_idx, r_base ); 2068 } 2069 2070 } else { 2071 2072 vassert(ty == Ity_I32); 2073 2074 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */ 2075 if (e->tag == Iex_Binop 2076 && e->Iex.Binop.op == Iop_Add32 2077 && e->Iex.Binop.arg2->tag == Iex_Const 2078 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32 2079 && uInt_fits_in_16_bits(e->Iex.Binop.arg2 2080 ->Iex.Const.con->Ico.U32)) { 2081 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, 2082 iselWordExpr_R(env, e->Iex.Binop.arg1) ); 2083 } 2084 2085 /* Add32(expr,expr) */ 2086 if (e->tag == Iex_Binop 2087 && e->Iex.Binop.op == Iop_Add32) { 2088 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1); 2089 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2); 2090 return PPCAMode_RR( r_idx, r_base ); 2091 } 2092 2093 } 2094 2095 /* Doesn't match anything in particular. Generate it into 2096 a register and use that. */ 2097 return PPCAMode_IR( 0, iselWordExpr_R(env,e) ); 2098 } 2099 2100 2101 /* --------------------- RH --------------------- */ 2102 2103 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH 2104 (reg-or-halfword-immediate). It's important to specify whether the 2105 immediate is to be regarded as signed or not. If yes, this will 2106 never return -32768 as an immediate; this guaranteed that all 2107 signed immediates that are return can have their sign inverted if 2108 need be. */ 2109 2110 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e ) 2111 { 2112 PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e); 2113 /* sanity checks ... */ 2114 switch (ri->tag) { 2115 case Prh_Imm: 2116 vassert(ri->Prh.Imm.syned == syned); 2117 if (syned) 2118 vassert(ri->Prh.Imm.imm16 != 0x8000); 2119 return ri; 2120 case Prh_Reg: 2121 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64)); 2122 vassert(hregIsVirtual(ri->Prh.Reg.reg)); 2123 return ri; 2124 default: 2125 vpanic("iselIntExpr_RH: unknown ppc RH tag"); 2126 } 2127 } 2128 2129 /* DO NOT CALL THIS DIRECTLY ! */ 2130 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e ) 2131 { 2132 ULong u; 2133 Long l; 2134 IRType ty = typeOfIRExpr(env->type_env,e); 2135 vassert(ty == Ity_I8 || ty == Ity_I16 || 2136 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64)); 2137 2138 /* special case: immediate */ 2139 if (e->tag == Iex_Const) { 2140 IRConst* con = e->Iex.Const.con; 2141 /* What value are we aiming to generate? */ 2142 switch (con->tag) { 2143 /* Note: Not sign-extending - we carry 'syned' around */ 2144 case Ico_U64: vassert(env->mode64); 2145 u = con->Ico.U64; break; 2146 case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break; 2147 case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break; 2148 case Ico_U8: u = 0x000000FF & con->Ico.U8; break; 2149 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)"); 2150 } 2151 l = (Long)u; 2152 /* Now figure out if it's representable. */ 2153 if (!syned && u <= 65535) { 2154 return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF)); 2155 } 2156 if (syned && l >= -32767 && l <= 32767) { 2157 return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF)); 2158 } 2159 /* no luck; use the Slow Way. */ 2160 } 2161 2162 /* default case: calculate into a register and return that */ 2163 return PPCRH_Reg( iselWordExpr_R ( env, e ) ); 2164 } 2165 2166 2167 /* --------------------- RIs --------------------- */ 2168 2169 /* Calculate an expression into an PPCRI operand. As with 2170 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or, 2171 in 64-bit mode, 64 bits. */ 2172 2173 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e ) 2174 { 2175 PPCRI* ri = iselWordExpr_RI_wrk(env, e); 2176 /* sanity checks ... */ 2177 switch (ri->tag) { 2178 case Pri_Imm: 2179 return ri; 2180 case Pri_Reg: 2181 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64)); 2182 vassert(hregIsVirtual(ri->Pri.Reg)); 2183 return ri; 2184 default: 2185 vpanic("iselIntExpr_RI: unknown ppc RI tag"); 2186 } 2187 } 2188 2189 /* DO NOT CALL THIS DIRECTLY ! */ 2190 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e ) 2191 { 2192 Long l; 2193 IRType ty = typeOfIRExpr(env->type_env,e); 2194 vassert(ty == Ity_I8 || ty == Ity_I16 || 2195 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64)); 2196 2197 /* special case: immediate */ 2198 if (e->tag == Iex_Const) { 2199 IRConst* con = e->Iex.Const.con; 2200 switch (con->tag) { 2201 case Ico_U64: vassert(env->mode64); 2202 l = (Long) con->Ico.U64; break; 2203 case Ico_U32: l = (Long)(Int) con->Ico.U32; break; 2204 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break; 2205 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break; 2206 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)"); 2207 } 2208 return PPCRI_Imm((ULong)l); 2209 } 2210 2211 /* default case: calculate into a register and return that */ 2212 return PPCRI_Reg( iselWordExpr_R ( env, e ) ); 2213 } 2214 2215 2216 /* --------------------- RH5u --------------------- */ 2217 2218 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter 2219 being an immediate in the range 1 .. 31 inclusive. Used for doing 2220 shift amounts. Only used in 32-bit mode. */ 2221 2222 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e ) 2223 { 2224 PPCRH* ri; 2225 vassert(!env->mode64); 2226 ri = iselWordExpr_RH5u_wrk(env, e); 2227 /* sanity checks ... */ 2228 switch (ri->tag) { 2229 case Prh_Imm: 2230 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31); 2231 vassert(!ri->Prh.Imm.syned); 2232 return ri; 2233 case Prh_Reg: 2234 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64)); 2235 vassert(hregIsVirtual(ri->Prh.Reg.reg)); 2236 return ri; 2237 default: 2238 vpanic("iselIntExpr_RH5u: unknown ppc RI tag"); 2239 } 2240 } 2241 2242 /* DO NOT CALL THIS DIRECTLY ! */ 2243 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e ) 2244 { 2245 IRType ty = typeOfIRExpr(env->type_env,e); 2246 vassert(ty == Ity_I8); 2247 2248 /* special case: immediate */ 2249 if (e->tag == Iex_Const 2250 && e->Iex.Const.con->tag == Ico_U8 2251 && e->Iex.Const.con->Ico.U8 >= 1 2252 && e->Iex.Const.con->Ico.U8 <= 31) { 2253 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8); 2254 } 2255 2256 /* default case: calculate into a register and return that */ 2257 return PPCRH_Reg( iselWordExpr_R ( env, e ) ); 2258 } 2259 2260 2261 /* --------------------- RH6u --------------------- */ 2262 2263 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter 2264 being an immediate in the range 1 .. 63 inclusive. Used for doing 2265 shift amounts. Only used in 64-bit mode. */ 2266 2267 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e ) 2268 { 2269 PPCRH* ri; 2270 vassert(env->mode64); 2271 ri = iselWordExpr_RH6u_wrk(env, e); 2272 /* sanity checks ... */ 2273 switch (ri->tag) { 2274 case Prh_Imm: 2275 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63); 2276 vassert(!ri->Prh.Imm.syned); 2277 return ri; 2278 case Prh_Reg: 2279 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64)); 2280 vassert(hregIsVirtual(ri->Prh.Reg.reg)); 2281 return ri; 2282 default: 2283 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag"); 2284 } 2285 } 2286 2287 /* DO NOT CALL THIS DIRECTLY ! */ 2288 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e ) 2289 { 2290 IRType ty = typeOfIRExpr(env->type_env,e); 2291 vassert(ty == Ity_I8); 2292 2293 /* special case: immediate */ 2294 if (e->tag == Iex_Const 2295 && e->Iex.Const.con->tag == Ico_U8 2296 && e->Iex.Const.con->Ico.U8 >= 1 2297 && e->Iex.Const.con->Ico.U8 <= 63) { 2298 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8); 2299 } 2300 2301 /* default case: calculate into a register and return that */ 2302 return PPCRH_Reg( iselWordExpr_R ( env, e ) ); 2303 } 2304 2305 2306 /* --------------------- CONDCODE --------------------- */ 2307 2308 /* Generate code to evaluated a bit-typed expression, returning the 2309 condition code which would correspond when the expression would 2310 notionally have returned 1. */ 2311 2312 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e ) 2313 { 2314 /* Uh, there's nothing we can sanity check here, unfortunately. */ 2315 return iselCondCode_wrk(env,e); 2316 } 2317 2318 /* DO NOT CALL THIS DIRECTLY ! */ 2319 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e ) 2320 { 2321 vassert(e); 2322 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1); 2323 2324 /* Constant 1:Bit */ 2325 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) { 2326 // Make a compare that will always be true: 2327 HReg r_zero = newVRegI(env); 2328 addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64)); 2329 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2330 7/*cr*/, r_zero, PPCRH_Reg(r_zero))); 2331 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2332 } 2333 2334 /* Not1(...) */ 2335 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) { 2336 /* Generate code for the arg, and negate the test condition */ 2337 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg); 2338 cond.test = invertCondTest(cond.test); 2339 return cond; 2340 } 2341 2342 /* --- patterns rooted at: 32to1 or 64to1 --- */ 2343 2344 /* 32to1, 64to1 */ 2345 if (e->tag == Iex_Unop && 2346 (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) { 2347 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2348 HReg tmp = newVRegI(env); 2349 /* could do better, probably -- andi. */ 2350 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, 2351 src, PPCRH_Imm(False,1))); 2352 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2353 7/*cr*/, tmp, PPCRH_Imm(False,1))); 2354 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2355 } 2356 2357 /* --- patterns rooted at: CmpNEZ8 --- */ 2358 2359 /* CmpNEZ8(x) */ 2360 /* could do better -- andi. */ 2361 if (e->tag == Iex_Unop 2362 && e->Iex.Unop.op == Iop_CmpNEZ8) { 2363 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg); 2364 HReg tmp = newVRegI(env); 2365 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg, 2366 PPCRH_Imm(False,0xFF))); 2367 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2368 7/*cr*/, tmp, PPCRH_Imm(False,0))); 2369 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2370 } 2371 2372 /* --- patterns rooted at: CmpNEZ32 --- */ 2373 2374 /* CmpNEZ32(x) */ 2375 if (e->tag == Iex_Unop 2376 && e->Iex.Unop.op == Iop_CmpNEZ32) { 2377 HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg); 2378 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2379 7/*cr*/, r1, PPCRH_Imm(False,0))); 2380 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2381 } 2382 2383 /* --- patterns rooted at: Cmp*32* --- */ 2384 2385 /* Cmp*32*(x,y) */ 2386 if (e->tag == Iex_Binop 2387 && (e->Iex.Binop.op == Iop_CmpEQ32 2388 || e->Iex.Binop.op == Iop_CmpNE32 2389 || e->Iex.Binop.op == Iop_CmpLT32S 2390 || e->Iex.Binop.op == Iop_CmpLT32U 2391 || e->Iex.Binop.op == Iop_CmpLE32S 2392 || e->Iex.Binop.op == Iop_CmpLE32U)) { 2393 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S || 2394 e->Iex.Binop.op == Iop_CmpLE32S); 2395 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 2396 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2); 2397 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/, 2398 7/*cr*/, r1, ri2)); 2399 2400 switch (e->Iex.Binop.op) { 2401 case Iop_CmpEQ32: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2402 case Iop_CmpNE32: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2403 case Iop_CmpLT32U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT ); 2404 case Iop_CmpLE32U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT ); 2405 default: vpanic("iselCondCode(ppc): CmpXX32"); 2406 } 2407 } 2408 2409 /* --- patterns rooted at: CmpNEZ64 --- */ 2410 2411 /* CmpNEZ64 */ 2412 if (e->tag == Iex_Unop 2413 && e->Iex.Unop.op == Iop_CmpNEZ64) { 2414 if (!env->mode64) { 2415 HReg hi, lo; 2416 HReg tmp = newVRegI(env); 2417 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg ); 2418 addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi))); 2419 addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/, 2420 7/*cr*/, tmp,PPCRH_Imm(False,0))); 2421 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2422 } else { // mode64 2423 HReg r_src = iselWordExpr_R(env, e->Iex.Binop.arg1); 2424 addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/, 2425 7/*cr*/, r_src,PPCRH_Imm(False,0))); 2426 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2427 } 2428 } 2429 2430 /* --- patterns rooted at: Cmp*64* --- */ 2431 2432 /* Cmp*64*(x,y) */ 2433 if (e->tag == Iex_Binop 2434 && (e->Iex.Binop.op == Iop_CmpEQ64 2435 || e->Iex.Binop.op == Iop_CmpNE64 2436 || e->Iex.Binop.op == Iop_CmpLT64S 2437 || e->Iex.Binop.op == Iop_CmpLT64U 2438 || e->Iex.Binop.op == Iop_CmpLE64S 2439 || e->Iex.Binop.op == Iop_CmpLE64U)) { 2440 Bool syned = (e->Iex.Binop.op == Iop_CmpLT64S || 2441 e->Iex.Binop.op == Iop_CmpLE64S); 2442 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1); 2443 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2); 2444 vassert(env->mode64); 2445 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/, 2446 7/*cr*/, r1, ri2)); 2447 2448 switch (e->Iex.Binop.op) { 2449 case Iop_CmpEQ64: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2450 case Iop_CmpNE64: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2451 case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT ); 2452 case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT ); 2453 default: vpanic("iselCondCode(ppc): CmpXX64"); 2454 } 2455 } 2456 2457 /* var */ 2458 if (e->tag == Iex_RdTmp) { 2459 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp); 2460 HReg src_masked = newVRegI(env); 2461 addInstr(env, 2462 PPCInstr_Alu(Palu_AND, src_masked, 2463 r_src, PPCRH_Imm(False,1))); 2464 addInstr(env, 2465 PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2466 7/*cr*/, src_masked, PPCRH_Imm(False,1))); 2467 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2468 } 2469 2470 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag); 2471 ppIRExpr(e); 2472 vpanic("iselCondCode(ppc)"); 2473 } 2474 2475 2476 /*---------------------------------------------------------*/ 2477 /*--- ISEL: Integer expressions (128 bit) ---*/ 2478 /*---------------------------------------------------------*/ 2479 2480 /* 64-bit mode ONLY: compute a 128-bit value into a register pair, 2481 which is returned as the first two parameters. As with 2482 iselWordExpr_R, these may be either real or virtual regs; in any 2483 case they must not be changed by subsequent code emitted by the 2484 caller. */ 2485 2486 static void iselInt128Expr ( HReg* rHi, HReg* rLo, 2487 ISelEnv* env, IRExpr* e ) 2488 { 2489 vassert(env->mode64); 2490 iselInt128Expr_wrk(rHi, rLo, env, e); 2491 # if 0 2492 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 2493 # endif 2494 vassert(hregClass(*rHi) == HRcGPR(env->mode64)); 2495 vassert(hregIsVirtual(*rHi)); 2496 vassert(hregClass(*rLo) == HRcGPR(env->mode64)); 2497 vassert(hregIsVirtual(*rLo)); 2498 } 2499 2500 /* DO NOT CALL THIS DIRECTLY ! */ 2501 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, 2502 ISelEnv* env, IRExpr* e ) 2503 { 2504 vassert(e); 2505 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128); 2506 2507 /* read 128-bit IRTemp */ 2508 if (e->tag == Iex_RdTmp) { 2509 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp); 2510 return; 2511 } 2512 2513 /* --------- BINARY ops --------- */ 2514 if (e->tag == Iex_Binop) { 2515 switch (e->Iex.Binop.op) { 2516 /* 64 x 64 -> 128 multiply */ 2517 case Iop_MullU64: 2518 case Iop_MullS64: { 2519 HReg tLo = newVRegI(env); 2520 HReg tHi = newVRegI(env); 2521 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64); 2522 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 2523 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2524 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 2525 False/*lo64*/, False/*64bit mul*/, 2526 tLo, r_srcL, r_srcR)); 2527 addInstr(env, PPCInstr_MulL(syned, 2528 True/*hi64*/, False/*64bit mul*/, 2529 tHi, r_srcL, r_srcR)); 2530 *rHi = tHi; 2531 *rLo = tLo; 2532 return; 2533 } 2534 2535 /* 64HLto128(e1,e2) */ 2536 case Iop_64HLto128: 2537 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 2538 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 2539 return; 2540 2541 default: 2542 break; 2543 } 2544 } /* if (e->tag == Iex_Binop) */ 2545 2546 2547 /* --------- UNARY ops --------- */ 2548 if (e->tag == Iex_Unop) { 2549 switch (e->Iex.Unop.op) { 2550 default: 2551 break; 2552 } 2553 } /* if (e->tag == Iex_Unop) */ 2554 2555 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag); 2556 ppIRExpr(e); 2557 vpanic("iselInt128Expr(ppc64)"); 2558 } 2559 2560 2561 /*---------------------------------------------------------*/ 2562 /*--- ISEL: Integer expressions (64 bit) ---*/ 2563 /*---------------------------------------------------------*/ 2564 2565 /* 32-bit mode ONLY: compute a 64-bit value into a register pair, 2566 which is returned as the first two parameters. As with 2567 iselIntExpr_R, these may be either real or virtual regs; in any 2568 case they must not be changed by subsequent code emitted by the 2569 caller. */ 2570 2571 static void iselInt64Expr ( HReg* rHi, HReg* rLo, 2572 ISelEnv* env, IRExpr* e ) 2573 { 2574 vassert(!env->mode64); 2575 iselInt64Expr_wrk(rHi, rLo, env, e); 2576 # if 0 2577 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 2578 # endif 2579 vassert(hregClass(*rHi) == HRcInt32); 2580 vassert(hregIsVirtual(*rHi)); 2581 vassert(hregClass(*rLo) == HRcInt32); 2582 vassert(hregIsVirtual(*rLo)); 2583 } 2584 2585 /* DO NOT CALL THIS DIRECTLY ! */ 2586 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, 2587 ISelEnv* env, IRExpr* e ) 2588 { 2589 vassert(e); 2590 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64); 2591 2592 /* 64-bit load */ 2593 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) { 2594 HReg tLo = newVRegI(env); 2595 HReg tHi = newVRegI(env); 2596 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr); 2597 vassert(!env->mode64); 2598 addInstr(env, PPCInstr_Load( 4/*byte-load*/, 2599 tHi, PPCAMode_IR( 0, r_addr ), 2600 False/*32-bit insn please*/) ); 2601 addInstr(env, PPCInstr_Load( 4/*byte-load*/, 2602 tLo, PPCAMode_IR( 4, r_addr ), 2603 False/*32-bit insn please*/) ); 2604 *rHi = tHi; 2605 *rLo = tLo; 2606 return; 2607 } 2608 2609 /* 64-bit literal */ 2610 if (e->tag == Iex_Const) { 2611 ULong w64 = e->Iex.Const.con->Ico.U64; 2612 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF; 2613 UInt wLo = ((UInt)w64) & 0xFFFFFFFF; 2614 HReg tLo = newVRegI(env); 2615 HReg tHi = newVRegI(env); 2616 vassert(e->Iex.Const.con->tag == Ico_U64); 2617 addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/)); 2618 addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/)); 2619 *rHi = tHi; 2620 *rLo = tLo; 2621 return; 2622 } 2623 2624 /* read 64-bit IRTemp */ 2625 if (e->tag == Iex_RdTmp) { 2626 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp); 2627 return; 2628 } 2629 2630 /* 64-bit GET */ 2631 if (e->tag == Iex_Get) { 2632 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 2633 GuestStatePtr(False/*mode32*/) ); 2634 PPCAMode* am_addr4 = advance4(env, am_addr); 2635 HReg tLo = newVRegI(env); 2636 HReg tHi = newVRegI(env); 2637 addInstr(env, PPCInstr_Load( 4, tHi, am_addr, False/*mode32*/ )); 2638 addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ )); 2639 *rHi = tHi; 2640 *rLo = tLo; 2641 return; 2642 } 2643 2644 /* 64-bit Mux0X */ 2645 if (e->tag == Iex_Mux0X) { 2646 HReg e0Lo, e0Hi, eXLo, eXHi; 2647 HReg tLo = newVRegI(env); 2648 HReg tHi = newVRegI(env); 2649 2650 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2651 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond); 2652 HReg r_tmp = newVRegI(env); 2653 2654 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0); 2655 iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX); 2656 addInstr(env, mk_iMOVds_RR(tHi,eXHi)); 2657 addInstr(env, mk_iMOVds_RR(tLo,eXLo)); 2658 2659 addInstr(env, PPCInstr_Alu(Palu_AND, 2660 r_tmp, r_cond, PPCRH_Imm(False,0xFF))); 2661 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2662 7/*cr*/, r_tmp, PPCRH_Imm(False,0))); 2663 2664 addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(e0Hi))); 2665 addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(e0Lo))); 2666 *rHi = tHi; 2667 *rLo = tLo; 2668 return; 2669 } 2670 2671 /* --------- BINARY ops --------- */ 2672 if (e->tag == Iex_Binop) { 2673 IROp op_binop = e->Iex.Binop.op; 2674 switch (op_binop) { 2675 /* 32 x 32 -> 64 multiply */ 2676 case Iop_MullU32: 2677 case Iop_MullS32: { 2678 HReg tLo = newVRegI(env); 2679 HReg tHi = newVRegI(env); 2680 Bool syned = toBool(op_binop == Iop_MullS32); 2681 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1); 2682 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2); 2683 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 2684 False/*lo32*/, True/*32bit mul*/, 2685 tLo, r_srcL, r_srcR)); 2686 addInstr(env, PPCInstr_MulL(syned, 2687 True/*hi32*/, True/*32bit mul*/, 2688 tHi, r_srcL, r_srcR)); 2689 *rHi = tHi; 2690 *rLo = tLo; 2691 return; 2692 } 2693 2694 /* Or64/And64/Xor64 */ 2695 case Iop_Or64: 2696 case Iop_And64: 2697 case Iop_Xor64: { 2698 HReg xLo, xHi, yLo, yHi; 2699 HReg tLo = newVRegI(env); 2700 HReg tHi = newVRegI(env); 2701 PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR : 2702 (op_binop == Iop_And64) ? Palu_AND : Palu_XOR; 2703 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 2704 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 2705 addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi))); 2706 addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo))); 2707 *rHi = tHi; 2708 *rLo = tLo; 2709 return; 2710 } 2711 2712 /* Add64 */ 2713 case Iop_Add64: { 2714 HReg xLo, xHi, yLo, yHi; 2715 HReg tLo = newVRegI(env); 2716 HReg tHi = newVRegI(env); 2717 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1); 2718 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2); 2719 addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/, 2720 tLo, xLo, yLo)); 2721 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/, 2722 tHi, xHi, yHi)); 2723 *rHi = tHi; 2724 *rLo = tLo; 2725 return; 2726 } 2727 2728 /* 32HLto64(e1,e2) */ 2729 case Iop_32HLto64: 2730 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 2731 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 2732 return; 2733 2734 /* F64toI64S */ 2735 case Iop_F64toI64S: { 2736 HReg tLo = newVRegI(env); 2737 HReg tHi = newVRegI(env); 2738 HReg r1 = StackFramePtr(env->mode64); 2739 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 2740 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 ); 2741 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2); 2742 HReg ftmp = newVRegF(env); 2743 2744 vassert(!env->mode64); 2745 /* Set host rounding mode */ 2746 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 2747 2748 sub_from_sp( env, 16 ); 2749 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, 2750 ftmp, fsrc)); 2751 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1)); 2752 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/)); 2753 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/)); 2754 add_to_sp( env, 16 ); 2755 2756 ///* Restore default FPU rounding. */ 2757 //set_FPU_rounding_default( env ); 2758 *rHi = tHi; 2759 *rLo = tLo; 2760 return; 2761 } 2762 2763 default: 2764 break; 2765 } 2766 } /* if (e->tag == Iex_Binop) */ 2767 2768 2769 /* --------- UNARY ops --------- */ 2770 if (e->tag == Iex_Unop) { 2771 switch (e->Iex.Unop.op) { 2772 2773 /* CmpwNEZ64(e) */ 2774 case Iop_CmpwNEZ64: { 2775 HReg argHi, argLo; 2776 HReg tmp1 = newVRegI(env); 2777 HReg tmp2 = newVRegI(env); 2778 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg); 2779 /* tmp1 = argHi | argLo */ 2780 addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo))); 2781 /* tmp2 = (tmp1 | -tmp1) >>s 31 */ 2782 addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1)); 2783 addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1))); 2784 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 2785 tmp2, tmp2, PPCRH_Imm(False, 31))); 2786 *rHi = tmp2; 2787 *rLo = tmp2; /* yes, really tmp2 */ 2788 return; 2789 } 2790 2791 /* Left64 */ 2792 case Iop_Left64: { 2793 HReg argHi, argLo; 2794 HReg zero32 = newVRegI(env); 2795 HReg resHi = newVRegI(env); 2796 HReg resLo = newVRegI(env); 2797 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg); 2798 vassert(env->mode64 == False); 2799 addInstr(env, PPCInstr_LI(zero32, 0, env->mode64)); 2800 /* resHi:resLo = - argHi:argLo */ 2801 addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/, 2802 resLo, zero32, argLo )); 2803 addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/, 2804 resHi, zero32, argHi )); 2805 /* resHi:resLo |= srcHi:srcLo */ 2806 addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo))); 2807 addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi))); 2808 *rHi = resHi; 2809 *rLo = resLo; 2810 return; 2811 } 2812 2813 /* 32Sto64(e) */ 2814 case Iop_32Sto64: { 2815 HReg tHi = newVRegI(env); 2816 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg); 2817 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 2818 tHi, src, PPCRH_Imm(False,31))); 2819 *rHi = tHi; 2820 *rLo = src; 2821 return; 2822 } 2823 2824 /* 32Uto64(e) */ 2825 case Iop_32Uto64: { 2826 HReg tHi = newVRegI(env); 2827 HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg); 2828 addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/)); 2829 *rHi = tHi; 2830 *rLo = tLo; 2831 return; 2832 } 2833 2834 /* V128{HI}to64 */ 2835 case Iop_V128HIto64: 2836 case Iop_V128to64: { 2837 HReg r_aligned16; 2838 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8; 2839 HReg tLo = newVRegI(env); 2840 HReg tHi = newVRegI(env); 2841 HReg vec = iselVecExpr(env, e->Iex.Unop.arg); 2842 PPCAMode *am_off0, *am_offLO, *am_offHI; 2843 sub_from_sp( env, 32 ); // Move SP down 32 bytes 2844 2845 // get a quadword aligned address within our stack space 2846 r_aligned16 = get_sp_aligned16( env ); 2847 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 2848 am_offHI = PPCAMode_IR( off, r_aligned16 ); 2849 am_offLO = PPCAMode_IR( off+4, r_aligned16 ); 2850 2851 // store as Vec128 2852 addInstr(env, 2853 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 )); 2854 2855 // load hi,lo words (of hi/lo half of vec) as Ity_I32's 2856 addInstr(env, 2857 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ )); 2858 addInstr(env, 2859 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ )); 2860 2861 add_to_sp( env, 32 ); // Reset SP 2862 *rHi = tHi; 2863 *rLo = tLo; 2864 return; 2865 } 2866 2867 /* could do better than this, but for now ... */ 2868 case Iop_1Sto64: { 2869 HReg tLo = newVRegI(env); 2870 HReg tHi = newVRegI(env); 2871 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg); 2872 addInstr(env, PPCInstr_Set(cond,tLo)); 2873 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 2874 tLo, tLo, PPCRH_Imm(False,31))); 2875 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 2876 tLo, tLo, PPCRH_Imm(False,31))); 2877 addInstr(env, mk_iMOVds_RR(tHi, tLo)); 2878 *rHi = tHi; 2879 *rLo = tLo; 2880 return; 2881 } 2882 2883 /* ReinterpF64asI64(e) */ 2884 /* Given an IEEE754 double, produce an I64 with the same bit 2885 pattern. */ 2886 case Iop_ReinterpF64asI64: { 2887 PPCAMode *am_addr0, *am_addr1; 2888 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg); 2889 HReg r_dstLo = newVRegI(env); 2890 HReg r_dstHi = newVRegI(env); 2891 2892 sub_from_sp( env, 16 ); // Move SP down 16 bytes 2893 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) ); 2894 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) ); 2895 2896 // store as F64 2897 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8, 2898 fr_src, am_addr0 )); 2899 2900 // load hi,lo as Ity_I32's 2901 addInstr(env, PPCInstr_Load( 4, r_dstHi, 2902 am_addr0, False/*mode32*/ )); 2903 addInstr(env, PPCInstr_Load( 4, r_dstLo, 2904 am_addr1, False/*mode32*/ )); 2905 *rHi = r_dstHi; 2906 *rLo = r_dstLo; 2907 2908 add_to_sp( env, 16 ); // Reset SP 2909 return; 2910 } 2911 2912 default: 2913 break; 2914 } 2915 } /* if (e->tag == Iex_Unop) */ 2916 2917 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag); 2918 ppIRExpr(e); 2919 vpanic("iselInt64Expr(ppc)"); 2920 } 2921 2922 2923 /*---------------------------------------------------------*/ 2924 /*--- ISEL: Floating point expressions (32 bit) ---*/ 2925 /*---------------------------------------------------------*/ 2926 2927 /* Nothing interesting here; really just wrappers for 2928 64-bit stuff. */ 2929 2930 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e ) 2931 { 2932 HReg r = iselFltExpr_wrk( env, e ); 2933 # if 0 2934 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 2935 # endif 2936 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */ 2937 vassert(hregIsVirtual(r)); 2938 return r; 2939 } 2940 2941 /* DO NOT CALL THIS DIRECTLY */ 2942 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e ) 2943 { 2944 IRType ty = typeOfIRExpr(env->type_env,e); 2945 vassert(ty == Ity_F32); 2946 2947 if (e->tag == Iex_RdTmp) { 2948 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 2949 } 2950 2951 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) { 2952 PPCAMode* am_addr; 2953 HReg r_dst = newVRegF(env); 2954 vassert(e->Iex.Load.ty == Ity_F32); 2955 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/); 2956 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr)); 2957 return r_dst; 2958 } 2959 2960 if (e->tag == Iex_Get) { 2961 HReg r_dst = newVRegF(env); 2962 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 2963 GuestStatePtr(env->mode64) ); 2964 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr )); 2965 return r_dst; 2966 } 2967 2968 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) { 2969 /* This is quite subtle. The only way to do the relevant 2970 truncation is to do a single-precision store and then a 2971 double precision load to get it back into a register. The 2972 problem is, if the data is then written to memory a second 2973 time, as in 2974 2975 STbe(...) = TruncF64asF32(...) 2976 2977 then will the second truncation further alter the value? The 2978 answer is no: flds (as generated here) followed by fsts 2979 (generated for the STbe) is the identity function on 32-bit 2980 floats, so we are safe. 2981 2982 Another upshot of this is that if iselStmt can see the 2983 entirety of 2984 2985 STbe(...) = TruncF64asF32(arg) 2986 2987 then it can short circuit having to deal with TruncF64asF32 2988 individually; instead just compute arg into a 64-bit FP 2989 register and do 'fsts' (since that itself does the 2990 truncation). 2991 2992 We generate pretty poor code here (should be ok both for 2993 32-bit and 64-bit mode); but it is expected that for the most 2994 part the latter optimisation will apply and hence this code 2995 will not often be used. 2996 */ 2997 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg); 2998 HReg fdst = newVRegF(env); 2999 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 3000 3001 sub_from_sp( env, 16 ); 3002 // store as F32, hence truncating 3003 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4, 3004 fsrc, zero_r1 )); 3005 // and reload. Good huh?! (sigh) 3006 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, 3007 fdst, zero_r1 )); 3008 add_to_sp( env, 16 ); 3009 return fdst; 3010 } 3011 3012 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag); 3013 ppIRExpr(e); 3014 vpanic("iselFltExpr_wrk(ppc)"); 3015 } 3016 3017 3018 /*---------------------------------------------------------*/ 3019 /*--- ISEL: Floating point expressions (64 bit) ---*/ 3020 /*---------------------------------------------------------*/ 3021 3022 /* Compute a 64-bit floating point value into a register, the identity 3023 of which is returned. As with iselIntExpr_R, the reg may be either 3024 real or virtual; in any case it must not be changed by subsequent 3025 code emitted by the caller. */ 3026 3027 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm: 3028 3029 Type S (1 bit) E (11 bits) F (52 bits) 3030 ---- --------- ----------- ----------- 3031 signalling NaN u 2047 (max) .0uuuuu---u 3032 (with at least 3033 one 1 bit) 3034 quiet NaN u 2047 (max) .1uuuuu---u 3035 3036 negative infinity 1 2047 (max) .000000---0 3037 3038 positive infinity 0 2047 (max) .000000---0 3039 3040 negative zero 1 0 .000000---0 3041 3042 positive zero 0 0 .000000---0 3043 */ 3044 3045 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) 3046 { 3047 HReg r = iselDblExpr_wrk( env, e ); 3048 # if 0 3049 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3050 # endif 3051 vassert(hregClass(r) == HRcFlt64); 3052 vassert(hregIsVirtual(r)); 3053 return r; 3054 } 3055 3056 /* DO NOT CALL THIS DIRECTLY */ 3057 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) 3058 { 3059 Bool mode64 = env->mode64; 3060 IRType ty = typeOfIRExpr(env->type_env,e); 3061 vassert(e); 3062 vassert(ty == Ity_F64); 3063 3064 if (e->tag == Iex_RdTmp) { 3065 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 3066 } 3067 3068 /* --------- LITERAL --------- */ 3069 if (e->tag == Iex_Const) { 3070 union { UInt u32x2[2]; ULong u64; Double f64; } u; 3071 vassert(sizeof(u) == 8); 3072 vassert(sizeof(u.u64) == 8); 3073 vassert(sizeof(u.f64) == 8); 3074 vassert(sizeof(u.u32x2) == 8); 3075 3076 if (e->Iex.Const.con->tag == Ico_F64) { 3077 u.f64 = e->Iex.Const.con->Ico.F64; 3078 } 3079 else if (e->Iex.Const.con->tag == Ico_F64i) { 3080 u.u64 = e->Iex.Const.con->Ico.F64i; 3081 } 3082 else 3083 vpanic("iselDblExpr(ppc): const"); 3084 3085 if (!mode64) { 3086 HReg r_srcHi = newVRegI(env); 3087 HReg r_srcLo = newVRegI(env); 3088 addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64)); 3089 addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64)); 3090 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo ); 3091 } else { // mode64 3092 HReg r_src = newVRegI(env); 3093 addInstr(env, PPCInstr_LI(r_src, u.u64, mode64)); 3094 return mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64 3095 } 3096 } 3097 3098 /* --------- LOAD --------- */ 3099 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) { 3100 HReg r_dst = newVRegF(env); 3101 PPCAMode* am_addr; 3102 vassert(e->Iex.Load.ty == Ity_F64); 3103 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/); 3104 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr)); 3105 return r_dst; 3106 } 3107 3108 /* --------- GET --------- */ 3109 if (e->tag == Iex_Get) { 3110 HReg r_dst = newVRegF(env); 3111 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 3112 GuestStatePtr(mode64) ); 3113 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr )); 3114 return r_dst; 3115 } 3116 3117 /* --------- OPS --------- */ 3118 if (e->tag == Iex_Qop) { 3119 PPCFpOp fpop = Pfp_INVALID; 3120 switch (e->Iex.Qop.op) { 3121 case Iop_MAddF64: fpop = Pfp_MADDD; break; 3122 case Iop_MAddF64r32: fpop = Pfp_MADDS; break; 3123 case Iop_MSubF64: fpop = Pfp_MSUBD; break; 3124 case Iop_MSubF64r32: fpop = Pfp_MSUBS; break; 3125 default: break; 3126 } 3127 if (fpop != Pfp_INVALID) { 3128 HReg r_dst = newVRegF(env); 3129 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.arg2); 3130 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.arg3); 3131 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.arg4); 3132 set_FPU_rounding_mode( env, e->Iex.Qop.arg1 ); 3133 addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst, 3134 r_srcML, r_srcMR, r_srcAcc)); 3135 return r_dst; 3136 } 3137 } 3138 3139 if (e->tag == Iex_Triop) { 3140 PPCFpOp fpop = Pfp_INVALID; 3141 switch (e->Iex.Triop.op) { 3142 case Iop_AddF64: fpop = Pfp_ADDD; break; 3143 case Iop_SubF64: fpop = Pfp_SUBD; break; 3144 case Iop_MulF64: fpop = Pfp_MULD; break; 3145 case Iop_DivF64: fpop = Pfp_DIVD; break; 3146 case Iop_AddF64r32: fpop = Pfp_ADDS; break; 3147 case Iop_SubF64r32: fpop = Pfp_SUBS; break; 3148 case Iop_MulF64r32: fpop = Pfp_MULS; break; 3149 case Iop_DivF64r32: fpop = Pfp_DIVS; break; 3150 default: break; 3151 } 3152 if (fpop != Pfp_INVALID) { 3153 HReg r_dst = newVRegF(env); 3154 HReg r_srcL = iselDblExpr(env, e->Iex.Triop.arg2); 3155 HReg r_srcR = iselDblExpr(env, e->Iex.Triop.arg3); 3156 set_FPU_rounding_mode( env, e->Iex.Triop.arg1 ); 3157 addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR)); 3158 return r_dst; 3159 } 3160 } 3161 3162 if (e->tag == Iex_Binop) { 3163 PPCFpOp fpop = Pfp_INVALID; 3164 switch (e->Iex.Binop.op) { 3165 case Iop_SqrtF64: fpop = Pfp_SQRT; break; 3166 default: break; 3167 } 3168 if (fpop != Pfp_INVALID) { 3169 HReg fr_dst = newVRegF(env); 3170 HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2); 3171 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 3172 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src)); 3173 return fr_dst; 3174 } 3175 } 3176 3177 if (e->tag == Iex_Binop) { 3178 3179 if (e->Iex.Binop.op == Iop_RoundF64toF32) { 3180 HReg r_dst = newVRegF(env); 3181 HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2); 3182 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 3183 addInstr(env, PPCInstr_FpRSP(r_dst, r_src)); 3184 //set_FPU_rounding_default( env ); 3185 return r_dst; 3186 } 3187 3188 if (e->Iex.Binop.op == Iop_I64StoF64) { 3189 if (mode64) { 3190 HReg fdst = newVRegF(env); 3191 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2); 3192 HReg r1 = StackFramePtr(env->mode64); 3193 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 3194 3195 /* Set host rounding mode */ 3196 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 3197 3198 sub_from_sp( env, 16 ); 3199 3200 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/)); 3201 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1)); 3202 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 3203 fdst, fdst)); 3204 3205 add_to_sp( env, 16 ); 3206 3207 ///* Restore default FPU rounding. */ 3208 //set_FPU_rounding_default( env ); 3209 return fdst; 3210 } else { 3211 /* 32-bit mode */ 3212 HReg fdst = newVRegF(env); 3213 HReg isrcHi, isrcLo; 3214 HReg r1 = StackFramePtr(env->mode64); 3215 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 3216 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 ); 3217 3218 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2); 3219 3220 /* Set host rounding mode */ 3221 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); 3222 3223 sub_from_sp( env, 16 ); 3224 3225 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/)); 3226 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/)); 3227 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1)); 3228 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 3229 fdst, fdst)); 3230 3231 add_to_sp( env, 16 ); 3232 3233 ///* Restore default FPU rounding. */ 3234 //set_FPU_rounding_default( env ); 3235 return fdst; 3236 } 3237 } 3238 3239 } 3240 3241 if (e->tag == Iex_Unop) { 3242 PPCFpOp fpop = Pfp_INVALID; 3243 switch (e->Iex.Unop.op) { 3244 case Iop_NegF64: fpop = Pfp_NEG; break; 3245 case Iop_AbsF64: fpop = Pfp_ABS; break; 3246 case Iop_Est5FRSqrt: fpop = Pfp_RSQRTE; break; 3247 case Iop_RoundF64toF64_NegINF: fpop = Pfp_FRIM; break; 3248 case Iop_RoundF64toF64_PosINF: fpop = Pfp_FRIP; break; 3249 case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break; 3250 case Iop_RoundF64toF64_ZERO: fpop = Pfp_FRIZ; break; 3251 default: break; 3252 } 3253 if (fpop != Pfp_INVALID) { 3254 HReg fr_dst = newVRegF(env); 3255 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg); 3256 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src)); 3257 return fr_dst; 3258 } 3259 } 3260 3261 if (e->tag == Iex_Unop) { 3262 switch (e->Iex.Unop.op) { 3263 case Iop_ReinterpI64asF64: { 3264 /* Given an I64, produce an IEEE754 double with the same 3265 bit pattern. */ 3266 if (!mode64) { 3267 HReg r_srcHi, r_srcLo; 3268 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg); 3269 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo ); 3270 } else { 3271 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 3272 return mk_LoadR64toFPR( env, r_src ); 3273 } 3274 } 3275 case Iop_F32toF64: { 3276 /* this is a no-op */ 3277 HReg res = iselFltExpr(env, e->Iex.Unop.arg); 3278 return res; 3279 } 3280 default: 3281 break; 3282 } 3283 } 3284 3285 /* --------- MULTIPLEX --------- */ 3286 if (e->tag == Iex_Mux0X) { 3287 if (ty == Ity_F64 3288 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) { 3289 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 3290 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond); 3291 HReg frX = iselDblExpr(env, e->Iex.Mux0X.exprX); 3292 HReg fr0 = iselDblExpr(env, e->Iex.Mux0X.expr0); 3293 HReg fr_dst = newVRegF(env); 3294 HReg r_tmp = newVRegI(env); 3295 addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp, 3296 r_cond, PPCRH_Imm(False,0xFF))); 3297 addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, frX )); 3298 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 3299 7/*cr*/, r_tmp, PPCRH_Imm(False,0))); 3300 addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr0 )); 3301 return fr_dst; 3302 } 3303 } 3304 3305 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag); 3306 ppIRExpr(e); 3307 vpanic("iselDblExpr_wrk(ppc)"); 3308 } 3309 3310 3311 /*---------------------------------------------------------*/ 3312 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/ 3313 /*---------------------------------------------------------*/ 3314 3315 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e ) 3316 { 3317 HReg r = iselVecExpr_wrk( env, e ); 3318 # if 0 3319 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3320 # endif 3321 vassert(hregClass(r) == HRcVec128); 3322 vassert(hregIsVirtual(r)); 3323 return r; 3324 } 3325 3326 /* DO NOT CALL THIS DIRECTLY */ 3327 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) 3328 { 3329 Bool mode64 = env->mode64; 3330 PPCAvOp op = Pav_INVALID; 3331 IRType ty = typeOfIRExpr(env->type_env,e); 3332 vassert(e); 3333 vassert(ty == Ity_V128); 3334 3335 if (e->tag == Iex_RdTmp) { 3336 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 3337 } 3338 3339 if (e->tag == Iex_Get) { 3340 /* Guest state vectors are 16byte aligned, 3341 so don't need to worry here */ 3342 HReg dst = newVRegV(env); 3343 addInstr(env, 3344 PPCInstr_AvLdSt( True/*load*/, 16, dst, 3345 PPCAMode_IR( e->Iex.Get.offset, 3346 GuestStatePtr(mode64) ))); 3347 return dst; 3348 } 3349 3350 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) { 3351 PPCAMode* am_addr; 3352 HReg v_dst = newVRegV(env); 3353 vassert(e->Iex.Load.ty == Ity_V128); 3354 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_V128/*xfer*/); 3355 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, v_dst, am_addr)); 3356 return v_dst; 3357 } 3358 3359 if (e->tag == Iex_Unop) { 3360 switch (e->Iex.Unop.op) { 3361 3362 case Iop_NotV128: { 3363 HReg arg = iselVecExpr(env, e->Iex.Unop.arg); 3364 HReg dst = newVRegV(env); 3365 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg)); 3366 return dst; 3367 } 3368 3369 case Iop_CmpNEZ8x16: { 3370 HReg arg = iselVecExpr(env, e->Iex.Unop.arg); 3371 HReg zero = newVRegV(env); 3372 HReg dst = newVRegV(env); 3373 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 3374 addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero)); 3375 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 3376 return dst; 3377 } 3378 3379 case Iop_CmpNEZ16x8: { 3380 HReg arg = iselVecExpr(env, e->Iex.Unop.arg); 3381 HReg zero = newVRegV(env); 3382 HReg dst = newVRegV(env); 3383 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 3384 addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero)); 3385 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 3386 return dst; 3387 } 3388 3389 case Iop_CmpNEZ32x4: { 3390 HReg arg = iselVecExpr(env, e->Iex.Unop.arg); 3391 HReg zero = newVRegV(env); 3392 HReg dst = newVRegV(env); 3393 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 3394 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero)); 3395 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 3396 return dst; 3397 } 3398 3399 case Iop_Recip32Fx4: op = Pavfp_RCPF; goto do_32Fx4_unary; 3400 case Iop_RSqrt32Fx4: op = Pavfp_RSQRTF; goto do_32Fx4_unary; 3401 case Iop_I32UtoFx4: op = Pavfp_CVTU2F; goto do_32Fx4_unary; 3402 case Iop_I32StoFx4: op = Pavfp_CVTS2F; goto do_32Fx4_unary; 3403 case Iop_QFtoI32Ux4_RZ: op = Pavfp_QCVTF2U; goto do_32Fx4_unary; 3404 case Iop_QFtoI32Sx4_RZ: op = Pavfp_QCVTF2S; goto do_32Fx4_unary; 3405 case Iop_RoundF32x4_RM: op = Pavfp_ROUNDM; goto do_32Fx4_unary; 3406 case Iop_RoundF32x4_RP: op = Pavfp_ROUNDP; goto do_32Fx4_unary; 3407 case Iop_RoundF32x4_RN: op = Pavfp_ROUNDN; goto do_32Fx4_unary; 3408 case Iop_RoundF32x4_RZ: op = Pavfp_ROUNDZ; goto do_32Fx4_unary; 3409 do_32Fx4_unary: 3410 { 3411 HReg arg = iselVecExpr(env, e->Iex.Unop.arg); 3412 HReg dst = newVRegV(env); 3413 addInstr(env, PPCInstr_AvUn32Fx4(op, dst, arg)); 3414 return dst; 3415 } 3416 3417 case Iop_32UtoV128: { 3418 HReg r_aligned16, r_zeros; 3419 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg); 3420 HReg dst = newVRegV(env); 3421 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12; 3422 sub_from_sp( env, 32 ); // Move SP down 3423 3424 /* Get a quadword aligned address within our stack space */ 3425 r_aligned16 = get_sp_aligned16( env ); 3426 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 3427 am_off4 = PPCAMode_IR( 4, r_aligned16 ); 3428 am_off8 = PPCAMode_IR( 8, r_aligned16 ); 3429 am_off12 = PPCAMode_IR( 12, r_aligned16 ); 3430 3431 /* Store zeros */ 3432 r_zeros = newVRegI(env); 3433 addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64)); 3434 addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 )); 3435 addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 )); 3436 addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 )); 3437 3438 /* Store r_src in low word of quadword-aligned mem */ 3439 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 )); 3440 3441 /* Load word into low word of quadword vector reg */ 3442 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 )); 3443 3444 add_to_sp( env, 32 ); // Reset SP 3445 return dst; 3446 } 3447 3448 case Iop_Dup8x16: 3449 case Iop_Dup16x8: 3450 case Iop_Dup32x4: 3451 return mk_AvDuplicateRI(env, e->Iex.Binop.arg1); 3452 3453 default: 3454 break; 3455 } /* switch (e->Iex.Unop.op) */ 3456 } /* if (e->tag == Iex_Unop) */ 3457 3458 if (e->tag == Iex_Binop) { 3459 switch (e->Iex.Binop.op) { 3460 3461 case Iop_64HLtoV128: { 3462 if (!mode64) { 3463 HReg r3, r2, r1, r0, r_aligned16; 3464 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12; 3465 HReg dst = newVRegV(env); 3466 /* do this via the stack (easy, convenient, etc) */ 3467 sub_from_sp( env, 32 ); // Move SP down 3468 3469 // get a quadword aligned address within our stack space 3470 r_aligned16 = get_sp_aligned16( env ); 3471 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 3472 am_off4 = PPCAMode_IR( 4, r_aligned16 ); 3473 am_off8 = PPCAMode_IR( 8, r_aligned16 ); 3474 am_off12 = PPCAMode_IR( 12, r_aligned16 ); 3475 3476 /* Do the less significant 64 bits */ 3477 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2); 3478 addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 )); 3479 addInstr(env, PPCInstr_Store( 4, am_off8, r1, mode64 )); 3480 /* Do the more significant 64 bits */ 3481 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1); 3482 addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 )); 3483 addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 )); 3484 3485 /* Fetch result back from stack. */ 3486 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0)); 3487 3488 add_to_sp( env, 32 ); // Reset SP 3489 return dst; 3490 } else { 3491 HReg rHi = iselWordExpr_R(env, e->Iex.Binop.arg1); 3492 HReg rLo = iselWordExpr_R(env, e->Iex.Binop.arg2); 3493 HReg dst = newVRegV(env); 3494 HReg r_aligned16; 3495 PPCAMode *am_off0, *am_off8; 3496 /* do this via the stack (easy, convenient, etc) */ 3497 sub_from_sp( env, 32 ); // Move SP down 3498 3499 // get a quadword aligned address within our stack space 3500 r_aligned16 = get_sp_aligned16( env ); 3501 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 3502 am_off8 = PPCAMode_IR( 8, r_aligned16 ); 3503 3504 /* Store 2*I64 to stack */ 3505 addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 )); 3506 addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 )); 3507 3508 /* Fetch result back from stack. */ 3509 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0)); 3510 3511 add_to_sp( env, 32 ); // Reset SP 3512 return dst; 3513 } 3514 } 3515 3516 case Iop_Add32Fx4: op = Pavfp_ADDF; goto do_32Fx4; 3517 case Iop_Sub32Fx4: op = Pavfp_SUBF; goto do_32Fx4; 3518 case Iop_Max32Fx4: op = Pavfp_MAXF; goto do_32Fx4; 3519 case Iop_Min32Fx4: op = Pavfp_MINF; goto do_32Fx4; 3520 case Iop_Mul32Fx4: op = Pavfp_MULF; goto do_32Fx4; 3521 case Iop_CmpEQ32Fx4: op = Pavfp_CMPEQF; goto do_32Fx4; 3522 case Iop_CmpGT32Fx4: op = Pavfp_CMPGTF; goto do_32Fx4; 3523 case Iop_CmpGE32Fx4: op = Pavfp_CMPGEF; goto do_32Fx4; 3524 do_32Fx4: 3525 { 3526 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); 3527 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); 3528 HReg dst = newVRegV(env); 3529 addInstr(env, PPCInstr_AvBin32Fx4(op, dst, argL, argR)); 3530 return dst; 3531 } 3532 3533 case Iop_CmpLE32Fx4: { 3534 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1); 3535 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2); 3536 HReg dst = newVRegV(env); 3537 3538 /* stay consistent with native ppc compares: 3539 if a left/right lane holds a nan, return zeros for that lane 3540 so: le == NOT(gt OR isNan) 3541 */ 3542 HReg isNanLR = newVRegV(env); 3543 HReg isNanL = isNan(env, argL); 3544 HReg isNanR = isNan(env, argR); 3545 addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR, 3546 isNanL, isNanR)); 3547 3548 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst, 3549 argL, argR)); 3550 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR)); 3551 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 3552 return dst; 3553 } 3554 3555 case Iop_AndV128: op = Pav_AND; goto do_AvBin; 3556 case Iop_OrV128: op = Pav_OR; goto do_AvBin; 3557 case Iop_XorV128: op = Pav_XOR; goto do_AvBin; 3558 do_AvBin: { 3559 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1); 3560 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2); 3561 HReg dst = newVRegV(env); 3562 addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2)); 3563 return dst; 3564 } 3565 3566 case Iop_Shl8x16: op = Pav_SHL; goto do_AvBin8x16; 3567 case Iop_Shr8x16: op = Pav_SHR; goto do_AvBin8x16; 3568 case Iop_Sar8x16: op = Pav_SAR; goto do_AvBin8x16; 3569 case Iop_Rol8x16: op = Pav_ROTL; goto do_AvBin8x16; 3570 case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16; 3571 case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16; 3572 case Iop_Add8x16: op = Pav_ADDU; goto do_AvBin8x16; 3573 case Iop_QAdd8Ux16: op = Pav_QADDU; goto do_AvBin8x16; 3574 case Iop_QAdd8Sx16: op = Pav_QADDS; goto do_AvBin8x16; 3575 case Iop_Sub8x16: op = Pav_SUBU; goto do_AvBin8x16; 3576 case Iop_QSub8Ux16: op = Pav_QSUBU; goto do_AvBin8x16; 3577 case Iop_QSub8Sx16: op = Pav_QSUBS; goto do_AvBin8x16; 3578 case Iop_Avg8Ux16: op = Pav_AVGU; goto do_AvBin8x16; 3579 case Iop_Avg8Sx16: op = Pav_AVGS; goto do_AvBin8x16; 3580 case Iop_Max8Ux16: op = Pav_MAXU; goto do_AvBin8x16; 3581 case Iop_Max8Sx16: op = Pav_MAXS; goto do_AvBin8x16; 3582 case Iop_Min8Ux16: op = Pav_MINU; goto do_AvBin8x16; 3583 case Iop_Min8Sx16: op = Pav_MINS; goto do_AvBin8x16; 3584 case Iop_MullEven8Ux16: op = Pav_OMULU; goto do_AvBin8x16; 3585 case Iop_MullEven8Sx16: op = Pav_OMULS; goto do_AvBin8x16; 3586 case Iop_CmpEQ8x16: op = Pav_CMPEQU; goto do_AvBin8x16; 3587 case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16; 3588 case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16; 3589 do_AvBin8x16: { 3590 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1); 3591 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2); 3592 HReg dst = newVRegV(env); 3593 addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2)); 3594 return dst; 3595 } 3596 3597 case Iop_Shl16x8: op = Pav_SHL; goto do_AvBin16x8; 3598 case Iop_Shr16x8: op = Pav_SHR; goto do_AvBin16x8; 3599 case Iop_Sar16x8: op = Pav_SAR; goto do_AvBin16x8; 3600 case Iop_Rol16x8: op = Pav_ROTL; goto do_AvBin16x8; 3601 case Iop_Narrow16x8: op = Pav_PACKUU; goto do_AvBin16x8; 3602 case Iop_QNarrow16Ux8: op = Pav_QPACKUU; goto do_AvBin16x8; 3603 case Iop_QNarrow16Sx8: op = Pav_QPACKSS; goto do_AvBin16x8; 3604 case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8; 3605 case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8; 3606 case Iop_Add16x8: op = Pav_ADDU; goto do_AvBin16x8; 3607 case Iop_QAdd16Ux8: op = Pav_QADDU; goto do_AvBin16x8; 3608 case Iop_QAdd16Sx8: op = Pav_QADDS; goto do_AvBin16x8; 3609 case Iop_Sub16x8: op = Pav_SUBU; goto do_AvBin16x8; 3610 case Iop_QSub16Ux8: op = Pav_QSUBU; goto do_AvBin16x8; 3611 case Iop_QSub16Sx8: op = Pav_QSUBS; goto do_AvBin16x8; 3612 case Iop_Avg16Ux8: op = Pav_AVGU; goto do_AvBin16x8; 3613 case Iop_Avg16Sx8: op = Pav_AVGS; goto do_AvBin16x8; 3614 case Iop_Max16Ux8: op = Pav_MAXU; goto do_AvBin16x8; 3615 case Iop_Max16Sx8: op = Pav_MAXS; goto do_AvBin16x8; 3616 case Iop_Min16Ux8: op = Pav_MINU; goto do_AvBin16x8; 3617 case Iop_Min16Sx8: op = Pav_MINS; goto do_AvBin16x8; 3618 case Iop_MullEven16Ux8: op = Pav_OMULU; goto do_AvBin16x8; 3619 case Iop_MullEven16Sx8: op = Pav_OMULS; goto do_AvBin16x8; 3620 case Iop_CmpEQ16x8: op = Pav_CMPEQU; goto do_AvBin16x8; 3621 case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8; 3622 case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8; 3623 do_AvBin16x8: { 3624 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1); 3625 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2); 3626 HReg dst = newVRegV(env); 3627 addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2)); 3628 return dst; 3629 } 3630 3631 case Iop_Shl32x4: op = Pav_SHL; goto do_AvBin32x4; 3632 case Iop_Shr32x4: op = Pav_SHR; goto do_AvBin32x4; 3633 case Iop_Sar32x4: op = Pav_SAR; goto do_AvBin32x4; 3634 case Iop_Rol32x4: op = Pav_ROTL; goto do_AvBin32x4; 3635 case Iop_Narrow32x4: op = Pav_PACKUU; goto do_AvBin32x4; 3636 case Iop_QNarrow32Ux4: op = Pav_QPACKUU; goto do_AvBin32x4; 3637 case Iop_QNarrow32Sx4: op = Pav_QPACKSS; goto do_AvBin32x4; 3638 case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4; 3639 case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4; 3640 case Iop_Add32x4: op = Pav_ADDU; goto do_AvBin32x4; 3641 case Iop_QAdd32Ux4: op = Pav_QADDU; goto do_AvBin32x4; 3642 case Iop_QAdd32Sx4: op = Pav_QADDS; goto do_AvBin32x4; 3643 case Iop_Sub32x4: op = Pav_SUBU; goto do_AvBin32x4; 3644 case Iop_QSub32Ux4: op = Pav_QSUBU; goto do_AvBin32x4; 3645 case Iop_QSub32Sx4: op = Pav_QSUBS; goto do_AvBin32x4; 3646 case Iop_Avg32Ux4: op = Pav_AVGU; goto do_AvBin32x4; 3647 case Iop_Avg32Sx4: op = Pav_AVGS; goto do_AvBin32x4; 3648 case Iop_Max32Ux4: op = Pav_MAXU; goto do_AvBin32x4; 3649 case Iop_Max32Sx4: op = Pav_MAXS; goto do_AvBin32x4; 3650 case Iop_Min32Ux4: op = Pav_MINU; goto do_AvBin32x4; 3651 case Iop_Min32Sx4: op = Pav_MINS; goto do_AvBin32x4; 3652 case Iop_CmpEQ32x4: op = Pav_CMPEQU; goto do_AvBin32x4; 3653 case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4; 3654 case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4; 3655 do_AvBin32x4: { 3656 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1); 3657 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2); 3658 HReg dst = newVRegV(env); 3659 addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2)); 3660 return dst; 3661 } 3662 3663 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16; 3664 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16; 3665 do_AvShift8x16: { 3666 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1); 3667 HReg dst = newVRegV(env); 3668 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2); 3669 addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft)); 3670 return dst; 3671 } 3672 3673 case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8; 3674 case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8; 3675 case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8; 3676 do_AvShift16x8: { 3677 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1); 3678 HReg dst = newVRegV(env); 3679 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2); 3680 addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft)); 3681 return dst; 3682 } 3683 3684 case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4; 3685 case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4; 3686 case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4; 3687 do_AvShift32x4: { 3688 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1); 3689 HReg dst = newVRegV(env); 3690 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2); 3691 addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft)); 3692 return dst; 3693 } 3694 3695 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128; 3696 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128; 3697 do_AvShiftV128: { 3698 HReg dst = newVRegV(env); 3699 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1); 3700 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2); 3701 /* Note: shift value gets masked by 127 */ 3702 addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft)); 3703 return dst; 3704 } 3705 3706 case Iop_Perm8x16: { 3707 HReg dst = newVRegV(env); 3708 HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1); 3709 HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2); 3710 addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl)); 3711 return dst; 3712 } 3713 3714 default: 3715 break; 3716 } /* switch (e->Iex.Binop.op) */ 3717 } /* if (e->tag == Iex_Binop) */ 3718 3719 if (e->tag == Iex_Const ) { 3720 vassert(e->Iex.Const.con->tag == Ico_V128); 3721 if (e->Iex.Const.con->Ico.V128 == 0x0000) { 3722 return generate_zeroes_V128(env); 3723 } 3724 else if (e->Iex.Const.con->Ico.V128 == 0xffff) { 3725 return generate_ones_V128(env); 3726 } 3727 } 3728 3729 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n", 3730 LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32, 3731 env->hwcaps)); 3732 ppIRExpr(e); 3733 vpanic("iselVecExpr_wrk(ppc)"); 3734 } 3735 3736 3737 /*---------------------------------------------------------*/ 3738 /*--- ISEL: Statements ---*/ 3739 /*---------------------------------------------------------*/ 3740 3741 static void iselStmt ( ISelEnv* env, IRStmt* stmt ) 3742 { 3743 Bool mode64 = env->mode64; 3744 if (vex_traceflags & VEX_TRACE_VCODE) { 3745 vex_printf("\n -- "); 3746 ppIRStmt(stmt); 3747 vex_printf("\n"); 3748 } 3749 3750 switch (stmt->tag) { 3751 3752 /* --------- STORE --------- */ 3753 case Ist_Store: { 3754 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr); 3755 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 3756 IREndness end = stmt->Ist.Store.end; 3757 3758 if (end != Iend_BE) 3759 goto stmt_fail; 3760 if (!mode64 && (tya != Ity_I32)) 3761 goto stmt_fail; 3762 if (mode64 && (tya != Ity_I64)) 3763 goto stmt_fail; 3764 3765 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 || 3766 (mode64 && (tyd == Ity_I64))) { 3767 PPCAMode* am_addr 3768 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/); 3769 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data); 3770 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)), 3771 am_addr, r_src, mode64 )); 3772 return; 3773 } 3774 if (tyd == Ity_F64) { 3775 PPCAMode* am_addr 3776 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/); 3777 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data); 3778 addInstr(env, 3779 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr)); 3780 return; 3781 } 3782 if (tyd == Ity_F32) { 3783 PPCAMode* am_addr 3784 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/); 3785 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data); 3786 addInstr(env, 3787 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr)); 3788 return; 3789 } 3790 if (tyd == Ity_V128) { 3791 PPCAMode* am_addr 3792 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/); 3793 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data); 3794 addInstr(env, 3795 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr)); 3796 return; 3797 } 3798 if (tyd == Ity_I64 && !mode64) { 3799 /* Just calculate the address in the register. Life is too 3800 short to arse around trying and possibly failing to adjust 3801 the offset in a 'reg+offset' style amode. */ 3802 HReg rHi32, rLo32; 3803 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr); 3804 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data ); 3805 addInstr(env, PPCInstr_Store( 4/*byte-store*/, 3806 PPCAMode_IR( 0, r_addr ), 3807 rHi32, 3808 False/*32-bit insn please*/) ); 3809 addInstr(env, PPCInstr_Store( 4/*byte-store*/, 3810 PPCAMode_IR( 4, r_addr ), 3811 rLo32, 3812 False/*32-bit insn please*/) ); 3813 return; 3814 } 3815 break; 3816 } 3817 3818 /* --------- PUT --------- */ 3819 case Ist_Put: { 3820 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 3821 if (ty == Ity_I8 || ty == Ity_I16 || 3822 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) { 3823 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data); 3824 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 3825 GuestStatePtr(mode64) ); 3826 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)), 3827 am_addr, r_src, mode64 )); 3828 return; 3829 } 3830 if (!mode64 && ty == Ity_I64) { 3831 HReg rHi, rLo; 3832 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 3833 GuestStatePtr(mode64) ); 3834 PPCAMode* am_addr4 = advance4(env, am_addr); 3835 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data); 3836 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 )); 3837 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 )); 3838 return; 3839 } 3840 if (ty == Ity_V128) { 3841 /* Guest state vectors are 16byte aligned, 3842 so don't need to worry here */ 3843 HReg v_src = iselVecExpr(env, stmt->Ist.Put.data); 3844 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 3845 GuestStatePtr(mode64) ); 3846 addInstr(env, 3847 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr)); 3848 return; 3849 } 3850 if (ty == Ity_F64) { 3851 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data); 3852 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 3853 GuestStatePtr(mode64) ); 3854 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8, 3855 fr_src, am_addr )); 3856 return; 3857 } 3858 break; 3859 } 3860 3861 /* --------- Indexed PUT --------- */ 3862 case Ist_PutI: { 3863 PPCAMode* dst_am 3864 = genGuestArrayOffset( 3865 env, stmt->Ist.PutI.descr, 3866 stmt->Ist.PutI.ix, stmt->Ist.PutI.bias ); 3867 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data); 3868 if (mode64 && ty == Ity_I64) { 3869 HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data); 3870 addInstr(env, PPCInstr_Store( toUChar(8), 3871 dst_am, r_src, mode64 )); 3872 return; 3873 } 3874 if ((!mode64) && ty == Ity_I32) { 3875 HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data); 3876 addInstr(env, PPCInstr_Store( toUChar(4), 3877 dst_am, r_src, mode64 )); 3878 return; 3879 } 3880 break; 3881 } 3882 3883 /* --------- TMP --------- */ 3884 case Ist_WrTmp: { 3885 IRTemp tmp = stmt->Ist.WrTmp.tmp; 3886 IRType ty = typeOfIRTemp(env->type_env, tmp); 3887 if (ty == Ity_I8 || ty == Ity_I16 || 3888 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) { 3889 HReg r_dst = lookupIRTemp(env, tmp); 3890 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data); 3891 addInstr(env, mk_iMOVds_RR( r_dst, r_src )); 3892 return; 3893 } 3894 if (!mode64 && ty == Ity_I64) { 3895 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo; 3896 iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data); 3897 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp); 3898 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) ); 3899 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) ); 3900 return; 3901 } 3902 if (mode64 && ty == Ity_I128) { 3903 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo; 3904 iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data); 3905 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp); 3906 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) ); 3907 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) ); 3908 return; 3909 } 3910 if (ty == Ity_I1) { 3911 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data); 3912 HReg r_dst = lookupIRTemp(env, tmp); 3913 addInstr(env, PPCInstr_Set(cond, r_dst)); 3914 return; 3915 } 3916 if (ty == Ity_F64) { 3917 HReg fr_dst = lookupIRTemp(env, tmp); 3918 HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data); 3919 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src)); 3920 return; 3921 } 3922 if (ty == Ity_F32) { 3923 HReg fr_dst = lookupIRTemp(env, tmp); 3924 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data); 3925 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src)); 3926 return; 3927 } 3928 if (ty == Ity_V128) { 3929 HReg v_dst = lookupIRTemp(env, tmp); 3930 HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data); 3931 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src)); 3932 return; 3933 } 3934 break; 3935 } 3936 3937 /* --------- Load Linked or Store Conditional --------- */ 3938 case Ist_LLSC: { 3939 IRTemp res = stmt->Ist.LLSC.result; 3940 IRType tyRes = typeOfIRTemp(env->type_env, res); 3941 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr); 3942 3943 if (stmt->Ist.LLSC.end != Iend_BE) 3944 goto stmt_fail; 3945 if (!mode64 && (tyAddr != Ity_I32)) 3946 goto stmt_fail; 3947 if (mode64 && (tyAddr != Ity_I64)) 3948 goto stmt_fail; 3949 3950 if (stmt->Ist.LLSC.storedata == NULL) { 3951 /* LL */ 3952 HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr ); 3953 HReg r_dst = lookupIRTemp(env, res); 3954 if (tyRes == Ity_I32) { 3955 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 )); 3956 return; 3957 } 3958 if (tyRes == Ity_I64 && mode64) { 3959 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 )); 3960 return; 3961 } 3962 /* fallthru */; 3963 } else { 3964 /* SC */ 3965 HReg r_res = lookupIRTemp(env, res); /* :: Ity_I1 */ 3966 HReg r_a = iselWordExpr_R(env, stmt->Ist.LLSC.addr); 3967 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata); 3968 HReg r_tmp = newVRegI(env); 3969 IRType tyData = typeOfIRExpr(env->type_env, 3970 stmt->Ist.LLSC.storedata); 3971 vassert(tyRes == Ity_I1); 3972 if (tyData == Ity_I32 || (tyData == Ity_I64 && mode64)) { 3973 addInstr(env, PPCInstr_StoreC( tyData==Ity_I32 ? 4 : 8, 3974 r_a, r_src, mode64 )); 3975 addInstr(env, PPCInstr_MfCR( r_tmp )); 3976 addInstr(env, PPCInstr_Shft( 3977 Pshft_SHR, 3978 env->mode64 ? False : True 3979 /*F:64-bit, T:32-bit shift*/, 3980 r_tmp, r_tmp, 3981 PPCRH_Imm(False/*unsigned*/, 29))); 3982 /* Probably unnecessary, since the IR dest type is Ity_I1, 3983 and so we are entitled to leave whatever junk we like 3984 drifting round in the upper 31 or 63 bits of r_res. 3985 However, for the sake of conservativeness .. */ 3986 addInstr(env, PPCInstr_Alu( 3987 Palu_AND, 3988 r_res, r_tmp, 3989 PPCRH_Imm(False/*signed*/, 1))); 3990 return; 3991 } 3992 /* fallthru */ 3993 } 3994 goto stmt_fail; 3995 /*NOTREACHED*/ 3996 } 3997 3998 /* --------- Call to DIRTY helper --------- */ 3999 case Ist_Dirty: { 4000 IRType retty; 4001 IRDirty* d = stmt->Ist.Dirty.details; 4002 Bool passBBP = False; 4003 4004 if (d->nFxState == 0) 4005 vassert(!d->needsBBP); 4006 passBBP = toBool(d->nFxState > 0 && d->needsBBP); 4007 4008 /* Marshal args, do the call, clear stack. */ 4009 doHelperCall( env, passBBP, d->guard, d->cee, d->args ); 4010 4011 /* Now figure out what to do with the returned value, if any. */ 4012 if (d->tmp == IRTemp_INVALID) 4013 /* No return value. Nothing to do. */ 4014 return; 4015 4016 retty = typeOfIRTemp(env->type_env, d->tmp); 4017 if (!mode64 && retty == Ity_I64) { 4018 HReg r_dstHi, r_dstLo; 4019 /* The returned value is in %r3:%r4. Park it in the 4020 register-pair associated with tmp. */ 4021 lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp); 4022 addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64))); 4023 addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64))); 4024 return; 4025 } 4026 if (retty == Ity_I8 || retty == Ity_I16 || 4027 retty == Ity_I32 || ((retty == Ity_I64) && mode64)) { 4028 /* The returned value is in %r3. Park it in the register 4029 associated with tmp. */ 4030 HReg r_dst = lookupIRTemp(env, d->tmp); 4031 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64))); 4032 return; 4033 } 4034 break; 4035 } 4036 4037 /* --------- MEM FENCE --------- */ 4038 case Ist_MBE: 4039 switch (stmt->Ist.MBE.event) { 4040 case Imbe_Fence: 4041 addInstr(env, PPCInstr_MFence()); 4042 return; 4043 default: 4044 break; 4045 } 4046 break; 4047 4048 /* --------- INSTR MARK --------- */ 4049 /* Doesn't generate any executable code ... */ 4050 case Ist_IMark: 4051 return; 4052 4053 /* --------- ABI HINT --------- */ 4054 /* These have no meaning (denotation in the IR) and so we ignore 4055 them ... if any actually made it this far. */ 4056 case Ist_AbiHint: 4057 return; 4058 4059 /* --------- NO-OP --------- */ 4060 /* Fairly self-explanatory, wouldn't you say? */ 4061 case Ist_NoOp: 4062 return; 4063 4064 /* --------- EXIT --------- */ 4065 case Ist_Exit: { 4066 PPCRI* ri_dst; 4067 PPCCondCode cc; 4068 IRConstTag tag = stmt->Ist.Exit.dst->tag; 4069 if (!mode64 && (tag != Ico_U32)) 4070 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value"); 4071 if (mode64 && (tag != Ico_U64)) 4072 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value"); 4073 ri_dst = iselWordExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst)); 4074 cc = iselCondCode(env,stmt->Ist.Exit.guard); 4075 addInstr(env, PPCInstr_RdWrLR(True, env->savedLR)); 4076 addInstr(env, PPCInstr_Goto(stmt->Ist.Exit.jk, cc, ri_dst)); 4077 return; 4078 } 4079 4080 default: break; 4081 } 4082 stmt_fail: 4083 ppIRStmt(stmt); 4084 vpanic("iselStmt(ppc)"); 4085 } 4086 4087 4088 /*---------------------------------------------------------*/ 4089 /*--- ISEL: Basic block terminators (Nexts) ---*/ 4090 /*---------------------------------------------------------*/ 4091 4092 static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk ) 4093 { 4094 PPCCondCode cond; 4095 PPCRI* ri; 4096 if (vex_traceflags & VEX_TRACE_VCODE) { 4097 vex_printf("\n-- goto {"); 4098 ppIRJumpKind(jk); 4099 vex_printf("} "); 4100 ppIRExpr(next); 4101 vex_printf("\n"); 4102 } 4103 cond = mk_PPCCondCode( Pct_ALWAYS, Pcf_7EQ ); 4104 ri = iselWordExpr_RI(env, next); 4105 addInstr(env, PPCInstr_RdWrLR(True, env->savedLR)); 4106 addInstr(env, PPCInstr_Goto(jk, cond, ri)); 4107 } 4108 4109 4110 /*---------------------------------------------------------*/ 4111 /*--- Insn selector top-level ---*/ 4112 /*---------------------------------------------------------*/ 4113 4114 /* Translate an entire BS to ppc code. */ 4115 4116 HInstrArray* iselSB_PPC ( IRSB* bb, VexArch arch_host, 4117 VexArchInfo* archinfo_host, 4118 VexAbiInfo* vbi ) 4119 { 4120 Int i, j; 4121 HReg hreg, hregHI; 4122 ISelEnv* env; 4123 UInt hwcaps_host = archinfo_host->hwcaps; 4124 Bool mode64 = False; 4125 UInt mask32, mask64; 4126 4127 vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64); 4128 mode64 = arch_host == VexArchPPC64; 4129 4130 /* do some sanity checks */ 4131 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V 4132 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX; 4133 4134 mask64 = VEX_HWCAPS_PPC64_V 4135 | VEX_HWCAPS_PPC64_FX | VEX_HWCAPS_PPC64_GX; 4136 4137 if (mode64) { 4138 vassert((hwcaps_host & mask32) == 0); 4139 } else { 4140 vassert((hwcaps_host & mask64) == 0); 4141 } 4142 4143 /* Make up an initial environment to use. */ 4144 env = LibVEX_Alloc(sizeof(ISelEnv)); 4145 env->vreg_ctr = 0; 4146 4147 /* Are we being ppc32 or ppc64? */ 4148 env->mode64 = mode64; 4149 4150 /* Set up output code array. */ 4151 env->code = newHInstrArray(); 4152 4153 /* Copy BB's type env. */ 4154 env->type_env = bb->tyenv; 4155 4156 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 4157 change as we go along. */ 4158 env->n_vregmap = bb->tyenv->types_used; 4159 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); 4160 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg)); 4161 4162 /* and finally ... */ 4163 env->hwcaps = hwcaps_host; 4164 env->previous_rm = NULL; 4165 env->vbi = vbi; 4166 4167 /* For each IR temporary, allocate a suitably-kinded virtual 4168 register. */ 4169 j = 0; 4170 for (i = 0; i < env->n_vregmap; i++) { 4171 hregHI = hreg = INVALID_HREG; 4172 switch (bb->tyenv->types[i]) { 4173 case Ity_I1: 4174 case Ity_I8: 4175 case Ity_I16: 4176 case Ity_I32: 4177 if (mode64) { hreg = mkHReg(j++, HRcInt64, True); break; 4178 } else { hreg = mkHReg(j++, HRcInt32, True); break; 4179 } 4180 case Ity_I64: 4181 if (mode64) { hreg = mkHReg(j++, HRcInt64, True); break; 4182 } else { hreg = mkHReg(j++, HRcInt32, True); 4183 hregHI = mkHReg(j++, HRcInt32, True); break; 4184 } 4185 case Ity_I128: vassert(mode64); 4186 hreg = mkHReg(j++, HRcInt64, True); 4187 hregHI = mkHReg(j++, HRcInt64, True); break; 4188 case Ity_F32: 4189 case Ity_F64: hreg = mkHReg(j++, HRcFlt64, True); break; 4190 case Ity_V128: hreg = mkHReg(j++, HRcVec128, True); break; 4191 default: 4192 ppIRType(bb->tyenv->types[i]); 4193 vpanic("iselBB(ppc): IRTemp type"); 4194 } 4195 env->vregmap[i] = hreg; 4196 env->vregmapHI[i] = hregHI; 4197 } 4198 env->vreg_ctr = j; 4199 4200 /* Keep a copy of the link reg, so helper functions don't kill it. */ 4201 env->savedLR = newVRegI(env); 4202 addInstr(env, PPCInstr_RdWrLR(False, env->savedLR)); 4203 4204 /* Ok, finally we can iterate over the statements. */ 4205 for (i = 0; i < bb->stmts_used; i++) 4206 if (bb->stmts[i]) 4207 iselStmt(env,bb->stmts[i]); 4208 4209 iselNext(env,bb->next,bb->jumpkind); 4210 4211 /* record the number of vregs we used. */ 4212 env->code->n_vregs = env->vreg_ctr; 4213 return env->code; 4214 } 4215 4216 4217 /*---------------------------------------------------------------*/ 4218 /*--- end host_ppc_isel.c ---*/ 4219 /*---------------------------------------------------------------*/ 4220