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