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