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-2013 OpenWorks LLP 11 info@open-works.net 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 26 02110-1301, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 30 Neither the names of the U.S. Department of Energy nor the 31 University of California nor the names of its contributors may be 32 used to endorse or promote products derived from this software 33 without prior written permission. 34*/ 35 36#include "libvex_basictypes.h" 37#include "libvex_ir.h" 38#include "libvex.h" 39 40#include "ir_match.h" 41#include "main_util.h" 42#include "main_globals.h" 43#include "host_generic_regs.h" 44#include "host_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 120What exns -> CR1 ? Sets FPRF ? Observes RM ? 121------------------------------------------------------------- 122 123fmr[.] if . n n 124fneg[.] if . n n 125fabs[.] if . n n 126fnabs[.] if . n n 127 128fadd[.] if . y y 129fadds[.] if . y y 130fcfid[.] (Si64->dbl) if . y y 131fcfidU[.] (Ui64->dbl) if . y y 132fcfids[.] (Si64->sngl) if . Y Y 133fcfidus[.] (Ui64->sngl) if . Y Y 134fcmpo (cmp, result n n n 135fcmpu to crfD) n n n 136fctid[.] (dbl->i64) if . ->undef y 137fctidz[.] (dbl->i64) if . ->undef rounds-to-zero 138fctiw[.] (dbl->i32) if . ->undef y 139fctiwz[.] (dbl->i32) if . ->undef rounds-to-zero 140fdiv[.] if . y y 141fdivs[.] if . y y 142fmadd[.] if . y y 143fmadds[.] if . y y 144fmsub[.] if . y y 145fmsubs[.] if . y y 146fmul[.] if . y y 147fmuls[.] if . y y 148 149(note: for fnm*, rounding happens before final negation) 150fnmadd[.] if . y y 151fnmadds[.] if . y y 152fnmsub[.] if . y y 153fnmsubs[.] if . y y 154 155fre[.] if . y y 156fres[.] if . y y 157 158frsqrte[.] if . y apparently not 159 160fsqrt[.] if . y y 161fsqrts[.] if . y y 162fsub[.] if . y y 163fsubs[.] if . y y 164 165 166fpscr: 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 170ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF 171in future) 172 173mcrfs - move fpscr field to CR field 174mtfsfi[.] - 4 bit imm moved to fpscr field 175mtfsf[.] - move frS[low 1/2] to fpscr but using 8-bit field mask 176mtfsb1[.] - set given fpscr bit 177mtfsb0[.] - clear given fpscr bit 178mffs[.] - move all fpscr to frD[low 1/2] 179 180For [.] presumably cr1 is set with exn summary bits, as per 181main FP insns 182 183A single precision store truncates/denormalises the in-register value, 184but does not round it. This is so that flds followed by fsts is 185always the identity. 186*/ 187 188 189/*---------------------------------------------------------*/ 190/*--- misc helpers ---*/ 191/*---------------------------------------------------------*/ 192 193/* These are duplicated in guest-ppc/toIR.c */ 194static IRExpr* unop ( IROp op, IRExpr* a ) 195{ 196 return IRExpr_Unop(op, a); 197} 198 199static IRExpr* mkU32 ( UInt i ) 200{ 201 return IRExpr_Const(IRConst_U32(i)); 202} 203 204static IRExpr* bind ( Int binder ) 205{ 206 return IRExpr_Binder(binder); 207} 208 209static 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 272typedef 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 302static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp ) 303{ 304 vassert(tmp >= 0); 305 vassert(tmp < env->n_vregmap); 306 return env->vregmapLo[tmp]; 307} 308 309static 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 */ 320static 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 333static 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 342static 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 350static 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 357static 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. */ 382static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e, 383 IREndness IEndianess ); 384static 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*/ 396static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, 397 Bool syned, IRExpr* e, 398 IREndness IEndianess ); 399static 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). */ 405static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e, 406 IREndness IEndianess ); 407static 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. */ 413static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e, 414 IREndness IEndianess ); 415static 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. */ 421static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e, 422 IREndness IEndianess ); 423static 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. */ 437static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, 438 IRType xferTy, 439 IREndness IEndianess ); 440static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, 441 IRType xferTy, 442 IREndness IEndianess ); 443 444static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi, 445 HReg* rMedLo, HReg* rLo, 446 ISelEnv* env, IRExpr* e, 447 IREndness IEndianess ); 448static 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. */ 455static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, 456 ISelEnv* env, IRExpr* e, 457 IREndness IEndianess ); 458static 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. */ 463static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, 464 ISelEnv* env, IRExpr* e, 465 IREndness IEndianess ); 466 467static void iselInt128Expr ( HReg* rHi, HReg* rLo, 468 ISelEnv* env, IRExpr* e, 469 IREndness IEndianess ); 470 471static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e, 472 IREndness IEndianess ); 473static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e, 474 IREndness IEndianess ); 475 476static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e, 477 IREndness IEndianess ); 478static HReg iselDblExpr ( ISelEnv* env, IRExpr* e, 479 IREndness IEndianess ); 480 481static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e, 482 IREndness IEndianess ); 483static HReg iselFltExpr ( ISelEnv* env, IRExpr* e, 484 IREndness IEndianess ); 485 486static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e, 487 IREndness IEndianess ); 488static HReg iselVecExpr ( ISelEnv* env, IRExpr* e, 489 IREndness IEndianess ); 490 491/* 64-bit mode ONLY. */ 492static HReg iselDfp32Expr_wrk ( ISelEnv* env, IRExpr* e, 493 IREndness IEndianess ); 494static HReg iselDfp32Expr ( ISelEnv* env, IRExpr* e, 495 IREndness IEndianess ); 496static HReg iselDfp64Expr_wrk ( ISelEnv* env, IRExpr* e, 497 IREndness IEndianess ); 498static HReg iselDfp64Expr ( ISelEnv* env, IRExpr* e, 499 IREndness IEndianess ); 500 501/* 64-bit mode ONLY: compute an D128 into a GPR64 pair. */ 502static void iselDfp128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, 503 IRExpr* e, IREndness IEndianess ); 504static 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 513static 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 523static 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 531static 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*/ 545static 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 */ 563static 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 */ 589static 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 614static 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. */ 630static 631PPCAMode* 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*/ 697static 698Bool 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 716static 717void 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 */ 1094static 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*/ 1163static 1164void _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 1216static void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode, 1217 IREndness IEndianess ) 1218{ 1219 _set_FPU_rounding_mode(env, mode, False, IEndianess); 1220} 1221 1222static 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*/ 1235static 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*/ 1244static 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*/ 1260static 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 */ 1339static 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 1383static 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 ! */ 1397static 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 2475static Bool uInt_fits_in_16_bits ( UInt u ) 2476{ 2477 /* Is u the same as the sign-extend of its lower 16 bits? */ 2478 Int i = u & 0xFFFF; 2479 i <<= 16; 2480 i >>= 16; 2481 return toBool(u == (UInt)i); 2482} 2483 2484static Bool uLong_fits_in_16_bits ( ULong u ) 2485{ 2486 /* Is u the same as the sign-extend of its lower 16 bits? */ 2487 Long i = u & 0xFFFFULL; 2488 i <<= 48; 2489 i >>= 48; 2490 return toBool(u == (ULong)i); 2491} 2492 2493static Bool uLong_is_4_aligned ( ULong u ) 2494{ 2495 return toBool((u & 3ULL) == 0); 2496} 2497 2498static Bool sane_AMode ( ISelEnv* env, PPCAMode* am ) 2499{ 2500 Bool mode64 = env->mode64; 2501 switch (am->tag) { 2502 case Pam_IR: 2503 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus, 2504 somehow, but I think it's OK. */ 2505 return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) && 2506 hregIsVirtual(am->Pam.IR.base) && 2507 uInt_fits_in_16_bits(am->Pam.IR.index) ); 2508 case Pam_RR: 2509 return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) && 2510 hregIsVirtual(am->Pam.RR.base) && 2511 hregClass(am->Pam.RR.index) == HRcGPR(mode64) && 2512 hregIsVirtual(am->Pam.RR.index) ); 2513 default: 2514 vpanic("sane_AMode: unknown ppc amode tag"); 2515 } 2516} 2517 2518static 2519PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy, 2520 IREndness IEndianess ) 2521{ 2522 PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy, IEndianess); 2523 vassert(sane_AMode(env, am)); 2524 return am; 2525} 2526 2527/* DO NOT CALL THIS DIRECTLY ! */ 2528static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, 2529 IRType xferTy, IREndness IEndianess ) 2530{ 2531 IRType ty = typeOfIRExpr(env->type_env,e); 2532 2533 if (env->mode64) { 2534 2535 /* If the data load/store type is I32 or I64, this amode might 2536 be destined for use in ld/ldu/lwa/st/stu. In which case 2537 insist that if it comes out as an _IR, the immediate must 2538 have its bottom two bits be zero. This does assume that for 2539 any other type (I8/I16/I128/F32/F64/V128) the amode will not 2540 be parked in any such instruction. But that seems a 2541 reasonable assumption. */ 2542 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64); 2543 2544 vassert(ty == Ity_I64); 2545 2546 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */ 2547 if (e->tag == Iex_Binop 2548 && e->Iex.Binop.op == Iop_Add64 2549 && e->Iex.Binop.arg2->tag == Iex_Const 2550 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64 2551 && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2 2552 ->Iex.Const.con->Ico.U64) 2553 : True) 2554 && uLong_fits_in_16_bits(e->Iex.Binop.arg2 2555 ->Iex.Const.con->Ico.U64)) { 2556 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64, 2557 iselWordExpr_R(env, e->Iex.Binop.arg1, 2558 IEndianess) ); 2559 } 2560 2561 /* Add64(expr,expr) */ 2562 if (e->tag == Iex_Binop 2563 && e->Iex.Binop.op == Iop_Add64) { 2564 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 2565 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 2566 return PPCAMode_RR( r_idx, r_base ); 2567 } 2568 2569 } else { 2570 2571 vassert(ty == Ity_I32); 2572 2573 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */ 2574 if (e->tag == Iex_Binop 2575 && e->Iex.Binop.op == Iop_Add32 2576 && e->Iex.Binop.arg2->tag == Iex_Const 2577 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32 2578 && uInt_fits_in_16_bits(e->Iex.Binop.arg2 2579 ->Iex.Const.con->Ico.U32)) { 2580 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32, 2581 iselWordExpr_R(env, e->Iex.Binop.arg1, 2582 IEndianess) ); 2583 } 2584 2585 /* Add32(expr,expr) */ 2586 if (e->tag == Iex_Binop 2587 && e->Iex.Binop.op == Iop_Add32) { 2588 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 2589 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 2590 return PPCAMode_RR( r_idx, r_base ); 2591 } 2592 2593 } 2594 2595 /* Doesn't match anything in particular. Generate it into 2596 a register and use that. */ 2597 return PPCAMode_IR( 0, iselWordExpr_R(env,e,IEndianess) ); 2598} 2599 2600 2601/* --------------------- RH --------------------- */ 2602 2603/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH 2604 (reg-or-halfword-immediate). It's important to specify whether the 2605 immediate is to be regarded as signed or not. If yes, this will 2606 never return -32768 as an immediate; this guaranteed that all 2607 signed immediates that are return can have their sign inverted if 2608 need be. */ 2609 2610static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e, 2611 IREndness IEndianess ) 2612{ 2613 PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e, IEndianess); 2614 /* sanity checks ... */ 2615 switch (ri->tag) { 2616 case Prh_Imm: 2617 vassert(ri->Prh.Imm.syned == syned); 2618 if (syned) 2619 vassert(ri->Prh.Imm.imm16 != 0x8000); 2620 return ri; 2621 case Prh_Reg: 2622 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64)); 2623 vassert(hregIsVirtual(ri->Prh.Reg.reg)); 2624 return ri; 2625 default: 2626 vpanic("iselIntExpr_RH: unknown ppc RH tag"); 2627 } 2628} 2629 2630/* DO NOT CALL THIS DIRECTLY ! */ 2631static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e, 2632 IREndness IEndianess ) 2633{ 2634 ULong u; 2635 Long l; 2636 IRType ty = typeOfIRExpr(env->type_env,e); 2637 vassert(ty == Ity_I8 || ty == Ity_I16 || 2638 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64)); 2639 2640 /* special case: immediate */ 2641 if (e->tag == Iex_Const) { 2642 IRConst* con = e->Iex.Const.con; 2643 /* What value are we aiming to generate? */ 2644 switch (con->tag) { 2645 /* Note: Not sign-extending - we carry 'syned' around */ 2646 case Ico_U64: vassert(env->mode64); 2647 u = con->Ico.U64; break; 2648 case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break; 2649 case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break; 2650 case Ico_U8: u = 0x000000FF & con->Ico.U8; break; 2651 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)"); 2652 } 2653 l = (Long)u; 2654 /* Now figure out if it's representable. */ 2655 if (!syned && u <= 65535) { 2656 return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF)); 2657 } 2658 if (syned && l >= -32767 && l <= 32767) { 2659 return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF)); 2660 } 2661 /* no luck; use the Slow Way. */ 2662 } 2663 2664 /* default case: calculate into a register and return that */ 2665 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) ); 2666} 2667 2668 2669/* --------------------- RIs --------------------- */ 2670 2671/* Calculate an expression into an PPCRI operand. As with 2672 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or, 2673 in 64-bit mode, 64 bits. */ 2674 2675static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 2676{ 2677 PPCRI* ri = iselWordExpr_RI_wrk(env, e, IEndianess); 2678 /* sanity checks ... */ 2679 switch (ri->tag) { 2680 case Pri_Imm: 2681 return ri; 2682 case Pri_Reg: 2683 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64)); 2684 vassert(hregIsVirtual(ri->Pri.Reg)); 2685 return ri; 2686 default: 2687 vpanic("iselIntExpr_RI: unknown ppc RI tag"); 2688 } 2689} 2690 2691/* DO NOT CALL THIS DIRECTLY ! */ 2692static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e, 2693 IREndness IEndianess ) 2694{ 2695 Long l; 2696 IRType ty = typeOfIRExpr(env->type_env,e); 2697 vassert(ty == Ity_I8 || ty == Ity_I16 || 2698 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64)); 2699 2700 /* special case: immediate */ 2701 if (e->tag == Iex_Const) { 2702 IRConst* con = e->Iex.Const.con; 2703 switch (con->tag) { 2704 case Ico_U64: vassert(env->mode64); 2705 l = (Long) con->Ico.U64; break; 2706 case Ico_U32: l = (Long)(Int) con->Ico.U32; break; 2707 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break; 2708 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break; 2709 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)"); 2710 } 2711 return PPCRI_Imm((ULong)l); 2712 } 2713 2714 /* default case: calculate into a register and return that */ 2715 return PPCRI_Reg( iselWordExpr_R ( env, e, IEndianess ) ); 2716} 2717 2718 2719/* --------------------- RH5u --------------------- */ 2720 2721/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter 2722 being an immediate in the range 1 .. 31 inclusive. Used for doing 2723 shift amounts. Only used in 32-bit mode. */ 2724 2725static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e, 2726 IREndness IEndianess ) 2727{ 2728 PPCRH* ri; 2729 vassert(!env->mode64); 2730 ri = iselWordExpr_RH5u_wrk(env, e, IEndianess); 2731 /* sanity checks ... */ 2732 switch (ri->tag) { 2733 case Prh_Imm: 2734 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31); 2735 vassert(!ri->Prh.Imm.syned); 2736 return ri; 2737 case Prh_Reg: 2738 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64)); 2739 vassert(hregIsVirtual(ri->Prh.Reg.reg)); 2740 return ri; 2741 default: 2742 vpanic("iselIntExpr_RH5u: unknown ppc RI tag"); 2743 } 2744} 2745 2746/* DO NOT CALL THIS DIRECTLY ! */ 2747static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e, 2748 IREndness IEndianess ) 2749{ 2750 IRType ty = typeOfIRExpr(env->type_env,e); 2751 vassert(ty == Ity_I8); 2752 2753 /* special case: immediate */ 2754 if (e->tag == Iex_Const 2755 && e->Iex.Const.con->tag == Ico_U8 2756 && e->Iex.Const.con->Ico.U8 >= 1 2757 && e->Iex.Const.con->Ico.U8 <= 31) { 2758 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8); 2759 } 2760 2761 /* default case: calculate into a register and return that */ 2762 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) ); 2763} 2764 2765 2766/* --------------------- RH6u --------------------- */ 2767 2768/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter 2769 being an immediate in the range 1 .. 63 inclusive. Used for doing 2770 shift amounts. Only used in 64-bit mode. */ 2771 2772static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e, 2773 IREndness IEndianess ) 2774{ 2775 PPCRH* ri; 2776 vassert(env->mode64); 2777 ri = iselWordExpr_RH6u_wrk(env, e, IEndianess); 2778 /* sanity checks ... */ 2779 switch (ri->tag) { 2780 case Prh_Imm: 2781 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63); 2782 vassert(!ri->Prh.Imm.syned); 2783 return ri; 2784 case Prh_Reg: 2785 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64)); 2786 vassert(hregIsVirtual(ri->Prh.Reg.reg)); 2787 return ri; 2788 default: 2789 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag"); 2790 } 2791} 2792 2793/* DO NOT CALL THIS DIRECTLY ! */ 2794static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e, 2795 IREndness IEndianess ) 2796{ 2797 IRType ty = typeOfIRExpr(env->type_env,e); 2798 vassert(ty == Ity_I8); 2799 2800 /* special case: immediate */ 2801 if (e->tag == Iex_Const 2802 && e->Iex.Const.con->tag == Ico_U8 2803 && e->Iex.Const.con->Ico.U8 >= 1 2804 && e->Iex.Const.con->Ico.U8 <= 63) { 2805 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8); 2806 } 2807 2808 /* default case: calculate into a register and return that */ 2809 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) ); 2810} 2811 2812 2813/* --------------------- CONDCODE --------------------- */ 2814 2815/* Generate code to evaluated a bit-typed expression, returning the 2816 condition code which would correspond when the expression would 2817 notionally have returned 1. */ 2818 2819static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e, 2820 IREndness IEndianess ) 2821{ 2822 /* Uh, there's nothing we can sanity check here, unfortunately. */ 2823 return iselCondCode_wrk(env,e, IEndianess); 2824} 2825 2826/* DO NOT CALL THIS DIRECTLY ! */ 2827static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e, 2828 IREndness IEndianess ) 2829{ 2830 vassert(e); 2831 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1); 2832 2833 /* Constant 1:Bit */ 2834 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) { 2835 // Make a compare that will always be true: 2836 HReg r_zero = newVRegI(env); 2837 addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64)); 2838 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2839 7/*cr*/, r_zero, PPCRH_Reg(r_zero))); 2840 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2841 } 2842 2843 /* Not1(...) */ 2844 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) { 2845 /* Generate code for the arg, and negate the test condition */ 2846 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess); 2847 cond.test = invertCondTest(cond.test); 2848 return cond; 2849 } 2850 2851 /* --- patterns rooted at: 32to1 or 64to1 --- */ 2852 2853 /* 32to1, 64to1 */ 2854 if (e->tag == Iex_Unop && 2855 (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) { 2856 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 2857 HReg tmp = newVRegI(env); 2858 /* could do better, probably -- andi. */ 2859 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, 2860 src, PPCRH_Imm(False,1))); 2861 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2862 7/*cr*/, tmp, PPCRH_Imm(False,1))); 2863 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2864 } 2865 2866 /* --- patterns rooted at: CmpNEZ8 --- */ 2867 2868 /* CmpNEZ8(x) */ 2869 /* Note this cloned as CmpNE8(x,0) below. */ 2870 /* could do better -- andi. */ 2871 if (e->tag == Iex_Unop 2872 && e->Iex.Unop.op == Iop_CmpNEZ8) { 2873 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 2874 HReg tmp = newVRegI(env); 2875 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg, 2876 PPCRH_Imm(False,0xFF))); 2877 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2878 7/*cr*/, tmp, PPCRH_Imm(False,0))); 2879 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2880 } 2881 2882 /* --- patterns rooted at: CmpNEZ32 --- */ 2883 2884 /* CmpNEZ32(x) */ 2885 if (e->tag == Iex_Unop 2886 && e->Iex.Unop.op == Iop_CmpNEZ32) { 2887 HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 2888 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2889 7/*cr*/, r1, PPCRH_Imm(False,0))); 2890 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2891 } 2892 2893 /* --- patterns rooted at: Cmp*32* --- */ 2894 2895 /* Cmp*32*(x,y) */ 2896 if (e->tag == Iex_Binop 2897 && (e->Iex.Binop.op == Iop_CmpEQ32 2898 || e->Iex.Binop.op == Iop_CmpNE32 2899 || e->Iex.Binop.op == Iop_CmpLT32S 2900 || e->Iex.Binop.op == Iop_CmpLT32U 2901 || e->Iex.Binop.op == Iop_CmpLE32S 2902 || e->Iex.Binop.op == Iop_CmpLE32U)) { 2903 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S || 2904 e->Iex.Binop.op == Iop_CmpLE32S); 2905 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 2906 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess); 2907 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/, 2908 7/*cr*/, r1, ri2)); 2909 2910 switch (e->Iex.Binop.op) { 2911 case Iop_CmpEQ32: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2912 case Iop_CmpNE32: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2913 case Iop_CmpLT32U: case Iop_CmpLT32S: 2914 return mk_PPCCondCode( Pct_TRUE, Pcf_7LT ); 2915 case Iop_CmpLE32U: case Iop_CmpLE32S: 2916 return mk_PPCCondCode( Pct_FALSE, Pcf_7GT ); 2917 default: vpanic("iselCondCode(ppc): CmpXX32"); 2918 } 2919 } 2920 2921 /* --- patterns rooted at: CmpNEZ64 --- */ 2922 2923 /* CmpNEZ64 */ 2924 if (e->tag == Iex_Unop 2925 && e->Iex.Unop.op == Iop_CmpNEZ64) { 2926 if (!env->mode64) { 2927 HReg hi, lo; 2928 HReg tmp = newVRegI(env); 2929 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg, IEndianess ); 2930 addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi))); 2931 addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/, 2932 7/*cr*/, tmp,PPCRH_Imm(False,0))); 2933 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2934 } else { // mode64 2935 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 2936 addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/, 2937 7/*cr*/, r_src,PPCRH_Imm(False,0))); 2938 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2939 } 2940 } 2941 2942 /* --- patterns rooted at: Cmp*64* --- */ 2943 2944 /* Cmp*64*(x,y) */ 2945 if (e->tag == Iex_Binop 2946 && (e->Iex.Binop.op == Iop_CmpEQ64 2947 || e->Iex.Binop.op == Iop_CmpNE64 2948 || e->Iex.Binop.op == Iop_CmpLT64S 2949 || e->Iex.Binop.op == Iop_CmpLT64U 2950 || e->Iex.Binop.op == Iop_CmpLE64S 2951 || e->Iex.Binop.op == Iop_CmpLE64U)) { 2952 Bool syned = (e->Iex.Binop.op == Iop_CmpLT64S || 2953 e->Iex.Binop.op == Iop_CmpLE64S); 2954 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 2955 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess); 2956 vassert(env->mode64); 2957 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/, 2958 7/*cr*/, r1, ri2)); 2959 2960 switch (e->Iex.Binop.op) { 2961 case Iop_CmpEQ64: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2962 case Iop_CmpNE64: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2963 case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT ); 2964 case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT ); 2965 default: vpanic("iselCondCode(ppc): CmpXX64"); 2966 } 2967 } 2968 2969 /* --- patterns rooted at: CmpNE8 --- */ 2970 2971 /* CmpNE8(x,0) */ 2972 /* Note this is a direct copy of CmpNEZ8 above. */ 2973 /* could do better -- andi. */ 2974 if (e->tag == Iex_Binop 2975 && e->Iex.Binop.op == Iop_CmpNE8 2976 && isZeroU8(e->Iex.Binop.arg2)) { 2977 HReg arg = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 2978 HReg tmp = newVRegI(env); 2979 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg, 2980 PPCRH_Imm(False,0xFF))); 2981 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2982 7/*cr*/, tmp, PPCRH_Imm(False,0))); 2983 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ ); 2984 } 2985 2986 /* var */ 2987 if (e->tag == Iex_RdTmp) { 2988 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp); 2989 HReg src_masked = newVRegI(env); 2990 addInstr(env, 2991 PPCInstr_Alu(Palu_AND, src_masked, 2992 r_src, PPCRH_Imm(False,1))); 2993 addInstr(env, 2994 PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 2995 7/*cr*/, src_masked, PPCRH_Imm(False,1))); 2996 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ ); 2997 } 2998 2999 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag); 3000 ppIRExpr(e); 3001 vpanic("iselCondCode(ppc)"); 3002} 3003 3004 3005/*---------------------------------------------------------*/ 3006/*--- ISEL: Integer expressions (128 bit) ---*/ 3007/*---------------------------------------------------------*/ 3008 3009/* 64-bit mode ONLY: compute a 128-bit value into a register pair, 3010 which is returned as the first two parameters. As with 3011 iselWordExpr_R, these may be either real or virtual regs; in any 3012 case they must not be changed by subsequent code emitted by the 3013 caller. */ 3014 3015static void iselInt128Expr ( HReg* rHi, HReg* rLo, 3016 ISelEnv* env, IRExpr* e, IREndness IEndianess ) 3017{ 3018 vassert(env->mode64); 3019 iselInt128Expr_wrk(rHi, rLo, env, e, IEndianess); 3020# if 0 3021 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3022# endif 3023 vassert(hregClass(*rHi) == HRcGPR(env->mode64)); 3024 vassert(hregIsVirtual(*rHi)); 3025 vassert(hregClass(*rLo) == HRcGPR(env->mode64)); 3026 vassert(hregIsVirtual(*rLo)); 3027} 3028 3029/* DO NOT CALL THIS DIRECTLY ! */ 3030static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, 3031 ISelEnv* env, IRExpr* e, IREndness IEndianess ) 3032{ 3033 vassert(e); 3034 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128); 3035 3036 /* read 128-bit IRTemp */ 3037 if (e->tag == Iex_RdTmp) { 3038 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp); 3039 return; 3040 } 3041 3042 /* --------- BINARY ops --------- */ 3043 if (e->tag == Iex_Binop) { 3044 switch (e->Iex.Binop.op) { 3045 /* 64 x 64 -> 128 multiply */ 3046 case Iop_MullU64: 3047 case Iop_MullS64: { 3048 HReg tLo = newVRegI(env); 3049 HReg tHi = newVRegI(env); 3050 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64); 3051 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 3052 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 3053 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 3054 False/*lo64*/, False/*64bit mul*/, 3055 tLo, r_srcL, r_srcR)); 3056 addInstr(env, PPCInstr_MulL(syned, 3057 True/*hi64*/, False/*64bit mul*/, 3058 tHi, r_srcL, r_srcR)); 3059 *rHi = tHi; 3060 *rLo = tLo; 3061 return; 3062 } 3063 3064 /* 64HLto128(e1,e2) */ 3065 case Iop_64HLto128: 3066 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 3067 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 3068 return; 3069 default: 3070 break; 3071 } 3072 } /* if (e->tag == Iex_Binop) */ 3073 3074 3075 /* --------- UNARY ops --------- */ 3076 if (e->tag == Iex_Unop) { 3077 switch (e->Iex.Unop.op) { 3078 default: 3079 break; 3080 } 3081 } /* if (e->tag == Iex_Unop) */ 3082 3083 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag); 3084 ppIRExpr(e); 3085 vpanic("iselInt128Expr(ppc64)"); 3086} 3087 3088 3089/*---------------------------------------------------------*/ 3090/*--- ISEL: Integer expressions (64 bit) ---*/ 3091/*---------------------------------------------------------*/ 3092 3093/* 32-bit mode ONLY: compute a 128-bit value into a register quad */ 3094static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo, 3095 HReg* rLo, ISelEnv* env, IRExpr* e, 3096 IREndness IEndianess ) 3097{ 3098 vassert(!env->mode64); 3099 iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e, IEndianess); 3100# if 0 3101 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3102# endif 3103 vassert(hregClass(*rHi) == HRcInt32); 3104 vassert(hregIsVirtual(*rHi)); 3105 vassert(hregClass(*rMedHi) == HRcInt32); 3106 vassert(hregIsVirtual(*rMedHi)); 3107 vassert(hregClass(*rMedLo) == HRcInt32); 3108 vassert(hregIsVirtual(*rMedLo)); 3109 vassert(hregClass(*rLo) == HRcInt32); 3110 vassert(hregIsVirtual(*rLo)); 3111} 3112 3113static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi, 3114 HReg* rMedLo, HReg* rLo, 3115 ISelEnv* env, IRExpr* e, 3116 IREndness IEndianess ) 3117{ 3118 vassert(e); 3119 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128); 3120 3121 /* read 128-bit IRTemp */ 3122 if (e->tag == Iex_RdTmp) { 3123 lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp); 3124 return; 3125 } 3126 3127 if (e->tag == Iex_Binop) { 3128 3129 IROp op_binop = e->Iex.Binop.op; 3130 switch (op_binop) { 3131 case Iop_64HLto128: 3132 iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess); 3133 iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess); 3134 return; 3135 default: 3136 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n", 3137 op_binop); 3138 break; 3139 } 3140 } 3141 3142 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag); 3143 return; 3144} 3145 3146/* 32-bit mode ONLY: compute a 64-bit value into a register pair, 3147 which is returned as the first two parameters. As with 3148 iselIntExpr_R, these may be either real or virtual regs; in any 3149 case they must not be changed by subsequent code emitted by the 3150 caller. */ 3151 3152static void iselInt64Expr ( HReg* rHi, HReg* rLo, 3153 ISelEnv* env, IRExpr* e, 3154 IREndness IEndianess ) 3155{ 3156 vassert(!env->mode64); 3157 iselInt64Expr_wrk(rHi, rLo, env, e, IEndianess); 3158# if 0 3159 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3160# endif 3161 vassert(hregClass(*rHi) == HRcInt32); 3162 vassert(hregIsVirtual(*rHi)); 3163 vassert(hregClass(*rLo) == HRcInt32); 3164 vassert(hregIsVirtual(*rLo)); 3165} 3166 3167/* DO NOT CALL THIS DIRECTLY ! */ 3168static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, 3169 ISelEnv* env, IRExpr* e, 3170 IREndness IEndianess ) 3171{ 3172 vassert(e); 3173 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64); 3174 3175 /* 64-bit load */ 3176 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) { 3177 HReg tLo = newVRegI(env); 3178 HReg tHi = newVRegI(env); 3179 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr, IEndianess); 3180 vassert(!env->mode64); 3181 addInstr(env, PPCInstr_Load( 4/*byte-load*/, 3182 tHi, PPCAMode_IR( 0, r_addr ), 3183 False/*32-bit insn please*/) ); 3184 addInstr(env, PPCInstr_Load( 4/*byte-load*/, 3185 tLo, PPCAMode_IR( 4, r_addr ), 3186 False/*32-bit insn please*/) ); 3187 *rHi = tHi; 3188 *rLo = tLo; 3189 return; 3190 } 3191 3192 /* 64-bit literal */ 3193 if (e->tag == Iex_Const) { 3194 ULong w64 = e->Iex.Const.con->Ico.U64; 3195 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF; 3196 UInt wLo = ((UInt)w64) & 0xFFFFFFFF; 3197 HReg tLo = newVRegI(env); 3198 HReg tHi = newVRegI(env); 3199 vassert(e->Iex.Const.con->tag == Ico_U64); 3200 addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/)); 3201 addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/)); 3202 *rHi = tHi; 3203 *rLo = tLo; 3204 return; 3205 } 3206 3207 /* read 64-bit IRTemp */ 3208 if (e->tag == Iex_RdTmp) { 3209 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp); 3210 return; 3211 } 3212 3213 /* 64-bit GET */ 3214 if (e->tag == Iex_Get) { 3215 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 3216 GuestStatePtr(False/*mode32*/) ); 3217 PPCAMode* am_addr4 = advance4(env, am_addr); 3218 HReg tLo = newVRegI(env); 3219 HReg tHi = newVRegI(env); 3220 addInstr(env, PPCInstr_Load( 4, tHi, am_addr, False/*mode32*/ )); 3221 addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ )); 3222 *rHi = tHi; 3223 *rLo = tLo; 3224 return; 3225 } 3226 3227 /* 64-bit ITE */ 3228 if (e->tag == Iex_ITE) { // VFD 3229 HReg e0Lo, e0Hi, eXLo, eXHi; 3230 iselInt64Expr(&eXHi, &eXLo, env, e->Iex.ITE.iftrue, IEndianess); 3231 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse, IEndianess); 3232 HReg tLo = newVRegI(env); 3233 HReg tHi = newVRegI(env); 3234 addInstr(env, mk_iMOVds_RR(tHi,e0Hi)); 3235 addInstr(env, mk_iMOVds_RR(tLo,e0Lo)); 3236 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess); 3237 addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(eXHi))); 3238 addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(eXLo))); 3239 *rHi = tHi; 3240 *rLo = tLo; 3241 return; 3242 } 3243 3244 /* --------- BINARY ops --------- */ 3245 if (e->tag == Iex_Binop) { 3246 IROp op_binop = e->Iex.Binop.op; 3247 switch (op_binop) { 3248 /* 32 x 32 -> 64 multiply */ 3249 case Iop_MullU32: 3250 case Iop_MullS32: { 3251 HReg tLo = newVRegI(env); 3252 HReg tHi = newVRegI(env); 3253 Bool syned = toBool(op_binop == Iop_MullS32); 3254 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, 3255 IEndianess); 3256 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, 3257 IEndianess); 3258 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 3259 False/*lo32*/, True/*32bit mul*/, 3260 tLo, r_srcL, r_srcR)); 3261 addInstr(env, PPCInstr_MulL(syned, 3262 True/*hi32*/, True/*32bit mul*/, 3263 tHi, r_srcL, r_srcR)); 3264 *rHi = tHi; 3265 *rLo = tLo; 3266 return; 3267 } 3268 3269 /* Or64/And64/Xor64 */ 3270 case Iop_Or64: 3271 case Iop_And64: 3272 case Iop_Xor64: { 3273 HReg xLo, xHi, yLo, yHi; 3274 HReg tLo = newVRegI(env); 3275 HReg tHi = newVRegI(env); 3276 PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR : 3277 (op_binop == Iop_And64) ? Palu_AND : Palu_XOR; 3278 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess); 3279 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess); 3280 addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi))); 3281 addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo))); 3282 *rHi = tHi; 3283 *rLo = tLo; 3284 return; 3285 } 3286 3287 /* Add64 */ 3288 case Iop_Add64: { 3289 HReg xLo, xHi, yLo, yHi; 3290 HReg tLo = newVRegI(env); 3291 HReg tHi = newVRegI(env); 3292 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess); 3293 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess); 3294 addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/, 3295 tLo, xLo, yLo)); 3296 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/, 3297 tHi, xHi, yHi)); 3298 *rHi = tHi; 3299 *rLo = tLo; 3300 return; 3301 } 3302 3303 /* 32HLto64(e1,e2) */ 3304 case Iop_32HLto64: 3305 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 3306 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 3307 return; 3308 3309 /* F64toI64[S|U] */ 3310 case Iop_F64toI64S: case Iop_F64toI64U: { 3311 HReg tLo = newVRegI(env); 3312 HReg tHi = newVRegI(env); 3313 HReg r1 = StackFramePtr(env->mode64); 3314 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 3315 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 ); 3316 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2, 3317 IEndianess); 3318 HReg ftmp = newVRegF(env); 3319 3320 vassert(!env->mode64); 3321 /* Set host rounding mode */ 3322 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 3323 3324 sub_from_sp( env, 16 ); 3325 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, 3326 (op_binop == Iop_F64toI64S) ? True : False, 3327 True, ftmp, fsrc)); 3328 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1)); 3329 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/)); 3330 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/)); 3331 add_to_sp( env, 16 ); 3332 3333 ///* Restore default FPU rounding. */ 3334 //set_FPU_rounding_default( env ); 3335 *rHi = tHi; 3336 *rLo = tLo; 3337 return; 3338 } 3339 case Iop_D64toI64S: { 3340 HReg tLo = newVRegI(env); 3341 HReg tHi = newVRegI(env); 3342 HReg r1 = StackFramePtr(env->mode64); 3343 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 3344 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 ); 3345 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess); 3346 HReg tmp = newVRegF(env); 3347 3348 vassert(!env->mode64); 3349 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 3350 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src)); 3351 3352 sub_from_sp( env, 16 ); 3353 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1)); 3354 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/)); 3355 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/)); 3356 add_to_sp( env, 16 ); 3357 *rHi = tHi; 3358 *rLo = tLo; 3359 return; 3360 } 3361 case Iop_D128toI64S: { 3362 PPCFpOp fpop = Pfp_DCTFIXQ; 3363 HReg r_srcHi = newVRegF(env); 3364 HReg r_srcLo = newVRegF(env); 3365 HReg tLo = newVRegI(env); 3366 HReg tHi = newVRegI(env); 3367 HReg ftmp = newVRegF(env); 3368 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 3369 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 3370 3371 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 3372 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2, 3373 IEndianess); 3374 addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo)); 3375 3376 // put the D64 result into an integer register pair 3377 sub_from_sp( env, 16 ); 3378 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1)); 3379 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/)); 3380 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/)); 3381 add_to_sp( env, 16 ); 3382 *rHi = tHi; 3383 *rLo = tLo; 3384 return; 3385 } 3386 default: 3387 break; 3388 } 3389 } /* if (e->tag == Iex_Binop) */ 3390 3391 3392 /* --------- UNARY ops --------- */ 3393 if (e->tag == Iex_Unop) { 3394 switch (e->Iex.Unop.op) { 3395 3396 /* CmpwNEZ64(e) */ 3397 case Iop_CmpwNEZ64: { 3398 HReg argHi, argLo; 3399 HReg tmp1 = newVRegI(env); 3400 HReg tmp2 = newVRegI(env); 3401 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess); 3402 /* tmp1 = argHi | argLo */ 3403 addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo))); 3404 /* tmp2 = (tmp1 | -tmp1) >>s 31 */ 3405 addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1)); 3406 addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1))); 3407 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 3408 tmp2, tmp2, PPCRH_Imm(False, 31))); 3409 *rHi = tmp2; 3410 *rLo = tmp2; /* yes, really tmp2 */ 3411 return; 3412 } 3413 3414 /* Left64 */ 3415 case Iop_Left64: { 3416 HReg argHi, argLo; 3417 HReg zero32 = newVRegI(env); 3418 HReg resHi = newVRegI(env); 3419 HReg resLo = newVRegI(env); 3420 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess); 3421 vassert(env->mode64 == False); 3422 addInstr(env, PPCInstr_LI(zero32, 0, env->mode64)); 3423 /* resHi:resLo = - argHi:argLo */ 3424 addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/, 3425 resLo, zero32, argLo )); 3426 addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/, 3427 resHi, zero32, argHi )); 3428 /* resHi:resLo |= srcHi:srcLo */ 3429 addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo))); 3430 addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi))); 3431 *rHi = resHi; 3432 *rLo = resLo; 3433 return; 3434 } 3435 3436 /* 32Sto64(e) */ 3437 case Iop_32Sto64: { 3438 HReg tHi = newVRegI(env); 3439 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 3440 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 3441 tHi, src, PPCRH_Imm(False,31))); 3442 *rHi = tHi; 3443 *rLo = src; 3444 return; 3445 } 3446 case Iop_ExtractExpD64: { 3447 HReg tmp = newVRegF(env); 3448 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess); 3449 HReg tLo = newVRegI(env); 3450 HReg tHi = newVRegI(env); 3451 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 3452 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 3453 3454 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src)); 3455 3456 // put the D64 result into a integer register pair 3457 sub_from_sp( env, 16 ); 3458 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1)); 3459 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/)); 3460 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/)); 3461 add_to_sp( env, 16 ); 3462 *rHi = tHi; 3463 *rLo = tLo; 3464 return; 3465 } 3466 case Iop_ExtractExpD128: { 3467 HReg r_srcHi; 3468 HReg r_srcLo; 3469 HReg tmp = newVRegF(env); 3470 HReg tLo = newVRegI(env); 3471 HReg tHi = newVRegI(env); 3472 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 3473 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 3474 3475 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, IEndianess); 3476 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp, 3477 r_srcHi, r_srcLo)); 3478 3479 // put the D64 result into a integer register pair 3480 sub_from_sp( env, 16 ); 3481 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1)); 3482 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/)); 3483 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/)); 3484 add_to_sp( env, 16 ); 3485 *rHi = tHi; 3486 *rLo = tLo; 3487 return; 3488 } 3489 3490 /* 32Uto64(e) */ 3491 case Iop_32Uto64: { 3492 HReg tHi = newVRegI(env); 3493 HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 3494 addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/)); 3495 *rHi = tHi; 3496 *rLo = tLo; 3497 return; 3498 } 3499 3500 case Iop_128to64: { 3501 /* Narrow, return the low 64-bit half as a 32-bit 3502 * register pair */ 3503 HReg r_Hi = INVALID_HREG; 3504 HReg r_MedHi = INVALID_HREG; 3505 HReg r_MedLo = INVALID_HREG; 3506 HReg r_Lo = INVALID_HREG; 3507 3508 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo, 3509 env, e->Iex.Unop.arg, IEndianess); 3510 *rHi = r_MedLo; 3511 *rLo = r_Lo; 3512 return; 3513 } 3514 3515 case Iop_128HIto64: { 3516 /* Narrow, return the high 64-bit half as a 32-bit 3517 * register pair */ 3518 HReg r_Hi = INVALID_HREG; 3519 HReg r_MedHi = INVALID_HREG; 3520 HReg r_MedLo = INVALID_HREG; 3521 HReg r_Lo = INVALID_HREG; 3522 3523 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo, 3524 env, e->Iex.Unop.arg, IEndianess); 3525 *rHi = r_Hi; 3526 *rLo = r_MedHi; 3527 return; 3528 } 3529 3530 /* V128{HI}to64 */ 3531 case Iop_V128HIto64: 3532 case Iop_V128to64: { 3533 HReg r_aligned16; 3534 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8; 3535 HReg tLo = newVRegI(env); 3536 HReg tHi = newVRegI(env); 3537 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 3538 PPCAMode *am_off0, *am_offLO, *am_offHI; 3539 sub_from_sp( env, 32 ); // Move SP down 32 bytes 3540 3541 // get a quadword aligned address within our stack space 3542 r_aligned16 = get_sp_aligned16( env ); 3543 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 3544 am_offHI = PPCAMode_IR( off, r_aligned16 ); 3545 am_offLO = PPCAMode_IR( off+4, r_aligned16 ); 3546 3547 // store as Vec128 3548 addInstr(env, 3549 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 )); 3550 3551 // load hi,lo words (of hi/lo half of vec) as Ity_I32's 3552 addInstr(env, 3553 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ )); 3554 addInstr(env, 3555 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ )); 3556 3557 add_to_sp( env, 32 ); // Reset SP 3558 *rHi = tHi; 3559 *rLo = tLo; 3560 return; 3561 } 3562 3563 /* could do better than this, but for now ... */ 3564 case Iop_1Sto64: { 3565 HReg tLo = newVRegI(env); 3566 HReg tHi = newVRegI(env); 3567 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess); 3568 addInstr(env, PPCInstr_Set(cond,tLo)); 3569 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, 3570 tLo, tLo, PPCRH_Imm(False,31))); 3571 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 3572 tLo, tLo, PPCRH_Imm(False,31))); 3573 addInstr(env, mk_iMOVds_RR(tHi, tLo)); 3574 *rHi = tHi; 3575 *rLo = tLo; 3576 return; 3577 } 3578 3579 case Iop_Not64: { 3580 HReg xLo, xHi; 3581 HReg tmpLo = newVRegI(env); 3582 HReg tmpHi = newVRegI(env); 3583 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg, IEndianess); 3584 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo)); 3585 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi)); 3586 *rHi = tmpHi; 3587 *rLo = tmpLo; 3588 return; 3589 } 3590 3591 /* ReinterpF64asI64(e) */ 3592 /* Given an IEEE754 double, produce an I64 with the same bit 3593 pattern. */ 3594 case Iop_ReinterpF64asI64: { 3595 PPCAMode *am_addr0, *am_addr1; 3596 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess); 3597 HReg r_dstLo = newVRegI(env); 3598 HReg r_dstHi = newVRegI(env); 3599 3600 sub_from_sp( env, 16 ); // Move SP down 16 bytes 3601 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) ); 3602 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) ); 3603 3604 // store as F64 3605 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8, 3606 fr_src, am_addr0 )); 3607 3608 // load hi,lo as Ity_I32's 3609 addInstr(env, PPCInstr_Load( 4, r_dstHi, 3610 am_addr0, False/*mode32*/ )); 3611 addInstr(env, PPCInstr_Load( 4, r_dstLo, 3612 am_addr1, False/*mode32*/ )); 3613 *rHi = r_dstHi; 3614 *rLo = r_dstLo; 3615 3616 add_to_sp( env, 16 ); // Reset SP 3617 return; 3618 } 3619 3620 case Iop_ReinterpD64asI64: { 3621 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess); 3622 PPCAMode *am_addr0, *am_addr1; 3623 HReg r_dstLo = newVRegI(env); 3624 HReg r_dstHi = newVRegI(env); 3625 3626 3627 sub_from_sp( env, 16 ); // Move SP down 16 bytes 3628 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) ); 3629 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) ); 3630 3631 // store as D64 3632 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8, 3633 fr_src, am_addr0 )); 3634 3635 // load hi,lo as Ity_I32's 3636 addInstr(env, PPCInstr_Load( 4, r_dstHi, 3637 am_addr0, False/*mode32*/ )); 3638 addInstr(env, PPCInstr_Load( 4, r_dstLo, 3639 am_addr1, False/*mode32*/ )); 3640 *rHi = r_dstHi; 3641 *rLo = r_dstLo; 3642 3643 add_to_sp( env, 16 ); // Reset SP 3644 3645 return; 3646 } 3647 3648 case Iop_BCDtoDPB: { 3649 PPCCondCode cc; 3650 UInt argiregs; 3651 HReg argregs[2]; 3652 Int argreg; 3653 HReg tLo = newVRegI(env); 3654 HReg tHi = newVRegI(env); 3655 HReg tmpHi; 3656 HReg tmpLo; 3657 Bool mode64 = env->mode64; 3658 3659 argregs[0] = hregPPC_GPR3(mode64); 3660 argregs[1] = hregPPC_GPR4(mode64); 3661 3662 argiregs = 0; 3663 argreg = 0; 3664 3665 iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess ); 3666 3667 argiregs |= ( 1 << (argreg+3 ) ); 3668 addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) ); 3669 3670 argiregs |= ( 1 << (argreg+3 ) ); 3671 addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) ); 3672 3673 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE ); 3674 3675 if (IEndianess == Iend_LE) { 3676 addInstr( env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB, 3677 argiregs, 3678 mk_RetLoc_simple(RLPri_2Int) ) ); 3679 } else { 3680 Addr64 target; 3681 target = mode64 ? (Addr)h_calc_BCDtoDPB : 3682 toUInt( (Addr)h_calc_BCDtoDPB ); 3683 addInstr( env, PPCInstr_Call( cc, target, 3684 argiregs, 3685 mk_RetLoc_simple(RLPri_2Int) ) ); 3686 } 3687 3688 addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) ); 3689 addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) ); 3690 3691 *rHi = tHi; 3692 *rLo = tLo; 3693 return; 3694 } 3695 3696 case Iop_DPBtoBCD: { 3697 PPCCondCode cc; 3698 UInt argiregs; 3699 HReg argregs[2]; 3700 Int argreg; 3701 HReg tLo = newVRegI(env); 3702 HReg tHi = newVRegI(env); 3703 HReg tmpHi; 3704 HReg tmpLo; 3705 Bool mode64 = env->mode64; 3706 3707 argregs[0] = hregPPC_GPR3(mode64); 3708 argregs[1] = hregPPC_GPR4(mode64); 3709 3710 argiregs = 0; 3711 argreg = 0; 3712 3713 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess); 3714 3715 argiregs |= (1 << (argreg+3)); 3716 addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi )); 3717 3718 argiregs |= (1 << (argreg+3)); 3719 addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo)); 3720 3721 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE ); 3722 3723 if (IEndianess == Iend_LE) { 3724 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD, 3725 argiregs, 3726 mk_RetLoc_simple(RLPri_2Int) ) ); 3727 } else { 3728 Addr64 target; 3729 target = mode64 ? (Addr)h_calc_DPBtoBCD : 3730 toUInt( (Addr)h_calc_DPBtoBCD ); 3731 addInstr(env, PPCInstr_Call( cc, target, argiregs, 3732 mk_RetLoc_simple(RLPri_2Int) ) ); 3733 } 3734 3735 addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1])); 3736 addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg])); 3737 3738 *rHi = tHi; 3739 *rLo = tLo; 3740 return; 3741 } 3742 3743 default: 3744 break; 3745 } 3746 } /* if (e->tag == Iex_Unop) */ 3747 3748 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag); 3749 ppIRExpr(e); 3750 vpanic("iselInt64Expr(ppc)"); 3751} 3752 3753 3754/*---------------------------------------------------------*/ 3755/*--- ISEL: Floating point expressions (32 bit) ---*/ 3756/*---------------------------------------------------------*/ 3757 3758/* Nothing interesting here; really just wrappers for 3759 64-bit stuff. */ 3760 3761static HReg iselFltExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 3762{ 3763 HReg r = iselFltExpr_wrk( env, e, IEndianess ); 3764# if 0 3765 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3766# endif 3767 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */ 3768 vassert(hregIsVirtual(r)); 3769 return r; 3770} 3771 3772/* DO NOT CALL THIS DIRECTLY */ 3773static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 3774{ 3775 Bool mode64 = env->mode64; 3776 3777 IRType ty = typeOfIRExpr(env->type_env,e); 3778 vassert(ty == Ity_F32); 3779 3780 if (e->tag == Iex_RdTmp) { 3781 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 3782 } 3783 3784 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) { 3785 PPCAMode* am_addr; 3786 HReg r_dst = newVRegF(env); 3787 vassert(e->Iex.Load.ty == Ity_F32); 3788 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/, 3789 IEndianess); 3790 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr)); 3791 return r_dst; 3792 } 3793 3794 if (e->tag == Iex_Get) { 3795 HReg r_dst = newVRegF(env); 3796 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 3797 GuestStatePtr(env->mode64) ); 3798 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr )); 3799 return r_dst; 3800 } 3801 3802 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) { 3803 /* This is quite subtle. The only way to do the relevant 3804 truncation is to do a single-precision store and then a 3805 double precision load to get it back into a register. The 3806 problem is, if the data is then written to memory a second 3807 time, as in 3808 3809 STbe(...) = TruncF64asF32(...) 3810 3811 then will the second truncation further alter the value? The 3812 answer is no: flds (as generated here) followed by fsts 3813 (generated for the STbe) is the identity function on 32-bit 3814 floats, so we are safe. 3815 3816 Another upshot of this is that if iselStmt can see the 3817 entirety of 3818 3819 STbe(...) = TruncF64asF32(arg) 3820 3821 then it can short circuit having to deal with TruncF64asF32 3822 individually; instead just compute arg into a 64-bit FP 3823 register and do 'fsts' (since that itself does the 3824 truncation). 3825 3826 We generate pretty poor code here (should be ok both for 3827 32-bit and 64-bit mode); but it is expected that for the most 3828 part the latter optimisation will apply and hence this code 3829 will not often be used. 3830 */ 3831 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg, IEndianess); 3832 HReg fdst = newVRegF(env); 3833 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 3834 3835 sub_from_sp( env, 16 ); 3836 // store as F32, hence truncating 3837 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4, 3838 fsrc, zero_r1 )); 3839 // and reload. Good huh?! (sigh) 3840 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, 3841 fdst, zero_r1 )); 3842 add_to_sp( env, 16 ); 3843 return fdst; 3844 } 3845 3846 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) { 3847 if (mode64) { 3848 HReg fdst = newVRegF(env); 3849 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 3850 HReg r1 = StackFramePtr(env->mode64); 3851 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 3852 3853 /* Set host rounding mode */ 3854 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 3855 3856 sub_from_sp( env, 16 ); 3857 3858 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/)); 3859 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1)); 3860 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 3861 False, False, 3862 fdst, fdst)); 3863 3864 add_to_sp( env, 16 ); 3865 3866 ///* Restore default FPU rounding. */ 3867 //set_FPU_rounding_default( env ); 3868 return fdst; 3869 } else { 3870 /* 32-bit mode */ 3871 HReg fdst = newVRegF(env); 3872 HReg isrcHi, isrcLo; 3873 HReg r1 = StackFramePtr(env->mode64); 3874 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 3875 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 ); 3876 3877 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, IEndianess); 3878 3879 /* Set host rounding mode */ 3880 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 3881 3882 sub_from_sp( env, 16 ); 3883 3884 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/)); 3885 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/)); 3886 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1)); 3887 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 3888 False, False, 3889 fdst, fdst)); 3890 3891 add_to_sp( env, 16 ); 3892 3893 ///* Restore default FPU rounding. */ 3894 //set_FPU_rounding_default( env ); 3895 return fdst; 3896 } 3897 3898 } 3899 3900 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag); 3901 ppIRExpr(e); 3902 vpanic("iselFltExpr_wrk(ppc)"); 3903} 3904 3905 3906/*---------------------------------------------------------*/ 3907/*--- ISEL: Floating point expressions (64 bit) ---*/ 3908/*---------------------------------------------------------*/ 3909 3910/* Compute a 64-bit floating point value into a register, the identity 3911 of which is returned. As with iselIntExpr_R, the reg may be either 3912 real or virtual; in any case it must not be changed by subsequent 3913 code emitted by the caller. */ 3914 3915/* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm: 3916 3917 Type S (1 bit) E (11 bits) F (52 bits) 3918 ---- --------- ----------- ----------- 3919 signalling NaN u 2047 (max) .0uuuuu---u 3920 (with at least 3921 one 1 bit) 3922 quiet NaN u 2047 (max) .1uuuuu---u 3923 3924 negative infinity 1 2047 (max) .000000---0 3925 3926 positive infinity 0 2047 (max) .000000---0 3927 3928 negative zero 1 0 .000000---0 3929 3930 positive zero 0 0 .000000---0 3931*/ 3932 3933static HReg iselDblExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 3934{ 3935 HReg r = iselDblExpr_wrk( env, e, IEndianess ); 3936# if 0 3937 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 3938# endif 3939 vassert(hregClass(r) == HRcFlt64); 3940 vassert(hregIsVirtual(r)); 3941 return r; 3942} 3943 3944/* DO NOT CALL THIS DIRECTLY */ 3945static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 3946{ 3947 Bool mode64 = env->mode64; 3948 IRType ty = typeOfIRExpr(env->type_env,e); 3949 vassert(e); 3950 vassert(ty == Ity_F64); 3951 3952 if (e->tag == Iex_RdTmp) { 3953 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 3954 } 3955 3956 /* --------- LITERAL --------- */ 3957 if (e->tag == Iex_Const) { 3958 union { UInt u32x2[2]; ULong u64; Double f64; } u; 3959 vassert(sizeof(u) == 8); 3960 vassert(sizeof(u.u64) == 8); 3961 vassert(sizeof(u.f64) == 8); 3962 vassert(sizeof(u.u32x2) == 8); 3963 3964 if (e->Iex.Const.con->tag == Ico_F64) { 3965 u.f64 = e->Iex.Const.con->Ico.F64; 3966 } 3967 else if (e->Iex.Const.con->tag == Ico_F64i) { 3968 u.u64 = e->Iex.Const.con->Ico.F64i; 3969 } 3970 else 3971 vpanic("iselDblExpr(ppc): const"); 3972 3973 if (!mode64) { 3974 HReg r_srcHi = newVRegI(env); 3975 HReg r_srcLo = newVRegI(env); 3976 addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64)); 3977 addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64)); 3978 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo ); 3979 } else { // mode64 3980 HReg r_src = newVRegI(env); 3981 addInstr(env, PPCInstr_LI(r_src, u.u64, mode64)); 3982 return mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64 3983 } 3984 } 3985 3986 /* --------- LOAD --------- */ 3987 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) { 3988 HReg r_dst = newVRegF(env); 3989 PPCAMode* am_addr; 3990 vassert(e->Iex.Load.ty == Ity_F64); 3991 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/, 3992 IEndianess); 3993 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr)); 3994 return r_dst; 3995 } 3996 3997 /* --------- GET --------- */ 3998 if (e->tag == Iex_Get) { 3999 HReg r_dst = newVRegF(env); 4000 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 4001 GuestStatePtr(mode64) ); 4002 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr )); 4003 return r_dst; 4004 } 4005 4006 /* --------- OPS --------- */ 4007 if (e->tag == Iex_Qop) { 4008 PPCFpOp fpop = Pfp_INVALID; 4009 switch (e->Iex.Qop.details->op) { 4010 case Iop_MAddF64: fpop = Pfp_MADDD; break; 4011 case Iop_MAddF64r32: fpop = Pfp_MADDS; break; 4012 case Iop_MSubF64: fpop = Pfp_MSUBD; break; 4013 case Iop_MSubF64r32: fpop = Pfp_MSUBS; break; 4014 default: break; 4015 } 4016 if (fpop != Pfp_INVALID) { 4017 HReg r_dst = newVRegF(env); 4018 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.details->arg2, 4019 IEndianess); 4020 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.details->arg3, 4021 IEndianess); 4022 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4, 4023 IEndianess); 4024 set_FPU_rounding_mode( env, e->Iex.Qop.details->arg1, IEndianess ); 4025 addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst, 4026 r_srcML, r_srcMR, r_srcAcc)); 4027 return r_dst; 4028 } 4029 } 4030 4031 if (e->tag == Iex_Triop) { 4032 IRTriop *triop = e->Iex.Triop.details; 4033 PPCFpOp fpop = Pfp_INVALID; 4034 switch (triop->op) { 4035 case Iop_AddF64: fpop = Pfp_ADDD; break; 4036 case Iop_SubF64: fpop = Pfp_SUBD; break; 4037 case Iop_MulF64: fpop = Pfp_MULD; break; 4038 case Iop_DivF64: fpop = Pfp_DIVD; break; 4039 case Iop_AddF64r32: fpop = Pfp_ADDS; break; 4040 case Iop_SubF64r32: fpop = Pfp_SUBS; break; 4041 case Iop_MulF64r32: fpop = Pfp_MULS; break; 4042 case Iop_DivF64r32: fpop = Pfp_DIVS; break; 4043 default: break; 4044 } 4045 if (fpop != Pfp_INVALID) { 4046 HReg r_dst = newVRegF(env); 4047 HReg r_srcL = iselDblExpr(env, triop->arg2, IEndianess); 4048 HReg r_srcR = iselDblExpr(env, triop->arg3, IEndianess); 4049 set_FPU_rounding_mode( env, triop->arg1, IEndianess ); 4050 addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR)); 4051 return r_dst; 4052 } 4053 } 4054 4055 if (e->tag == Iex_Binop) { 4056 PPCFpOp fpop = Pfp_INVALID; 4057 switch (e->Iex.Binop.op) { 4058 case Iop_SqrtF64: fpop = Pfp_SQRT; break; 4059 default: break; 4060 } 4061 if (fpop == Pfp_SQRT) { 4062 HReg fr_dst = newVRegF(env); 4063 HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess); 4064 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4065 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src)); 4066 return fr_dst; 4067 } 4068 } 4069 4070 if (e->tag == Iex_Binop) { 4071 4072 if (e->Iex.Binop.op == Iop_RoundF64toF32) { 4073 HReg r_dst = newVRegF(env); 4074 HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess); 4075 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4076 addInstr(env, PPCInstr_FpRSP(r_dst, r_src)); 4077 //set_FPU_rounding_default( env ); 4078 return r_dst; 4079 } 4080 4081 if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) { 4082 if (mode64) { 4083 HReg fdst = newVRegF(env); 4084 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 4085 HReg r1 = StackFramePtr(env->mode64); 4086 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 4087 4088 /* Set host rounding mode */ 4089 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4090 4091 sub_from_sp( env, 16 ); 4092 4093 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/)); 4094 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1)); 4095 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 4096 e->Iex.Binop.op == Iop_I64StoF64, 4097 True/*fdst is 64 bit*/, 4098 fdst, fdst)); 4099 4100 add_to_sp( env, 16 ); 4101 4102 ///* Restore default FPU rounding. */ 4103 //set_FPU_rounding_default( env ); 4104 return fdst; 4105 } else { 4106 /* 32-bit mode */ 4107 HReg fdst = newVRegF(env); 4108 HReg isrcHi, isrcLo; 4109 HReg r1 = StackFramePtr(env->mode64); 4110 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 ); 4111 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 ); 4112 4113 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, 4114 IEndianess); 4115 4116 /* Set host rounding mode */ 4117 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4118 4119 sub_from_sp( env, 16 ); 4120 4121 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/)); 4122 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/)); 4123 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1)); 4124 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 4125 e->Iex.Binop.op == Iop_I64StoF64, 4126 True/*fdst is 64 bit*/, 4127 fdst, fdst)); 4128 4129 add_to_sp( env, 16 ); 4130 4131 ///* Restore default FPU rounding. */ 4132 //set_FPU_rounding_default( env ); 4133 return fdst; 4134 } 4135 } 4136 4137 } 4138 4139 if (e->tag == Iex_Unop) { 4140 PPCFpOp fpop = Pfp_INVALID; 4141 switch (e->Iex.Unop.op) { 4142 case Iop_NegF64: fpop = Pfp_NEG; break; 4143 case Iop_AbsF64: fpop = Pfp_ABS; break; 4144 case Iop_RSqrtEst5GoodF64: fpop = Pfp_RSQRTE; break; 4145 case Iop_RoundF64toF64_NegINF: fpop = Pfp_FRIM; break; 4146 case Iop_RoundF64toF64_PosINF: fpop = Pfp_FRIP; break; 4147 case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break; 4148 case Iop_RoundF64toF64_ZERO: fpop = Pfp_FRIZ; break; 4149 default: break; 4150 } 4151 if (fpop != Pfp_INVALID) { 4152 HReg fr_dst = newVRegF(env); 4153 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess); 4154 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src)); 4155 return fr_dst; 4156 } 4157 } 4158 4159 if (e->tag == Iex_Unop) { 4160 switch (e->Iex.Unop.op) { 4161 case Iop_ReinterpI64asF64: { 4162 /* Given an I64, produce an IEEE754 double with the same 4163 bit pattern. */ 4164 if (!mode64) { 4165 HReg r_srcHi, r_srcLo; 4166 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, 4167 IEndianess); 4168 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo ); 4169 } else { 4170 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 4171 return mk_LoadR64toFPR( env, r_src ); 4172 } 4173 } 4174 4175 case Iop_F32toF64: { 4176 if (e->Iex.Unop.arg->tag == Iex_Unop && 4177 e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) { 4178 e = e->Iex.Unop.arg; 4179 4180 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 4181 HReg fr_dst = newVRegF(env); 4182 PPCAMode *am_addr; 4183 4184 sub_from_sp( env, 16 ); // Move SP down 16 bytes 4185 am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4186 4187 // store src as Ity_I32's 4188 addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 )); 4189 4190 // load single precision float, but the end results loads into a 4191 // 64-bit FP register -- i.e., F64. 4192 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr)); 4193 4194 add_to_sp( env, 16 ); // Reset SP 4195 return fr_dst; 4196 } 4197 4198 4199 /* this is a no-op */ 4200 HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess); 4201 return res; 4202 } 4203 default: 4204 break; 4205 } 4206 } 4207 4208 /* --------- MULTIPLEX --------- */ 4209 if (e->tag == Iex_ITE) { // VFD 4210 if (ty == Ity_F64 4211 && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) { 4212 HReg fr1 = iselDblExpr(env, e->Iex.ITE.iftrue, IEndianess); 4213 HReg fr0 = iselDblExpr(env, e->Iex.ITE.iffalse, IEndianess); 4214 HReg fr_dst = newVRegF(env); 4215 addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, fr0 )); 4216 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess); 4217 addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr1 )); 4218 return fr_dst; 4219 } 4220 } 4221 4222 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag); 4223 ppIRExpr(e); 4224 vpanic("iselDblExpr_wrk(ppc)"); 4225} 4226 4227static HReg iselDfp32Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess) 4228{ 4229 HReg r = iselDfp32Expr_wrk( env, e, IEndianess ); 4230 vassert(hregClass(r) == HRcFlt64); 4231 vassert( hregIsVirtual(r) ); 4232 return r; 4233} 4234 4235/* DO NOT CALL THIS DIRECTLY */ 4236static HReg iselDfp32Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess) 4237{ 4238 Bool mode64 = env->mode64; 4239 IRType ty = typeOfIRExpr( env->type_env, e ); 4240 4241 vassert( e ); 4242 vassert( ty == Ity_D32 ); 4243 4244 /* --------- GET --------- */ 4245 if (e->tag == Iex_Get) { 4246 HReg r_dst = newVRegF( env ); 4247 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 4248 GuestStatePtr(mode64) ); 4249 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) ); 4250 return r_dst; 4251 } 4252 4253 /* --------- LOAD --------- */ 4254 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) { 4255 PPCAMode* am_addr; 4256 HReg r_dst = newVRegF(env); 4257 vassert(e->Iex.Load.ty == Ity_D32); 4258 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D32/*xfer*/, 4259 IEndianess); 4260 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr)); 4261 return r_dst; 4262 } 4263 4264 /* --------- OPS --------- */ 4265 if (e->tag == Iex_Binop) { 4266 if (e->Iex.Binop.op == Iop_D64toD32) { 4267 HReg fr_dst = newVRegF(env); 4268 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess); 4269 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4270 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DRSP, fr_dst, fr_src)); 4271 return fr_dst; 4272 } 4273 } 4274 4275 ppIRExpr( e ); 4276 vpanic( "iselDfp32Expr_wrk(ppc)" ); 4277} 4278 4279static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess) 4280{ 4281 HReg r = iselDfp64Expr_wrk( env, e, IEndianess ); 4282 vassert(hregClass(r) == HRcFlt64); 4283 vassert( hregIsVirtual(r) ); 4284 return r; 4285} 4286 4287/* DO NOT CALL THIS DIRECTLY */ 4288static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess) 4289{ 4290 Bool mode64 = env->mode64; 4291 IRType ty = typeOfIRExpr( env->type_env, e ); 4292 HReg r_dstHi, r_dstLo; 4293 4294 vassert( e ); 4295 vassert( ty == Ity_D64 ); 4296 4297 if (e->tag == Iex_RdTmp) { 4298 return lookupIRTemp( env, e->Iex.RdTmp.tmp ); 4299 } 4300 4301 /* --------- GET --------- */ 4302 if (e->tag == Iex_Get) { 4303 HReg r_dst = newVRegF( env ); 4304 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset, 4305 GuestStatePtr(mode64) ); 4306 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) ); 4307 return r_dst; 4308 } 4309 4310 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) { 4311 PPCAMode* am_addr; 4312 HReg r_dst = newVRegF(env); 4313 vassert(e->Iex.Load.ty == Ity_D64); 4314 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D64/*xfer*/, 4315 IEndianess); 4316 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr)); 4317 return r_dst; 4318 } 4319 4320 /* --------- OPS --------- */ 4321 if (e->tag == Iex_Qop) { 4322 HReg r_dst = newVRegF( env ); 4323 return r_dst; 4324 } 4325 4326 if (e->tag == Iex_Unop) { 4327 HReg fr_dst = newVRegF(env); 4328 switch (e->Iex.Unop.op) { 4329 case Iop_ReinterpI64asD64: { 4330 /* Given an I64, produce an IEEE754 DFP with the same 4331 bit pattern. */ 4332 if (!mode64) { 4333 HReg r_srcHi, r_srcLo; 4334 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, 4335 IEndianess); 4336 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo ); 4337 } else { 4338 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 4339 return mk_LoadR64toFPR( env, r_src ); 4340 } 4341 } 4342 case Iop_D32toD64: { 4343 HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg, IEndianess); 4344 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src)); 4345 return fr_dst; 4346 } 4347 case Iop_D128HItoD64: 4348 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg, 4349 IEndianess ); 4350 return r_dstHi; 4351 case Iop_D128LOtoD64: 4352 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg, 4353 IEndianess ); 4354 return r_dstLo; 4355 case Iop_InsertExpD64: { 4356 HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess); 4357 HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess); 4358 4359 addInstr(env, PPCInstr_Dfp64Binary(Pfp_DIEX, fr_dst, fr_srcL, 4360 fr_srcR)); 4361 return fr_dst; 4362 } 4363 default: 4364 vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n", 4365 e->Iex.Unop.op ); 4366 } 4367 } 4368 4369 if (e->tag == Iex_Binop) { 4370 PPCFpOp fpop = Pfp_INVALID; 4371 HReg fr_dst = newVRegF(env); 4372 4373 switch (e->Iex.Binop.op) { 4374 case Iop_D128toD64: fpop = Pfp_DRDPQ; break; 4375 case Iop_D64toD32: fpop = Pfp_DRSP; break; 4376 case Iop_I64StoD64: fpop = Pfp_DCFFIX; break; 4377 case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break; 4378 default: break; 4379 } 4380 if (fpop == Pfp_DRDPQ) { 4381 HReg r_srcHi = newVRegF(env); 4382 HReg r_srcLo = newVRegF(env); 4383 4384 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4385 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2, 4386 IEndianess); 4387 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo)); 4388 return fr_dst; 4389 4390 } else if (fpop == Pfp_DRINTN) { 4391 HReg fr_src = newVRegF(env); 4392 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess); 4393 4394 /* NOTE, this IOP takes a DFP value and rounds to the 4395 * neares floating point integer value, i.e. fractional part 4396 * is zero. The result is a decimal floating point number. 4397 * the INT in the name is a bit misleading. 4398 */ 4399 fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess); 4400 addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc)); 4401 return fr_dst; 4402 4403 } else if (fpop == Pfp_DRSP) { 4404 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess); 4405 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4406 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src)); 4407 return fr_dst; 4408 4409 } else if (fpop == Pfp_DCFFIX) { 4410 HReg fr_src = newVRegF(env); 4411 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4412 4413 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4414 sub_from_sp( env, 16 ); 4415 4416 // put the I64 value into a floating point register 4417 if (mode64) { 4418 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 4419 4420 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/)); 4421 } else { 4422 HReg tmpHi, tmpLo; 4423 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 4424 4425 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2, 4426 IEndianess); 4427 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/)); 4428 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/)); 4429 } 4430 4431 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1)); 4432 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src)); 4433 add_to_sp( env, 16 ); 4434 return fr_dst; 4435 } 4436 4437 switch (e->Iex.Binop.op) { 4438 /* shift instructions D64, I32 -> D64 */ 4439 case Iop_ShlD64: fpop = Pfp_DSCLI; break; 4440 case Iop_ShrD64: fpop = Pfp_DSCRI; break; 4441 default: break; 4442 } 4443 if (fpop != Pfp_INVALID) { 4444 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess); 4445 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess); 4446 4447 /* shift value must be an immediate value */ 4448 vassert(shift->tag == Pri_Imm); 4449 4450 addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift)); 4451 return fr_dst; 4452 } 4453 4454 switch (e->Iex.Binop.op) { 4455 case Iop_InsertExpD64: 4456 fpop = Pfp_DIEX; 4457 break; 4458 default: break; 4459 } 4460 if (fpop != Pfp_INVALID) { 4461 HReg fr_srcL = newVRegF(env); 4462 HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess); 4463 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4464 sub_from_sp( env, 16 ); 4465 4466 if (env->mode64) { 4467 // put the I64 value into a floating point reg 4468 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 4469 4470 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/)); 4471 } else { 4472 // put the I64 register pair into a floating point reg 4473 HReg tmpHi; 4474 HReg tmpLo; 4475 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 4476 4477 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1, 4478 IEndianess); 4479 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/)); 4480 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/)); 4481 } 4482 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1)); 4483 addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL, 4484 fr_srcR)); 4485 add_to_sp( env, 16 ); 4486 return fr_dst; 4487 } 4488 } 4489 4490 if (e->tag == Iex_Triop) { 4491 IRTriop *triop = e->Iex.Triop.details; 4492 PPCFpOp fpop = Pfp_INVALID; 4493 4494 switch (triop->op) { 4495 case Iop_AddD64: 4496 fpop = Pfp_DFPADD; 4497 break; 4498 case Iop_SubD64: 4499 fpop = Pfp_DFPSUB; 4500 break; 4501 case Iop_MulD64: 4502 fpop = Pfp_DFPMUL; 4503 break; 4504 case Iop_DivD64: 4505 fpop = Pfp_DFPDIV; 4506 break; 4507 default: 4508 break; 4509 } 4510 if (fpop != Pfp_INVALID) { 4511 HReg r_dst = newVRegF( env ); 4512 HReg r_srcL = iselDfp64Expr( env, triop->arg2, IEndianess ); 4513 HReg r_srcR = iselDfp64Expr( env, triop->arg3, IEndianess ); 4514 4515 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess ); 4516 addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) ); 4517 return r_dst; 4518 } 4519 4520 switch (triop->op) { 4521 case Iop_QuantizeD64: fpop = Pfp_DQUA; break; 4522 case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break; 4523 default: break; 4524 } 4525 if (fpop == Pfp_DQUA) { 4526 HReg r_dst = newVRegF(env); 4527 HReg r_srcL = iselDfp64Expr(env, triop->arg2, IEndianess); 4528 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess); 4529 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess); 4530 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, 4531 rmc)); 4532 return r_dst; 4533 4534 } else if (fpop == Pfp_RRDTR) { 4535 HReg r_dst = newVRegF(env); 4536 HReg r_srcL = newVRegF(env); 4537 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess); 4538 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess); 4539 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4540 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess); 4541 4542 /* Move I8 to float register to issue instruction */ 4543 sub_from_sp( env, 16 ); 4544 if (mode64) 4545 addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/)); 4546 else 4547 addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/)); 4548 4549 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1)); 4550 add_to_sp( env, 16 ); 4551 4552 // will set TE and RMC when issuing instruction 4553 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc)); 4554 return r_dst; 4555 } 4556 } 4557 4558 ppIRExpr( e ); 4559 vpanic( "iselDfp64Expr_wrk(ppc)" ); 4560} 4561 4562static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e, 4563 IREndness IEndianess) 4564{ 4565 iselDfp128Expr_wrk( rHi, rLo, env, e, IEndianess ); 4566 vassert( hregIsVirtual(*rHi) ); 4567 vassert( hregIsVirtual(*rLo) ); 4568} 4569 4570/* DO NOT CALL THIS DIRECTLY */ 4571static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e, 4572 IREndness IEndianess) 4573{ 4574 vassert( e ); 4575 vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 ); 4576 4577 /* read 128-bit IRTemp */ 4578 if (e->tag == Iex_RdTmp) { 4579 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp ); 4580 return; 4581 } 4582 4583 if (e->tag == Iex_Unop) { 4584 HReg r_dstHi = newVRegF(env); 4585 HReg r_dstLo = newVRegF(env); 4586 4587 if (e->Iex.Unop.op == Iop_I64StoD128) { 4588 HReg fr_src = newVRegF(env); 4589 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4590 4591 // put the I64 value into a floating point reg 4592 if (env->mode64) { 4593 HReg tmp = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 4594 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/)); 4595 } else { 4596 HReg tmpHi, tmpLo; 4597 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 4598 4599 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, 4600 IEndianess); 4601 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/)); 4602 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/)); 4603 } 4604 4605 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1)); 4606 addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo, 4607 fr_src)); 4608 } 4609 4610 if (e->Iex.Unop.op == Iop_D64toD128) { 4611 HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess); 4612 4613 /* Source is 64bit, result is 128 bit. High 64bit source arg, 4614 * is ignored by the instruction. Set high arg to r_src just 4615 * to meet the vassert tests. 4616 */ 4617 addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo, 4618 r_src, r_src)); 4619 } 4620 *rHi = r_dstHi; 4621 *rLo = r_dstLo; 4622 return; 4623 } 4624 4625 /* --------- OPS --------- */ 4626 if (e->tag == Iex_Binop) { 4627 HReg r_srcHi; 4628 HReg r_srcLo; 4629 4630 switch (e->Iex.Binop.op) { 4631 case Iop_D64HLtoD128: 4632 r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1, IEndianess ); 4633 r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2, IEndianess ); 4634 *rHi = r_srcHi; 4635 *rLo = r_srcLo; 4636 return; 4637 break; 4638 case Iop_D128toD64: { 4639 PPCFpOp fpop = Pfp_DRDPQ; 4640 HReg fr_dst = newVRegF(env); 4641 4642 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess ); 4643 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2, 4644 IEndianess); 4645 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo)); 4646 4647 /* Need to meet the interface spec but the result is 4648 * just 64-bits so send the result back in both halfs. 4649 */ 4650 *rHi = fr_dst; 4651 *rLo = fr_dst; 4652 return; 4653 } 4654 case Iop_ShlD128: 4655 case Iop_ShrD128: { 4656 HReg fr_dst_hi = newVRegF(env); 4657 HReg fr_dst_lo = newVRegF(env); 4658 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess); 4659 PPCFpOp fpop = Pfp_DSCLIQ; /* fix later if necessary */ 4660 4661 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1, 4662 IEndianess); 4663 4664 if (e->Iex.Binop.op == Iop_ShrD128) 4665 fpop = Pfp_DSCRIQ; 4666 4667 addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo, 4668 r_srcHi, r_srcLo, shift)); 4669 4670 *rHi = fr_dst_hi; 4671 *rLo = fr_dst_lo; 4672 return; 4673 } 4674 case Iop_RoundD128toInt: { 4675 HReg r_dstHi = newVRegF(env); 4676 HReg r_dstLo = newVRegF(env); 4677 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess); 4678 4679 // will set R and RMC when issuing instruction 4680 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2, 4681 IEndianess); 4682 4683 addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo, 4684 r_srcHi, r_srcLo, r_rmc)); 4685 *rHi = r_dstHi; 4686 *rLo = r_dstLo; 4687 return; 4688 } 4689 case Iop_InsertExpD128: { 4690 HReg r_dstHi = newVRegF(env); 4691 HReg r_dstLo = newVRegF(env); 4692 HReg r_srcL = newVRegF(env); 4693 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4694 r_srcHi = newVRegF(env); 4695 r_srcLo = newVRegF(env); 4696 4697 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2, 4698 IEndianess); 4699 4700 /* Move I64 to float register to issue instruction */ 4701 if (env->mode64) { 4702 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 4703 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/)); 4704 } else { 4705 HReg tmpHi, tmpLo; 4706 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 4707 4708 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, 4709 IEndianess); 4710 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/)); 4711 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/)); 4712 } 4713 4714 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1)); 4715 addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ, 4716 r_dstHi, r_dstLo, 4717 r_srcL, r_srcHi, r_srcLo)); 4718 *rHi = r_dstHi; 4719 *rLo = r_dstLo; 4720 return; 4721 } 4722 default: 4723 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n", 4724 e->Iex.Binop.op ); 4725 break; 4726 } 4727 } 4728 4729 if (e->tag == Iex_Triop) { 4730 IRTriop *triop = e->Iex.Triop.details; 4731 PPCFpOp fpop = Pfp_INVALID; 4732 HReg r_dstHi = newVRegF(env); 4733 HReg r_dstLo = newVRegF(env); 4734 4735 switch (triop->op) { 4736 case Iop_AddD128: 4737 fpop = Pfp_DFPADDQ; 4738 break; 4739 case Iop_SubD128: 4740 fpop = Pfp_DFPSUBQ; 4741 break; 4742 case Iop_MulD128: 4743 fpop = Pfp_DFPMULQ; 4744 break; 4745 case Iop_DivD128: 4746 fpop = Pfp_DFPDIVQ; 4747 break; 4748 default: 4749 break; 4750 } 4751 4752 if (fpop != Pfp_INVALID) { 4753 HReg r_srcRHi = newVRegV( env ); 4754 HReg r_srcRLo = newVRegV( env ); 4755 4756 /* dst will be used to pass in the left operand and get the result. */ 4757 iselDfp128Expr( &r_dstHi, &r_dstLo, env, triop->arg2, IEndianess ); 4758 iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, triop->arg3, IEndianess ); 4759 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess ); 4760 addInstr( env, 4761 PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo, 4762 r_srcRHi, r_srcRLo ) ); 4763 *rHi = r_dstHi; 4764 *rLo = r_dstLo; 4765 return; 4766 } 4767 switch (triop->op) { 4768 case Iop_QuantizeD128: fpop = Pfp_DQUAQ; break; 4769 case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break; 4770 default: break; 4771 } 4772 if (fpop == Pfp_DQUAQ) { 4773 HReg r_srcHi = newVRegF(env); 4774 HReg r_srcLo = newVRegF(env); 4775 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess); 4776 4777 /* dst will be used to pass in the left operand and get the result */ 4778 iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2, IEndianess); 4779 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess); 4780 4781 // will set RMC when issuing instruction 4782 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo, 4783 r_srcHi, r_srcLo, rmc)); 4784 *rHi = r_dstHi; 4785 *rLo = r_dstLo; 4786 return; 4787 4788 } else if (fpop == Pfp_DRRNDQ) { 4789 HReg r_srcHi = newVRegF(env); 4790 HReg r_srcLo = newVRegF(env); 4791 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess); 4792 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); 4793 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); 4794 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess); 4795 HReg r_zero = newVRegI( env ); 4796 4797 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess); 4798 4799 /* dst will be used to pass in the left operand and get the result */ 4800 /* Move I8 to float register to issue instruction. Note, the 4801 * instruction only looks at the bottom 6 bits so we really don't 4802 * have to clear the upper bits since the iselWordExpr_R sets the 4803 * bottom 8-bits. 4804 */ 4805 sub_from_sp( env, 16 ); 4806 4807 if (env->mode64) 4808 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/)); 4809 else 4810 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/)); 4811 4812 /* Have to write to the upper bits to ensure they have been 4813 * initialized. The instruction ignores all but the lower 6-bits. 4814 */ 4815 addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) ); 4816 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1)); 4817 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1)); 4818 4819 add_to_sp( env, 16 ); 4820 4821 // will set RMC when issuing instruction 4822 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo, 4823 r_srcHi, r_srcLo, rmc)); 4824 *rHi = r_dstHi; 4825 *rLo = r_dstLo; 4826 return; 4827 } 4828 } 4829 4830 ppIRExpr( e ); 4831 vpanic( "iselDfp128Expr(ppc64)" ); 4832} 4833 4834 4835/*---------------------------------------------------------*/ 4836/*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/ 4837/*---------------------------------------------------------*/ 4838 4839static HReg iselVecExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 4840{ 4841 HReg r = iselVecExpr_wrk( env, e, IEndianess ); 4842# if 0 4843 vex_printf("\n"); ppIRExpr(e); vex_printf("\n"); 4844# endif 4845 vassert(hregClass(r) == HRcVec128); 4846 vassert(hregIsVirtual(r)); 4847 return r; 4848} 4849 4850/* DO NOT CALL THIS DIRECTLY */ 4851static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess ) 4852{ 4853 Bool mode64 = env->mode64; 4854 PPCAvOp op = Pav_INVALID; 4855 PPCAvFpOp fpop = Pavfp_INVALID; 4856 IRType ty = typeOfIRExpr(env->type_env,e); 4857 vassert(e); 4858 vassert(ty == Ity_V128); 4859 4860 if (e->tag == Iex_RdTmp) { 4861 return lookupIRTemp(env, e->Iex.RdTmp.tmp); 4862 } 4863 4864 if (e->tag == Iex_Get) { 4865 /* Guest state vectors are 16byte aligned, 4866 so don't need to worry here */ 4867 HReg dst = newVRegV(env); 4868 addInstr(env, 4869 PPCInstr_AvLdSt( True/*load*/, 16, dst, 4870 PPCAMode_IR( e->Iex.Get.offset, 4871 GuestStatePtr(mode64) ))); 4872 return dst; 4873 } 4874 4875 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) { 4876 /* Need to be able to do V128 unaligned loads. The BE unaligned load 4877 * can be accomplised using the following code sequece from the ISA. 4878 * It uses the lvx instruction that does two aligned loads and then 4879 * permute the data to store the required data as if it had been an 4880 * unaligned load. 4881 * 4882 * lvx Vhi,0,Rb # load MSQ, using the unaligned address in Rb 4883 * lvsl Vp, 0,Rb # Set permute control vector 4884 * addi Rb,Rb,15 # Address of LSQ 4885 * lvx Vlo,0,Rb # load LSQ 4886 * vperm Vt,Vhi,Vlo,Vp # align the data as requested 4887 */ 4888 4889 HReg Vhi = newVRegV(env); 4890 HReg Vlo = newVRegV(env); 4891 HReg Vp = newVRegV(env); 4892 HReg v_dst = newVRegV(env); 4893 HReg rB; 4894 HReg rB_plus_15 = newVRegI(env); 4895 4896 vassert(e->Iex.Load.ty == Ity_V128); 4897 rB = iselWordExpr_R( env, e->Iex.Load.addr, IEndianess ); 4898 4899 // lvx Vhi, 0, Rb 4900 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi, 4901 PPCAMode_IR(0, rB)) ); 4902 4903 if (IEndianess == Iend_LE) 4904 // lvsr Vp, 0, Rb 4905 addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp, 4906 PPCAMode_IR(0, rB)) ); 4907 else 4908 // lvsl Vp, 0, Rb 4909 addInstr(env, PPCInstr_AvSh( True/*left shift*/, Vp, 4910 PPCAMode_IR(0, rB)) ); 4911 4912 // addi Rb_plus_15, Rb, 15 4913 addInstr(env, PPCInstr_Alu( Palu_ADD, rB_plus_15, 4914 rB, PPCRH_Imm(True, toUShort(15))) ); 4915 4916 // lvx Vlo, 0, Rb_plus_15 4917 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vlo, 4918 PPCAMode_IR(0, rB_plus_15)) ); 4919 4920 if (IEndianess == Iend_LE) 4921 // vperm Vt, Vhi, Vlo, Vp 4922 addInstr(env, PPCInstr_AvPerm( v_dst, Vlo, Vhi, Vp )); 4923 else 4924 // vperm Vt, Vhi, Vlo, Vp 4925 addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp )); 4926 4927 return v_dst; 4928 } 4929 4930 if (e->tag == Iex_Unop) { 4931 switch (e->Iex.Unop.op) { 4932 4933 case Iop_NotV128: { 4934 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 4935 HReg dst = newVRegV(env); 4936 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg)); 4937 return dst; 4938 } 4939 4940 case Iop_CmpNEZ8x16: { 4941 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 4942 HReg zero = newVRegV(env); 4943 HReg dst = newVRegV(env); 4944 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 4945 addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero)); 4946 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 4947 return dst; 4948 } 4949 4950 case Iop_CmpNEZ16x8: { 4951 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 4952 HReg zero = newVRegV(env); 4953 HReg dst = newVRegV(env); 4954 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 4955 addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero)); 4956 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 4957 return dst; 4958 } 4959 4960 case Iop_CmpNEZ32x4: { 4961 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 4962 HReg zero = newVRegV(env); 4963 HReg dst = newVRegV(env); 4964 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 4965 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero)); 4966 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 4967 return dst; 4968 } 4969 4970 case Iop_CmpNEZ64x2: { 4971 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 4972 HReg zero = newVRegV(env); 4973 HReg dst = newVRegV(env); 4974 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero)); 4975 addInstr(env, PPCInstr_AvBin64x2(Pav_CMPEQU, dst, arg, zero)); 4976 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 4977 return dst; 4978 } 4979 4980 case Iop_RecipEst32Fx4: fpop = Pavfp_RCPF; goto do_32Fx4_unary; 4981 case Iop_RSqrtEst32Fx4: fpop = Pavfp_RSQRTF; goto do_32Fx4_unary; 4982 case Iop_I32UtoFx4: fpop = Pavfp_CVTU2F; goto do_32Fx4_unary; 4983 case Iop_I32StoFx4: fpop = Pavfp_CVTS2F; goto do_32Fx4_unary; 4984 case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary; 4985 case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary; 4986 case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM; goto do_32Fx4_unary; 4987 case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP; goto do_32Fx4_unary; 4988 case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN; goto do_32Fx4_unary; 4989 case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ; goto do_32Fx4_unary; 4990 do_32Fx4_unary: 4991 { 4992 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 4993 HReg dst = newVRegV(env); 4994 addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg)); 4995 return dst; 4996 } 4997 4998 case Iop_32UtoV128: { 4999 HReg r_aligned16, r_zeros; 5000 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess); 5001 HReg dst = newVRegV(env); 5002 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12; 5003 sub_from_sp( env, 32 ); // Move SP down 5004 5005 /* Get a quadword aligned address within our stack space */ 5006 r_aligned16 = get_sp_aligned16( env ); 5007 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 5008 am_off4 = PPCAMode_IR( 4, r_aligned16 ); 5009 am_off8 = PPCAMode_IR( 8, r_aligned16 ); 5010 am_off12 = PPCAMode_IR( 12, r_aligned16 ); 5011 5012 /* Store zeros */ 5013 r_zeros = newVRegI(env); 5014 addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64)); 5015 if (IEndianess == Iend_LE) 5016 addInstr(env, PPCInstr_Store( 4, am_off0, r_src, mode64 )); 5017 else 5018 addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 )); 5019 addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 )); 5020 addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 )); 5021 5022 /* Store r_src in low word of quadword-aligned mem */ 5023 if (IEndianess == Iend_LE) 5024 addInstr(env, PPCInstr_Store( 4, am_off12, r_zeros, mode64 )); 5025 else 5026 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 )); 5027 5028 /* Load word into low word of quadword vector reg */ 5029 if (IEndianess == Iend_LE) 5030 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off0 )); 5031 else 5032 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 )); 5033 5034 add_to_sp( env, 32 ); // Reset SP 5035 return dst; 5036 } 5037 5038 case Iop_Dup8x16: 5039 case Iop_Dup16x8: 5040 case Iop_Dup32x4: 5041 return mk_AvDuplicateRI(env, e->Iex.Unop.arg, IEndianess); 5042 5043 case Iop_CipherSV128: op = Pav_CIPHERSUBV128; goto do_AvCipherV128Un; 5044 do_AvCipherV128Un: { 5045 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 5046 HReg dst = newVRegV(env); 5047 addInstr(env, PPCInstr_AvCipherV128Unary(op, dst, arg)); 5048 return dst; 5049 } 5050 5051 case Iop_Clz8x16: op = Pav_ZEROCNTBYTE; goto do_zerocnt; 5052 case Iop_Clz16x8: op = Pav_ZEROCNTHALF; goto do_zerocnt; 5053 case Iop_Clz32x4: op = Pav_ZEROCNTWORD; goto do_zerocnt; 5054 case Iop_Clz64x2: op = Pav_ZEROCNTDBL; goto do_zerocnt; 5055 case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE; goto do_zerocnt; 5056 do_zerocnt: 5057 { 5058 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess); 5059 HReg dst = newVRegV(env); 5060 addInstr(env, PPCInstr_AvUnary(op, dst, arg)); 5061 return dst; 5062 } 5063 5064 default: 5065 break; 5066 } /* switch (e->Iex.Unop.op) */ 5067 } /* if (e->tag == Iex_Unop) */ 5068 5069 if (e->tag == Iex_Binop) { 5070 switch (e->Iex.Binop.op) { 5071 5072 case Iop_64HLtoV128: { 5073 if (!mode64) { 5074 HReg r3, r2, r1, r0, r_aligned16; 5075 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12; 5076 HReg dst = newVRegV(env); 5077 /* do this via the stack (easy, convenient, etc) */ 5078 sub_from_sp( env, 32 ); // Move SP down 5079 5080 // get a quadword aligned address within our stack space 5081 r_aligned16 = get_sp_aligned16( env ); 5082 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 5083 am_off4 = PPCAMode_IR( 4, r_aligned16 ); 5084 am_off8 = PPCAMode_IR( 8, r_aligned16 ); 5085 am_off12 = PPCAMode_IR( 12, r_aligned16 ); 5086 5087 /* Do the less significant 64 bits */ 5088 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2, IEndianess); 5089 addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 )); 5090 addInstr(env, PPCInstr_Store( 4, am_off8, r1, mode64 )); 5091 /* Do the more significant 64 bits */ 5092 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1, IEndianess); 5093 addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 )); 5094 addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 )); 5095 5096 /* Fetch result back from stack. */ 5097 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0)); 5098 5099 add_to_sp( env, 32 ); // Reset SP 5100 return dst; 5101 } else { 5102 HReg rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess); 5103 HReg rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess); 5104 HReg dst = newVRegV(env); 5105 HReg r_aligned16; 5106 PPCAMode *am_off0, *am_off8; 5107 /* do this via the stack (easy, convenient, etc) */ 5108 sub_from_sp( env, 32 ); // Move SP down 5109 5110 // get a quadword aligned address within our stack space 5111 r_aligned16 = get_sp_aligned16( env ); 5112 am_off0 = PPCAMode_IR( 0, r_aligned16 ); 5113 am_off8 = PPCAMode_IR( 8, r_aligned16 ); 5114 5115 /* Store 2*I64 to stack */ 5116 if (IEndianess == Iend_LE) { 5117 addInstr(env, PPCInstr_Store( 8, am_off0, rLo, mode64 )); 5118 addInstr(env, PPCInstr_Store( 8, am_off8, rHi, mode64 )); 5119 } else { 5120 addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 )); 5121 addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 )); 5122 } 5123 /* Fetch result back from stack. */ 5124 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0)); 5125 5126 add_to_sp( env, 32 ); // Reset SP 5127 return dst; 5128 } 5129 } 5130 5131 case Iop_Max32Fx4: fpop = Pavfp_MAXF; goto do_32Fx4; 5132 case Iop_Min32Fx4: fpop = Pavfp_MINF; goto do_32Fx4; 5133 case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4; 5134 case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4; 5135 case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4; 5136 do_32Fx4: 5137 { 5138 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5139 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5140 HReg dst = newVRegV(env); 5141 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR)); 5142 return dst; 5143 } 5144 5145 case Iop_CmpLE32Fx4: { 5146 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5147 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5148 HReg dst = newVRegV(env); 5149 5150 /* stay consistent with native ppc compares: 5151 if a left/right lane holds a nan, return zeros for that lane 5152 so: le == NOT(gt OR isNan) 5153 */ 5154 HReg isNanLR = newVRegV(env); 5155 HReg isNanL = isNan(env, argL, IEndianess); 5156 HReg isNanR = isNan(env, argR, IEndianess); 5157 addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR, 5158 isNanL, isNanR)); 5159 5160 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst, 5161 argL, argR)); 5162 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR)); 5163 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst)); 5164 return dst; 5165 } 5166 5167 case Iop_AndV128: op = Pav_AND; goto do_AvBin; 5168 case Iop_OrV128: op = Pav_OR; goto do_AvBin; 5169 case Iop_XorV128: op = Pav_XOR; goto do_AvBin; 5170 do_AvBin: { 5171 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5172 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5173 HReg dst = newVRegV(env); 5174 addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2)); 5175 return dst; 5176 } 5177 5178 case Iop_Shl8x16: op = Pav_SHL; goto do_AvBin8x16; 5179 case Iop_Shr8x16: op = Pav_SHR; goto do_AvBin8x16; 5180 case Iop_Sar8x16: op = Pav_SAR; goto do_AvBin8x16; 5181 case Iop_Rol8x16: op = Pav_ROTL; goto do_AvBin8x16; 5182 case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16; 5183 case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16; 5184 case Iop_Add8x16: op = Pav_ADDU; goto do_AvBin8x16; 5185 case Iop_QAdd8Ux16: op = Pav_QADDU; goto do_AvBin8x16; 5186 case Iop_QAdd8Sx16: op = Pav_QADDS; goto do_AvBin8x16; 5187 case Iop_Sub8x16: op = Pav_SUBU; goto do_AvBin8x16; 5188 case Iop_QSub8Ux16: op = Pav_QSUBU; goto do_AvBin8x16; 5189 case Iop_QSub8Sx16: op = Pav_QSUBS; goto do_AvBin8x16; 5190 case Iop_Avg8Ux16: op = Pav_AVGU; goto do_AvBin8x16; 5191 case Iop_Avg8Sx16: op = Pav_AVGS; goto do_AvBin8x16; 5192 case Iop_Max8Ux16: op = Pav_MAXU; goto do_AvBin8x16; 5193 case Iop_Max8Sx16: op = Pav_MAXS; goto do_AvBin8x16; 5194 case Iop_Min8Ux16: op = Pav_MINU; goto do_AvBin8x16; 5195 case Iop_Min8Sx16: op = Pav_MINS; goto do_AvBin8x16; 5196 case Iop_MullEven8Ux16: op = Pav_OMULU; goto do_AvBin8x16; 5197 case Iop_MullEven8Sx16: op = Pav_OMULS; goto do_AvBin8x16; 5198 case Iop_CmpEQ8x16: op = Pav_CMPEQU; goto do_AvBin8x16; 5199 case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16; 5200 case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16; 5201 case Iop_PolynomialMulAdd8x16: op = Pav_POLYMULADD; goto do_AvBin8x16; 5202 do_AvBin8x16: { 5203 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5204 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5205 HReg dst = newVRegV(env); 5206 addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2)); 5207 return dst; 5208 } 5209 5210 case Iop_Shl16x8: op = Pav_SHL; goto do_AvBin16x8; 5211 case Iop_Shr16x8: op = Pav_SHR; goto do_AvBin16x8; 5212 case Iop_Sar16x8: op = Pav_SAR; goto do_AvBin16x8; 5213 case Iop_Rol16x8: op = Pav_ROTL; goto do_AvBin16x8; 5214 case Iop_NarrowBin16to8x16: op = Pav_PACKUU; goto do_AvBin16x8; 5215 case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8; 5216 case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8; 5217 case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8; 5218 case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8; 5219 case Iop_Add16x8: op = Pav_ADDU; goto do_AvBin16x8; 5220 case Iop_QAdd16Ux8: op = Pav_QADDU; goto do_AvBin16x8; 5221 case Iop_QAdd16Sx8: op = Pav_QADDS; goto do_AvBin16x8; 5222 case Iop_Sub16x8: op = Pav_SUBU; goto do_AvBin16x8; 5223 case Iop_QSub16Ux8: op = Pav_QSUBU; goto do_AvBin16x8; 5224 case Iop_QSub16Sx8: op = Pav_QSUBS; goto do_AvBin16x8; 5225 case Iop_Avg16Ux8: op = Pav_AVGU; goto do_AvBin16x8; 5226 case Iop_Avg16Sx8: op = Pav_AVGS; goto do_AvBin16x8; 5227 case Iop_Max16Ux8: op = Pav_MAXU; goto do_AvBin16x8; 5228 case Iop_Max16Sx8: op = Pav_MAXS; goto do_AvBin16x8; 5229 case Iop_Min16Ux8: op = Pav_MINU; goto do_AvBin16x8; 5230 case Iop_Min16Sx8: op = Pav_MINS; goto do_AvBin16x8; 5231 case Iop_MullEven16Ux8: op = Pav_OMULU; goto do_AvBin16x8; 5232 case Iop_MullEven16Sx8: op = Pav_OMULS; goto do_AvBin16x8; 5233 case Iop_CmpEQ16x8: op = Pav_CMPEQU; goto do_AvBin16x8; 5234 case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8; 5235 case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8; 5236 case Iop_PolynomialMulAdd16x8: op = Pav_POLYMULADD; goto do_AvBin16x8; 5237 do_AvBin16x8: { 5238 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5239 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5240 HReg dst = newVRegV(env); 5241 addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2)); 5242 return dst; 5243 } 5244 5245 case Iop_Shl32x4: op = Pav_SHL; goto do_AvBin32x4; 5246 case Iop_Shr32x4: op = Pav_SHR; goto do_AvBin32x4; 5247 case Iop_Sar32x4: op = Pav_SAR; goto do_AvBin32x4; 5248 case Iop_Rol32x4: op = Pav_ROTL; goto do_AvBin32x4; 5249 case Iop_NarrowBin32to16x8: op = Pav_PACKUU; goto do_AvBin32x4; 5250 case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4; 5251 case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4; 5252 case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4; 5253 case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4; 5254 case Iop_Add32x4: op = Pav_ADDU; goto do_AvBin32x4; 5255 case Iop_QAdd32Ux4: op = Pav_QADDU; goto do_AvBin32x4; 5256 case Iop_QAdd32Sx4: op = Pav_QADDS; goto do_AvBin32x4; 5257 case Iop_Sub32x4: op = Pav_SUBU; goto do_AvBin32x4; 5258 case Iop_QSub32Ux4: op = Pav_QSUBU; goto do_AvBin32x4; 5259 case Iop_QSub32Sx4: op = Pav_QSUBS; goto do_AvBin32x4; 5260 case Iop_Avg32Ux4: op = Pav_AVGU; goto do_AvBin32x4; 5261 case Iop_Avg32Sx4: op = Pav_AVGS; goto do_AvBin32x4; 5262 case Iop_Max32Ux4: op = Pav_MAXU; goto do_AvBin32x4; 5263 case Iop_Max32Sx4: op = Pav_MAXS; goto do_AvBin32x4; 5264 case Iop_Min32Ux4: op = Pav_MINU; goto do_AvBin32x4; 5265 case Iop_Min32Sx4: op = Pav_MINS; goto do_AvBin32x4; 5266 case Iop_Mul32x4: op = Pav_MULU; goto do_AvBin32x4; 5267 case Iop_MullEven32Ux4: op = Pav_OMULU; goto do_AvBin32x4; 5268 case Iop_MullEven32Sx4: op = Pav_OMULS; goto do_AvBin32x4; 5269 case Iop_CmpEQ32x4: op = Pav_CMPEQU; goto do_AvBin32x4; 5270 case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4; 5271 case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4; 5272 case Iop_CatOddLanes32x4: op = Pav_CATODD; goto do_AvBin32x4; 5273 case Iop_CatEvenLanes32x4: op = Pav_CATEVEN; goto do_AvBin32x4; 5274 case Iop_PolynomialMulAdd32x4: op = Pav_POLYMULADD; goto do_AvBin32x4; 5275 do_AvBin32x4: { 5276 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5277 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5278 HReg dst = newVRegV(env); 5279 addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2)); 5280 return dst; 5281 } 5282 5283 case Iop_Shl64x2: op = Pav_SHL; goto do_AvBin64x2; 5284 case Iop_Shr64x2: op = Pav_SHR; goto do_AvBin64x2; 5285 case Iop_Sar64x2: op = Pav_SAR; goto do_AvBin64x2; 5286 case Iop_Rol64x2: op = Pav_ROTL; goto do_AvBin64x2; 5287 case Iop_NarrowBin64to32x4: op = Pav_PACKUU; goto do_AvBin64x2; 5288 case Iop_QNarrowBin64Sto32Sx4: op = Pav_QPACKSS; goto do_AvBin64x2; 5289 case Iop_QNarrowBin64Uto32Ux4: op = Pav_QPACKUU; goto do_AvBin64x2; 5290 case Iop_InterleaveHI64x2: op = Pav_MRGHI; goto do_AvBin64x2; 5291 case Iop_InterleaveLO64x2: op = Pav_MRGLO; goto do_AvBin64x2; 5292 case Iop_Add64x2: op = Pav_ADDU; goto do_AvBin64x2; 5293 case Iop_Sub64x2: op = Pav_SUBU; goto do_AvBin64x2; 5294 case Iop_Max64Ux2: op = Pav_MAXU; goto do_AvBin64x2; 5295 case Iop_Max64Sx2: op = Pav_MAXS; goto do_AvBin64x2; 5296 case Iop_Min64Ux2: op = Pav_MINU; goto do_AvBin64x2; 5297 case Iop_Min64Sx2: op = Pav_MINS; goto do_AvBin64x2; 5298 case Iop_CmpEQ64x2: op = Pav_CMPEQU; goto do_AvBin64x2; 5299 case Iop_CmpGT64Ux2: op = Pav_CMPGTU; goto do_AvBin64x2; 5300 case Iop_CmpGT64Sx2: op = Pav_CMPGTS; goto do_AvBin64x2; 5301 case Iop_PolynomialMulAdd64x2: op = Pav_POLYMULADD; goto do_AvBin64x2; 5302 do_AvBin64x2: { 5303 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5304 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5305 HReg dst = newVRegV(env); 5306 addInstr(env, PPCInstr_AvBin64x2(op, dst, arg1, arg2)); 5307 return dst; 5308 } 5309 5310 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16; 5311 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16; 5312 do_AvShift8x16: { 5313 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5314 HReg dst = newVRegV(env); 5315 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess); 5316 addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft)); 5317 return dst; 5318 } 5319 5320 case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8; 5321 case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8; 5322 case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8; 5323 do_AvShift16x8: { 5324 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5325 HReg dst = newVRegV(env); 5326 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess); 5327 addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft)); 5328 return dst; 5329 } 5330 5331 case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4; 5332 case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4; 5333 case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4; 5334 do_AvShift32x4: { 5335 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5336 HReg dst = newVRegV(env); 5337 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess); 5338 addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft)); 5339 return dst; 5340 } 5341 5342 case Iop_ShlN64x2: op = Pav_SHL; goto do_AvShift64x2; 5343 case Iop_ShrN64x2: op = Pav_SHR; goto do_AvShift64x2; 5344 case Iop_SarN64x2: op = Pav_SAR; goto do_AvShift64x2; 5345 do_AvShift64x2: { 5346 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5347 HReg dst = newVRegV(env); 5348 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess); 5349 addInstr(env, PPCInstr_AvBin64x2(op, dst, r_src, v_shft)); 5350 return dst; 5351 } 5352 5353 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128; 5354 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128; 5355 do_AvShiftV128: { 5356 HReg dst = newVRegV(env); 5357 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5358 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess); 5359 /* Note: shift value gets masked by 127 */ 5360 addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft)); 5361 return dst; 5362 } 5363 5364 case Iop_Perm8x16: { 5365 HReg dst = newVRegV(env); 5366 HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5367 HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5368 addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl)); 5369 return dst; 5370 } 5371 5372 case Iop_CipherV128: op = Pav_CIPHERV128; goto do_AvCipherV128; 5373 case Iop_CipherLV128: op = Pav_CIPHERLV128; goto do_AvCipherV128; 5374 case Iop_NCipherV128: op = Pav_NCIPHERV128; goto do_AvCipherV128; 5375 case Iop_NCipherLV128:op = Pav_NCIPHERLV128; goto do_AvCipherV128; 5376 do_AvCipherV128: { 5377 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5378 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess); 5379 HReg dst = newVRegV(env); 5380 addInstr(env, PPCInstr_AvCipherV128Binary(op, dst, arg1, arg2)); 5381 return dst; 5382 } 5383 5384 case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128; 5385 case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128; 5386 do_AvHashV128: { 5387 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess); 5388 HReg dst = newVRegV(env); 5389 PPCRI* s_field = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess); 5390 addInstr(env, PPCInstr_AvHashV128Binary(op, dst, arg1, s_field)); 5391 return dst; 5392 } 5393 default: 5394 break; 5395 } /* switch (e->Iex.Binop.op) */ 5396 } /* if (e->tag == Iex_Binop) */ 5397 5398 if (e->tag == Iex_Triop) { 5399 IRTriop *triop = e->Iex.Triop.details; 5400 switch (triop->op) { 5401 case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128; 5402 case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128; 5403 do_AvBCDV128: { 5404 HReg arg1 = iselVecExpr(env, triop->arg1, IEndianess); 5405 HReg arg2 = iselVecExpr(env, triop->arg2, IEndianess); 5406 HReg dst = newVRegV(env); 5407 PPCRI* ps = iselWordExpr_RI(env, triop->arg3, IEndianess); 5408 addInstr(env, PPCInstr_AvBCDV128Trinary(op, dst, arg1, arg2, ps)); 5409 return dst; 5410 } 5411 5412 case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4_with_rm; 5413 case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4_with_rm; 5414 case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4_with_rm; 5415 do_32Fx4_with_rm: 5416 { 5417 HReg argL = iselVecExpr(env, triop->arg2, IEndianess); 5418 HReg argR = iselVecExpr(env, triop->arg3, IEndianess); 5419 HReg dst = newVRegV(env); 5420 /* FIXME: this is bogus, in the sense that Altivec ignores 5421 FPSCR.RM, at least for some FP operations. So setting the 5422 RM is pointless. This is only really correct in the case 5423 where the RM is known, at JIT time, to be Irrm_NEAREST, 5424 since -- at least for Altivec FP add/sub/mul -- the 5425 emitted insn is hardwired to round to nearest. */ 5426 set_FPU_rounding_mode(env, triop->arg1, IEndianess); 5427 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR)); 5428 return dst; 5429 } 5430 5431 default: 5432 break; 5433 } /* switch (e->Iex.Triop.op) */ 5434 } /* if (e->tag == Iex_Trinop) */ 5435 5436 5437 if (e->tag == Iex_Const ) { 5438 vassert(e->Iex.Const.con->tag == Ico_V128); 5439 if (e->Iex.Const.con->Ico.V128 == 0x0000) { 5440 return generate_zeroes_V128(env); 5441 } 5442 else if (e->Iex.Const.con->Ico.V128 == 0xffff) { 5443 return generate_ones_V128(env); 5444 } 5445 } 5446 5447 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n", 5448 LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32, 5449 env->hwcaps)); 5450 ppIRExpr(e); 5451 vpanic("iselVecExpr_wrk(ppc)"); 5452} 5453 5454 5455/*---------------------------------------------------------*/ 5456/*--- ISEL: Statements ---*/ 5457/*---------------------------------------------------------*/ 5458 5459static void iselStmt ( ISelEnv* env, IRStmt* stmt, IREndness IEndianess ) 5460{ 5461 Bool mode64 = env->mode64; 5462 if (vex_traceflags & VEX_TRACE_VCODE) { 5463 vex_printf("\n -- "); 5464 ppIRStmt(stmt); 5465 vex_printf("\n"); 5466 } 5467 5468 switch (stmt->tag) { 5469 5470 /* --------- STORE --------- */ 5471 case Ist_Store: { 5472 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr); 5473 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data); 5474 IREndness end = stmt->Ist.Store.end; 5475 5476 if (end != IEndianess) 5477 goto stmt_fail; 5478 if (!mode64 && (tya != Ity_I32)) 5479 goto stmt_fail; 5480 if (mode64 && (tya != Ity_I64)) 5481 goto stmt_fail; 5482 5483 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 || 5484 (mode64 && (tyd == Ity_I64))) { 5485 PPCAMode* am_addr 5486 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/, 5487 IEndianess); 5488 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data, IEndianess); 5489 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)), 5490 am_addr, r_src, mode64 )); 5491 return; 5492 } 5493 if (tyd == Ity_F64) { 5494 PPCAMode* am_addr 5495 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/, 5496 IEndianess); 5497 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess); 5498 addInstr(env, 5499 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr)); 5500 return; 5501 } 5502 if (tyd == Ity_F32) { 5503 PPCAMode* am_addr 5504 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/, 5505 IEndianess); 5506 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess); 5507 addInstr(env, 5508 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr)); 5509 return; 5510 } 5511 if (tyd == Ity_D64) { 5512 PPCAMode* am_addr 5513 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/, 5514 IEndianess); 5515 HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess); 5516 addInstr(env, 5517 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr)); 5518 return; 5519 } 5520 if (tyd == Ity_D32) { 5521 PPCAMode* am_addr 5522 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/, 5523 IEndianess); 5524 HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess); 5525 addInstr(env, 5526 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr)); 5527 return; 5528 } 5529 if (tyd == Ity_V128) { 5530 PPCAMode* am_addr 5531 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/, 5532 IEndianess); 5533 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess); 5534 addInstr(env, 5535 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr)); 5536 return; 5537 } 5538 if (tyd == Ity_I64 && !mode64) { 5539 /* Just calculate the address in the register. Life is too 5540 short to arse around trying and possibly failing to adjust 5541 the offset in a 'reg+offset' style amode. */ 5542 HReg rHi32, rLo32; 5543 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess); 5544 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data, 5545 IEndianess ); 5546 addInstr(env, PPCInstr_Store( 4/*byte-store*/, 5547 PPCAMode_IR( 0, r_addr ), 5548 rHi32, 5549 False/*32-bit insn please*/) ); 5550 addInstr(env, PPCInstr_Store( 4/*byte-store*/, 5551 PPCAMode_IR( 4, r_addr ), 5552 rLo32, 5553 False/*32-bit insn please*/) ); 5554 return; 5555 } 5556 break; 5557 } 5558 5559 /* --------- PUT --------- */ 5560 case Ist_Put: { 5561 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data); 5562 if (ty == Ity_I8 || ty == Ity_I16 || 5563 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) { 5564 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data, IEndianess); 5565 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 5566 GuestStatePtr(mode64) ); 5567 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)), 5568 am_addr, r_src, mode64 )); 5569 return; 5570 } 5571 if (!mode64 && ty == Ity_I64) { 5572 HReg rHi, rLo; 5573 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 5574 GuestStatePtr(mode64) ); 5575 PPCAMode* am_addr4 = advance4(env, am_addr); 5576 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess); 5577 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 )); 5578 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 )); 5579 return; 5580 } 5581 if (ty == Ity_V128) { 5582 /* Guest state vectors are 16byte aligned, 5583 so don't need to worry here */ 5584 HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess); 5585 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 5586 GuestStatePtr(mode64) ); 5587 addInstr(env, 5588 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr)); 5589 return; 5590 } 5591 if (ty == Ity_F64) { 5592 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data, IEndianess); 5593 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 5594 GuestStatePtr(mode64) ); 5595 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8, 5596 fr_src, am_addr )); 5597 return; 5598 } 5599 if (ty == Ity_D32) { 5600 /* The 32-bit value is stored in a 64-bit register */ 5601 HReg fr_src = iselDfp32Expr( env, stmt->Ist.Put.data, IEndianess ); 5602 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 5603 GuestStatePtr(mode64) ); 5604 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, 5605 fr_src, am_addr ) ); 5606 return; 5607 } 5608 if (ty == Ity_D64) { 5609 HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data, IEndianess ); 5610 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset, 5611 GuestStatePtr(mode64) ); 5612 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) ); 5613 return; 5614 } 5615 break; 5616 } 5617 5618 /* --------- Indexed PUT --------- */ 5619 case Ist_PutI: { 5620 IRPutI *puti = stmt->Ist.PutI.details; 5621 5622 PPCAMode* dst_am 5623 = genGuestArrayOffset( 5624 env, puti->descr, 5625 puti->ix, puti->bias, 5626 IEndianess ); 5627 IRType ty = typeOfIRExpr(env->type_env, puti->data); 5628 if (mode64 && ty == Ity_I64) { 5629 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess); 5630 addInstr(env, PPCInstr_Store( toUChar(8), 5631 dst_am, r_src, mode64 )); 5632 return; 5633 } 5634 if ((!mode64) && ty == Ity_I32) { 5635 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess); 5636 addInstr(env, PPCInstr_Store( toUChar(4), 5637 dst_am, r_src, mode64 )); 5638 return; 5639 } 5640 break; 5641 } 5642 5643 /* --------- TMP --------- */ 5644 case Ist_WrTmp: { 5645 IRTemp tmp = stmt->Ist.WrTmp.tmp; 5646 IRType ty = typeOfIRTemp(env->type_env, tmp); 5647 if (ty == Ity_I8 || ty == Ity_I16 || 5648 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) { 5649 HReg r_dst = lookupIRTemp(env, tmp); 5650 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data, IEndianess); 5651 addInstr(env, mk_iMOVds_RR( r_dst, r_src )); 5652 return; 5653 } 5654 if (!mode64 && ty == Ity_I64) { 5655 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo; 5656 5657 iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data, 5658 IEndianess); 5659 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp); 5660 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) ); 5661 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) ); 5662 return; 5663 } 5664 if (mode64 && ty == Ity_I128) { 5665 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo; 5666 iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data, 5667 IEndianess); 5668 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp); 5669 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) ); 5670 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) ); 5671 return; 5672 } 5673 if (!mode64 && ty == Ity_I128) { 5674 HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo; 5675 HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo; 5676 5677 iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi, 5678 &r_srcMedLo, &r_srcLo, 5679 env, stmt->Ist.WrTmp.data, IEndianess); 5680 5681 lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo, 5682 &r_dstLo, env, tmp); 5683 5684 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) ); 5685 addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) ); 5686 addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) ); 5687 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) ); 5688 return; 5689 } 5690 if (ty == Ity_I1) { 5691 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data, 5692 IEndianess); 5693 HReg r_dst = lookupIRTemp(env, tmp); 5694 addInstr(env, PPCInstr_Set(cond, r_dst)); 5695 return; 5696 } 5697 if (ty == Ity_F64) { 5698 HReg fr_dst = lookupIRTemp(env, tmp); 5699 HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data, IEndianess); 5700 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src)); 5701 return; 5702 } 5703 if (ty == Ity_F32) { 5704 HReg fr_dst = lookupIRTemp(env, tmp); 5705 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data, IEndianess); 5706 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src)); 5707 return; 5708 } 5709 if (ty == Ity_D32) { 5710 HReg fr_dst = lookupIRTemp(env, tmp); 5711 HReg fr_src = iselDfp32Expr(env, stmt->Ist.WrTmp.data, IEndianess); 5712 addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src)); 5713 return; 5714 } 5715 if (ty == Ity_V128) { 5716 HReg v_dst = lookupIRTemp(env, tmp); 5717 HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess); 5718 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src)); 5719 return; 5720 } 5721 if (ty == Ity_D64) { 5722 HReg fr_dst = lookupIRTemp( env, tmp ); 5723 HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data, IEndianess ); 5724 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) ); 5725 return; 5726 } 5727 if (ty == Ity_D128) { 5728 HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo; 5729 // lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp ); 5730 lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp ); 5731 iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data, 5732 IEndianess ); 5733 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) ); 5734 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) ); 5735 return; 5736 } 5737 break; 5738 } 5739 5740 /* --------- Load Linked or Store Conditional --------- */ 5741 case Ist_LLSC: { 5742 IRTemp res = stmt->Ist.LLSC.result; 5743 IRType tyRes = typeOfIRTemp(env->type_env, res); 5744 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr); 5745 5746 if (stmt->Ist.LLSC.end != IEndianess) 5747 goto stmt_fail; 5748 if (!mode64 && (tyAddr != Ity_I32)) 5749 goto stmt_fail; 5750 if (mode64 && (tyAddr != Ity_I64)) 5751 goto stmt_fail; 5752 5753 if (stmt->Ist.LLSC.storedata == NULL) { 5754 /* LL */ 5755 HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr, IEndianess ); 5756 HReg r_dst = lookupIRTemp(env, res); 5757 if (tyRes == Ity_I8) { 5758 addInstr(env, PPCInstr_LoadL( 1, r_dst, r_addr, mode64 )); 5759 return; 5760 } 5761 if (tyRes == Ity_I16) { 5762 addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 )); 5763 return; 5764 } 5765 if (tyRes == Ity_I32) { 5766 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 )); 5767 return; 5768 } 5769 if (tyRes == Ity_I64 && mode64) { 5770 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 )); 5771 return; 5772 } 5773 /* fallthru */; 5774 } else { 5775 /* SC */ 5776 HReg r_res = lookupIRTemp(env, res); /* :: Ity_I1 */ 5777 HReg r_a = iselWordExpr_R(env, stmt->Ist.LLSC.addr, IEndianess); 5778 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata, 5779 IEndianess); 5780 HReg r_tmp = newVRegI(env); 5781 IRType tyData = typeOfIRExpr(env->type_env, 5782 stmt->Ist.LLSC.storedata); 5783 vassert(tyRes == Ity_I1); 5784 if (tyData == Ity_I8 || tyData == Ity_I16 || tyData == Ity_I32 || 5785 (tyData == Ity_I64 && mode64)) { 5786 int size = 0; 5787 5788 if (tyData == Ity_I64) 5789 size = 8; 5790 else if (tyData == Ity_I32) 5791 size = 4; 5792 else if (tyData == Ity_I16) 5793 size = 2; 5794 else if (tyData == Ity_I8) 5795 size = 1; 5796 5797 addInstr(env, PPCInstr_StoreC( size, 5798 r_a, r_src, mode64 )); 5799 addInstr(env, PPCInstr_MfCR( r_tmp )); 5800 addInstr(env, PPCInstr_Shft( 5801 Pshft_SHR, 5802 env->mode64 ? False : True 5803 /*F:64-bit, T:32-bit shift*/, 5804 r_tmp, r_tmp, 5805 PPCRH_Imm(False/*unsigned*/, 29))); 5806 /* Probably unnecessary, since the IR dest type is Ity_I1, 5807 and so we are entitled to leave whatever junk we like 5808 drifting round in the upper 31 or 63 bits of r_res. 5809 However, for the sake of conservativeness .. */ 5810 addInstr(env, PPCInstr_Alu( 5811 Palu_AND, 5812 r_res, r_tmp, 5813 PPCRH_Imm(False/*signed*/, 1))); 5814 return; 5815 } 5816 /* fallthru */ 5817 } 5818 goto stmt_fail; 5819 /*NOTREACHED*/ 5820 } 5821 5822 /* --------- Call to DIRTY helper --------- */ 5823 case Ist_Dirty: { 5824 IRDirty* d = stmt->Ist.Dirty.details; 5825 5826 /* Figure out the return type, if any. */ 5827 IRType retty = Ity_INVALID; 5828 if (d->tmp != IRTemp_INVALID) 5829 retty = typeOfIRTemp(env->type_env, d->tmp); 5830 5831 /* Throw out any return types we don't know about. The set of 5832 acceptable return types is the same in both 32- and 64-bit 5833 mode, so we don't need to inspect mode64 to make a 5834 decision. */ 5835 Bool retty_ok = False; 5836 switch (retty) { 5837 case Ity_INVALID: /* function doesn't return anything */ 5838 case Ity_V128: 5839 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8: 5840 retty_ok = True; break; 5841 default: 5842 break; 5843 } 5844 if (!retty_ok) 5845 break; /* will go to stmt_fail: */ 5846 5847 /* Marshal args, do the call, clear stack, set the return value 5848 to 0x555..555 if this is a conditional call that returns a 5849 value and the call is skipped. */ 5850 UInt addToSp = 0; 5851 RetLoc rloc = mk_RetLoc_INVALID(); 5852 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args, 5853 IEndianess ); 5854 vassert(is_sane_RetLoc(rloc)); 5855 5856 /* Now figure out what to do with the returned value, if any. */ 5857 switch (retty) { 5858 case Ity_INVALID: { 5859 /* No return value. Nothing to do. */ 5860 vassert(d->tmp == IRTemp_INVALID); 5861 vassert(rloc.pri == RLPri_None); 5862 vassert(addToSp == 0); 5863 return; 5864 } 5865 case Ity_I32: case Ity_I16: case Ity_I8: { 5866 /* The returned value is in %r3. Park it in the register 5867 associated with tmp. */ 5868 HReg r_dst = lookupIRTemp(env, d->tmp); 5869 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64))); 5870 vassert(rloc.pri == RLPri_Int); 5871 vassert(addToSp == 0); 5872 return; 5873 } 5874 case Ity_I64: 5875 if (mode64) { 5876 /* The returned value is in %r3. Park it in the register 5877 associated with tmp. */ 5878 HReg r_dst = lookupIRTemp(env, d->tmp); 5879 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64))); 5880 vassert(rloc.pri == RLPri_Int); 5881 vassert(addToSp == 0); 5882 } else { 5883 /* The returned value is in %r3:%r4. Park it in the 5884 register-pair associated with tmp. */ 5885 HReg r_dstHi = INVALID_HREG; 5886 HReg r_dstLo = INVALID_HREG; 5887 lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp); 5888 addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64))); 5889 addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64))); 5890 vassert(rloc.pri == RLPri_2Int); 5891 vassert(addToSp == 0); 5892 } 5893 return; 5894 case Ity_V128: { 5895 /* The returned value is on the stack, and *retloc tells 5896 us where. Fish it off the stack and then move the 5897 stack pointer upwards to clear it, as directed by 5898 doHelperCall. */ 5899 vassert(rloc.pri == RLPri_V128SpRel); 5900 vassert(addToSp >= 16); 5901 HReg dst = lookupIRTemp(env, d->tmp); 5902 PPCAMode* am = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64)); 5903 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am )); 5904 add_to_sp(env, addToSp); 5905 return; 5906 } 5907 default: 5908 /*NOTREACHED*/ 5909 vassert(0); 5910 } 5911 } 5912 5913 /* --------- MEM FENCE --------- */ 5914 case Ist_MBE: 5915 switch (stmt->Ist.MBE.event) { 5916 case Imbe_Fence: 5917 addInstr(env, PPCInstr_MFence()); 5918 return; 5919 default: 5920 break; 5921 } 5922 break; 5923 5924 /* --------- INSTR MARK --------- */ 5925 /* Doesn't generate any executable code ... */ 5926 case Ist_IMark: 5927 return; 5928 5929 /* --------- ABI HINT --------- */ 5930 /* These have no meaning (denotation in the IR) and so we ignore 5931 them ... if any actually made it this far. */ 5932 case Ist_AbiHint: 5933 return; 5934 5935 /* --------- NO-OP --------- */ 5936 /* Fairly self-explanatory, wouldn't you say? */ 5937 case Ist_NoOp: 5938 return; 5939 5940 /* --------- EXIT --------- */ 5941 case Ist_Exit: { 5942 IRConst* dst = stmt->Ist.Exit.dst; 5943 if (!mode64 && dst->tag != Ico_U32) 5944 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value"); 5945 if (mode64 && dst->tag != Ico_U64) 5946 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value"); 5947 5948 PPCCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard, IEndianess); 5949 PPCAMode* amCIA = PPCAMode_IR(stmt->Ist.Exit.offsIP, 5950 hregPPC_GPR31(mode64)); 5951 5952 /* Case: boring transfer to known address */ 5953 if (stmt->Ist.Exit.jk == Ijk_Boring 5954 || stmt->Ist.Exit.jk == Ijk_Call 5955 /* || stmt->Ist.Exit.jk == Ijk_Ret */) { 5956 if (env->chainingAllowed) { 5957 /* .. almost always true .. */ 5958 /* Skip the event check at the dst if this is a forwards 5959 edge. */ 5960 Bool toFastEP 5961 = mode64 5962 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga) 5963 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga); 5964 if (0) vex_printf("%s", toFastEP ? "Y" : ","); 5965 addInstr(env, PPCInstr_XDirect( 5966 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64 5967 : (Addr64)stmt->Ist.Exit.dst->Ico.U32, 5968 amCIA, cc, toFastEP)); 5969 } else { 5970 /* .. very occasionally .. */ 5971 /* We can't use chaining, so ask for an assisted transfer, 5972 as that's the only alternative that is allowable. */ 5973 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst), 5974 IEndianess); 5975 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring)); 5976 } 5977 return; 5978 } 5979 5980 /* Case: assisted transfer to arbitrary address */ 5981 switch (stmt->Ist.Exit.jk) { 5982 /* Keep this list in sync with that in iselNext below */ 5983 case Ijk_ClientReq: 5984 case Ijk_EmFail: 5985 case Ijk_EmWarn: 5986 case Ijk_NoDecode: 5987 case Ijk_NoRedir: 5988 case Ijk_SigBUS: 5989 case Ijk_SigTRAP: 5990 case Ijk_Sys_syscall: 5991 case Ijk_InvalICache: 5992 { 5993 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst), 5994 IEndianess); 5995 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, 5996 stmt->Ist.Exit.jk)); 5997 return; 5998 } 5999 default: 6000 break; 6001 } 6002 6003 /* Do we ever expect to see any other kind? */ 6004 goto stmt_fail; 6005 } 6006 6007 default: break; 6008 } 6009 stmt_fail: 6010 ppIRStmt(stmt); 6011 vpanic("iselStmt(ppc)"); 6012} 6013 6014 6015/*---------------------------------------------------------*/ 6016/*--- ISEL: Basic block terminators (Nexts) ---*/ 6017/*---------------------------------------------------------*/ 6018 6019static void iselNext ( ISelEnv* env, 6020 IRExpr* next, IRJumpKind jk, Int offsIP, 6021 IREndness IEndianess) 6022{ 6023 if (vex_traceflags & VEX_TRACE_VCODE) { 6024 vex_printf( "\n-- PUT(%d) = ", offsIP); 6025 ppIRExpr( next ); 6026 vex_printf( "; exit-"); 6027 ppIRJumpKind(jk); 6028 vex_printf( "\n"); 6029 } 6030 6031 PPCCondCode always = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE ); 6032 6033 /* Case: boring transfer to known address */ 6034 if (next->tag == Iex_Const) { 6035 IRConst* cdst = next->Iex.Const.con; 6036 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32)); 6037 if (jk == Ijk_Boring || jk == Ijk_Call) { 6038 /* Boring transfer to known address */ 6039 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64)); 6040 if (env->chainingAllowed) { 6041 /* .. almost always true .. */ 6042 /* Skip the event check at the dst if this is a forwards 6043 edge. */ 6044 Bool toFastEP 6045 = env->mode64 6046 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga) 6047 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga); 6048 if (0) vex_printf("%s", toFastEP ? "X" : "."); 6049 addInstr(env, PPCInstr_XDirect( 6050 env->mode64 ? (Addr64)cdst->Ico.U64 6051 : (Addr64)cdst->Ico.U32, 6052 amCIA, always, toFastEP)); 6053 } else { 6054 /* .. very occasionally .. */ 6055 /* We can't use chaining, so ask for an assisted transfer, 6056 as that's the only alternative that is allowable. */ 6057 HReg r = iselWordExpr_R(env, next, IEndianess); 6058 addInstr(env, PPCInstr_XAssisted(r, amCIA, always, 6059 Ijk_Boring)); 6060 } 6061 return; 6062 } 6063 } 6064 6065 /* Case: call/return (==boring) transfer to any address */ 6066 switch (jk) { 6067 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: { 6068 HReg r = iselWordExpr_R(env, next, IEndianess); 6069 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64)); 6070 if (env->chainingAllowed) { 6071 addInstr(env, PPCInstr_XIndir(r, amCIA, always)); 6072 } else { 6073 addInstr(env, PPCInstr_XAssisted(r, amCIA, always, 6074 Ijk_Boring)); 6075 } 6076 return; 6077 } 6078 default: 6079 break; 6080 } 6081 6082 /* Case: assisted transfer to arbitrary address */ 6083 switch (jk) { 6084 /* Keep this list in sync with that for Ist_Exit above */ 6085 case Ijk_ClientReq: 6086 case Ijk_EmFail: 6087 case Ijk_EmWarn: 6088 case Ijk_NoDecode: 6089 case Ijk_NoRedir: 6090 case Ijk_SigBUS: 6091 case Ijk_SigTRAP: 6092 case Ijk_Sys_syscall: 6093 case Ijk_InvalICache: 6094 { 6095 HReg r = iselWordExpr_R(env, next, IEndianess); 6096 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64)); 6097 addInstr(env, PPCInstr_XAssisted(r, amCIA, always, jk)); 6098 return; 6099 } 6100 default: 6101 break; 6102 } 6103 6104 vex_printf( "\n-- PUT(%d) = ", offsIP); 6105 ppIRExpr( next ); 6106 vex_printf( "; exit-"); 6107 ppIRJumpKind(jk); 6108 vex_printf( "\n"); 6109 vassert(0); // are we expecting any other kind? 6110} 6111 6112 6113/*---------------------------------------------------------*/ 6114/*--- Insn selector top-level ---*/ 6115/*---------------------------------------------------------*/ 6116 6117/* Translate an entire SB to ppc code. */ 6118HInstrArray* iselSB_PPC ( const IRSB* bb, 6119 VexArch arch_host, 6120 const VexArchInfo* archinfo_host, 6121 const VexAbiInfo* vbi, 6122 Int offs_Host_EvC_Counter, 6123 Int offs_Host_EvC_FailAddr, 6124 Bool chainingAllowed, 6125 Bool addProfInc, 6126 Addr max_ga) 6127 6128{ 6129 Int i, j; 6130 HReg hregLo, hregMedLo, hregMedHi, hregHi; 6131 ISelEnv* env; 6132 UInt hwcaps_host = archinfo_host->hwcaps; 6133 Bool mode64 = False; 6134 UInt mask32, mask64; 6135 PPCAMode *amCounter, *amFailAddr; 6136 IREndness IEndianess; 6137 6138 vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64); 6139 mode64 = arch_host == VexArchPPC64; 6140 6141 /* do some sanity checks */ 6142 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V 6143 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX 6144 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07; 6145 6146 6147 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX 6148 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP 6149 | VEX_HWCAPS_PPC64_ISA2_07; 6150 6151 if (mode64) { 6152 vassert((hwcaps_host & mask32) == 0); 6153 } else { 6154 vassert((hwcaps_host & mask64) == 0); 6155 } 6156 6157 /* Check that the host's endianness is as expected. */ 6158 vassert((archinfo_host->endness == VexEndnessBE) || 6159 (archinfo_host->endness == VexEndnessLE)); 6160 6161 if (archinfo_host->endness == VexEndnessBE) 6162 IEndianess = Iend_BE; 6163 else 6164 IEndianess = Iend_LE; 6165 6166 /* Make up an initial environment to use. */ 6167 env = LibVEX_Alloc_inline(sizeof(ISelEnv)); 6168 env->vreg_ctr = 0; 6169 6170 /* Are we being ppc32 or ppc64? */ 6171 env->mode64 = mode64; 6172 6173 /* Set up output code array. */ 6174 env->code = newHInstrArray(); 6175 6176 /* Copy BB's type env. */ 6177 env->type_env = bb->tyenv; 6178 6179 /* Make up an IRTemp -> virtual HReg mapping. This doesn't 6180 * change as we go along. 6181 * 6182 * vregmap2 and vregmap3 are only used in 32 bit mode 6183 * for supporting I128 in 32-bit mode 6184 */ 6185 env->n_vregmap = bb->tyenv->types_used; 6186 env->vregmapLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 6187 env->vregmapMedLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 6188 if (mode64) { 6189 env->vregmapMedHi = NULL; 6190 env->vregmapHi = NULL; 6191 } else { 6192 env->vregmapMedHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 6193 env->vregmapHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg)); 6194 } 6195 6196 /* and finally ... */ 6197 env->chainingAllowed = chainingAllowed; 6198 env->max_ga = max_ga; 6199 env->hwcaps = hwcaps_host; 6200 env->previous_rm = NULL; 6201 env->vbi = vbi; 6202 6203 /* For each IR temporary, allocate a suitably-kinded virtual 6204 register. */ 6205 j = 0; 6206 for (i = 0; i < env->n_vregmap; i++) { 6207 hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG; 6208 switch (bb->tyenv->types[i]) { 6209 case Ity_I1: 6210 case Ity_I8: 6211 case Ity_I16: 6212 case Ity_I32: 6213 if (mode64) { 6214 hregLo = mkHReg(True, HRcInt64, 0, j++); 6215 } else { 6216 hregLo = mkHReg(True, HRcInt32, 0, j++); 6217 } 6218 break; 6219 case Ity_I64: 6220 if (mode64) { 6221 hregLo = mkHReg(True, HRcInt64, 0, j++); 6222 } else { 6223 hregLo = mkHReg(True, HRcInt32, 0, j++); 6224 hregMedLo = mkHReg(True, HRcInt32, 0, j++); 6225 } 6226 break; 6227 case Ity_I128: 6228 if (mode64) { 6229 hregLo = mkHReg(True, HRcInt64, 0, j++); 6230 hregMedLo = mkHReg(True, HRcInt64, 0, j++); 6231 } else { 6232 hregLo = mkHReg(True, HRcInt32, 0, j++); 6233 hregMedLo = mkHReg(True, HRcInt32, 0, j++); 6234 hregMedHi = mkHReg(True, HRcInt32, 0, j++); 6235 hregHi = mkHReg(True, HRcInt32, 0, j++); 6236 } 6237 break; 6238 case Ity_F32: 6239 case Ity_F64: 6240 hregLo = mkHReg(True, HRcFlt64, 0, j++); 6241 break; 6242 case Ity_V128: 6243 hregLo = mkHReg(True, HRcVec128, 0, j++); 6244 break; 6245 case Ity_D32: 6246 case Ity_D64: 6247 hregLo = mkHReg(True, HRcFlt64, 0, j++); 6248 break; 6249 case Ity_D128: 6250 hregLo = mkHReg(True, HRcFlt64, 0, j++); 6251 hregMedLo = mkHReg(True, HRcFlt64, 0, j++); 6252 break; 6253 default: 6254 ppIRType(bb->tyenv->types[i]); 6255 vpanic("iselBB(ppc): IRTemp type"); 6256 } 6257 env->vregmapLo[i] = hregLo; 6258 env->vregmapMedLo[i] = hregMedLo; 6259 if (!mode64) { 6260 env->vregmapMedHi[i] = hregMedHi; 6261 env->vregmapHi[i] = hregHi; 6262 } 6263 } 6264 env->vreg_ctr = j; 6265 6266 /* The very first instruction must be an event check. */ 6267 amCounter = PPCAMode_IR(offs_Host_EvC_Counter, hregPPC_GPR31(mode64)); 6268 amFailAddr = PPCAMode_IR(offs_Host_EvC_FailAddr, hregPPC_GPR31(mode64)); 6269 addInstr(env, PPCInstr_EvCheck(amCounter, amFailAddr)); 6270 6271 /* Possibly a block counter increment (for profiling). At this 6272 point we don't know the address of the counter, so just pretend 6273 it is zero. It will have to be patched later, but before this 6274 translation is used, by a call to LibVEX_patchProfCtr. */ 6275 if (addProfInc) { 6276 addInstr(env, PPCInstr_ProfInc()); 6277 } 6278 6279 /* Ok, finally we can iterate over the statements. */ 6280 for (i = 0; i < bb->stmts_used; i++) 6281 iselStmt(env, bb->stmts[i], IEndianess); 6282 6283 iselNext(env, bb->next, bb->jumpkind, bb->offsIP, IEndianess); 6284 6285 /* record the number of vregs we used. */ 6286 env->code->n_vregs = env->vreg_ctr; 6287 return env->code; 6288} 6289 6290 6291/*---------------------------------------------------------------*/ 6292/*--- end host_ppc_isel.c ---*/ 6293/*---------------------------------------------------------------*/ 6294