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