2 /*---------------------------------------------------------------*/
3 /*--- begin host_ppc_isel.c ---*/
4 /*---------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2004-2010 OpenWorks LLP
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.
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.
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
28 The GNU General Public License is contained in the file COPYING.
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.
36 #include "libvex_basictypes.h"
37 #include "libvex_ir.h"
41 #include "main_util.h"
42 #include "main_globals.h"
43 #include "host_generic_regs.h"
44 #include "host_ppc_defs.h"
46 /* GPR register class for ppc32/64 */
47 #define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32)
50 /*---------------------------------------------------------*/
51 /*--- Register Usage Conventions ---*/
52 /*---------------------------------------------------------*/
58 GPR2 not used - TOC pointer
60 GPR11 if mode64: not used - calls by ptr / env ptr for some langs
61 GPR12 if mode64: not used - exceptions / global linkage code
62 GPR13 not used - Thread-specific pointer
64 GPR29 Unused by us (reserved for the dispatcher)
65 GPR30 AltiVec temp spill register
66 GPR31 GuestStatePointer
70 GPR3:10 Caller-saved regs
72 GPR3:12 Caller-saved regs
73 GPR14:29 Callee-saved regs
75 GPR3 [Return | Parameter] - carrying reg
76 GPR4:10 Parameter-carrying regs
83 FPR0 Caller-saved - scratch reg
85 FPR1:13 Caller-saved - param & return regs
87 FPR1:8 Caller-saved - param & return regs
88 FPR9:13 Caller-saved regs
89 FPR14:31 Callee-saved regs
92 Vector Regs (on processors with the VMX feature)
94 VR0-VR1 Volatile scratch registers
95 VR2-VR13 Volatile vector parameters registers
96 VR14-VR19 Volatile scratch registers
97 VR20-VR31 Non-volatile registers
98 VRSAVE Non-volatile 32-bit register
102 /*---------------------------------------------------------*/
103 /*--- PPC FP Status & Control Register Conventions ---*/
104 /*---------------------------------------------------------*/
106 Vex-generated code expects to run with the FPU set as follows: all
107 exceptions masked. The rounding mode is set appropriately before
108 each floating point insn emitted (or left unchanged if known to be
109 correct already). There are a few fp insns (fmr,fneg,fabs,fnabs),
110 which are unaffected by the rm and so the rounding mode is not set
113 At least on MPC7447A (Mac Mini), frsqrte is also not affected by
114 rounding mode. At some point the ppc docs get sufficiently vague
115 that the only way to find out is to write test programs.
117 /* Notes on the FP instruction set, 6 Feb 06.
119 What exns -> CR1 ? Sets FPRF ? Observes RM ?
120 -------------------------------------------------------------
129 fcfid[.] (Si64->dbl) if . y y
130 fcfidU[.] (Ui64->dbl) if . y y
131 fcfids[.] (Si64->sngl) if . Y Y
132 fcfidus[.] (Ui64->sngl) if . Y Y
133 fcmpo (cmp, result n n n
135 fctid[.] (dbl->i64) if . ->undef y
136 fctidz[.] (dbl->i64) if . ->undef rounds-to-zero
137 fctiw[.] (dbl->i32) if . ->undef y
138 fctiwz[.] (dbl->i32) if . ->undef rounds-to-zero
148 (note: for fnm*, rounding happens before final negation)
157 frsqrte[.] if . y apparently not
165 fpscr: bits 30-31 (ibm) is RM
166 24-29 (ibm) are exnmasks/non-IEEE bit, all zero
167 15-19 (ibm) is FPRF: class, <, =, >, UNord
169 ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF
172 mcrfs - move fpscr field to CR field
173 mtfsfi[.] - 4 bit imm moved to fpscr field
174 mtfsf[.] - move frS[low 1/2] to fpscr but using 8-bit field mask
175 mtfsb1[.] - set given fpscr bit
176 mtfsb0[.] - clear given fpscr bit
177 mffs[.] - move all fpscr to frD[low 1/2]
179 For [.] presumably cr1 is set with exn summary bits, as per
182 A single precision store truncates/denormalises the in-register value,
183 but does not round it. This is so that flds followed by fsts is
188 /*---------------------------------------------------------*/
189 /*--- misc helpers ---*/
190 /*---------------------------------------------------------*/
192 /* These are duplicated in guest-ppc/toIR.c */
193 static IRExpr* unop ( IROp op, IRExpr* a )
195 return IRExpr_Unop(op, a);
198 static IRExpr* mkU32 ( UInt i )
200 return IRExpr_Const(IRConst_U32(i));
203 static IRExpr* bind ( Int binder )
205 return IRExpr_Binder(binder);
209 /*---------------------------------------------------------*/
211 /*---------------------------------------------------------*/
213 /* This carries around:
215 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
216 might encounter. This is computed before insn selection starts,
219 - A mapping from IRTemp to HReg. This tells the insn selector
220 which virtual register(s) are associated with each IRTemp
221 temporary. This is computed before insn selection starts, and
222 does not change. We expect this mapping to map precisely the
223 same set of IRTemps as the type mapping does.
225 - vregmap holds the primary register for the IRTemp.
226 - vregmapHI holds the secondary register for the IRTemp,
227 if any is needed. That's only for Ity_I64 temps
228 in 32 bit mode or Ity_I128 temps in 64-bit mode.
230 - The name of the vreg in which we stash a copy of the link reg,
231 so helper functions don't kill it.
233 - The code array, that is, the insns selected so far.
235 - A counter, for generating new virtual registers.
237 - The host subarchitecture we are selecting insns for.
238 This is set at the start and does not change.
240 - A Bool to tell us if the host is 32 or 64bit.
241 This is set at the start and does not change.
243 - An IRExpr*, which may be NULL, holding the IR expression (an
244 IRRoundingMode-encoded value) to which the FPU's rounding mode
245 was most recently set. Setting to NULL is always safe. Used to
246 avoid redundant settings of the FPU's rounding mode, as
247 described in set_FPU_rounding_mode below.
249 - A VexMiscInfo*, needed for knowing how to generate
250 function calls for this target
267 /* 27 Jan 06: Not currently used, but should be */
279 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
282 vassert(tmp < env->n_vregmap);
283 return env->vregmap[tmp];
286 static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO,
287 ISelEnv* env, IRTemp tmp )
289 vassert(!env->mode64);
291 vassert(tmp < env->n_vregmap);
292 vassert(env->vregmapHI[tmp] != INVALID_HREG);
293 *vrLO = env->vregmap[tmp];
294 *vrHI = env->vregmapHI[tmp];
297 static void addInstr ( ISelEnv* env, PPCInstr* instr )
299 addHInstr(env->code, instr);
300 if (vex_traceflags & VEX_TRACE_VCODE) {
301 ppPPCInstr(instr, env->mode64);
306 static HReg newVRegI ( ISelEnv* env )
308 HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64),
309 True/*virtual reg*/);
314 static HReg newVRegF ( ISelEnv* env )
316 HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/);
321 static HReg newVRegV ( ISelEnv* env )
323 HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/);
329 /*---------------------------------------------------------*/
330 /*--- ISEL: Forward declarations ---*/
331 /*---------------------------------------------------------*/
333 /* These are organised as iselXXX and iselXXX_wrk pairs. The
334 iselXXX_wrk do the real work, but are not to be called directly.
335 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
336 checks that all returned registers are virtual. You should not
337 call the _wrk version directly.
339 'Word' refers to the size of the native machine word, that is,
340 32-bit int in 32-bit mode and 64-bit int in 64-bit mode. '2Word'
341 therefore refers to a double-width (64/128-bit) quantity in two
344 /* 32-bit mode: compute an I8/I16/I32 into a GPR.
345 64-bit mode: compute an I8/I16/I32/I64 into a GPR. */
346 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e );
347 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e );
349 /* 32-bit mode: Compute an I8/I16/I32 into a RH
350 (reg-or-halfword-immediate).
351 64-bit mode: Compute an I8/I16/I32/I64 into a RH
352 (reg-or-halfword-immediate).
353 It's important to specify whether the immediate is to be regarded
354 as signed or not. If yes, this will never return -32768 as an
355 immediate; this guaranteed that all signed immediates that are
356 return can have their sign inverted if need be.
358 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env,
359 Bool syned, IRExpr* e );
360 static PPCRH* iselWordExpr_RH ( ISelEnv* env,
361 Bool syned, IRExpr* e );
363 /* 32-bit mode: compute an I32 into a RI (reg or 32-bit immediate).
364 64-bit mode: compute an I64 into a RI (reg or 64-bit immediate). */
365 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
366 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e );
368 /* In 32 bit mode ONLY, compute an I8 into a
369 reg-or-5-bit-unsigned-immediate, the latter being an immediate in
370 the range 1 .. 31 inclusive. Used for doing shift amounts. */
371 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e );
372 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e );
374 /* In 64-bit mode ONLY, compute an I8 into a
375 reg-or-6-bit-unsigned-immediate, the latter being an immediate in
376 the range 1 .. 63 inclusive. Used for doing shift amounts. */
377 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e );
378 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e );
380 /* 32-bit mode: compute an I32 into an AMode.
381 64-bit mode: compute an I64 into an AMode.
383 Requires to know (xferTy) the type of data to be loaded/stored
384 using this amode. That is so that, for 64-bit code generation, any
385 PPCAMode_IR returned will have an index (immediate offset) field
386 that is guaranteed to be 4-aligned, if there is any chance that the
387 amode is to be used in ld/ldu/lda/std/stdu.
389 Since there are no such restrictions on 32-bit insns, xferTy is
390 ignored for 32-bit code generation. */
391 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy );
392 static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy );
394 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */
395 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
396 ISelEnv* env, IRExpr* e );
397 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
398 ISelEnv* env, IRExpr* e );
400 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
401 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
402 ISelEnv* env, IRExpr* e );
403 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
404 ISelEnv* env, IRExpr* e );
406 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
407 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e );
409 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );
410 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );
412 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );
413 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e );
415 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );
416 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e );
419 /*---------------------------------------------------------*/
420 /*--- ISEL: Misc helpers ---*/
421 /*---------------------------------------------------------*/
423 /* Make an int reg-reg move. */
425 static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src )
427 vassert(hregClass(r_dst) == hregClass(r_src));
428 vassert(hregClass(r_src) == HRcInt32 ||
429 hregClass(r_src) == HRcInt64);
430 return PPCInstr_Alu(Palu_OR, r_dst, r_src, PPCRH_Reg(r_src));
433 /* Advance/retreat %r1 by n. */
435 static void add_to_sp ( ISelEnv* env, UInt n )
437 HReg sp = StackFramePtr(env->mode64);
438 vassert(n < 256 && (n%16) == 0);
439 addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp,
440 PPCRH_Imm(True,toUShort(n)) ));
443 static void sub_from_sp ( ISelEnv* env, UInt n )
445 HReg sp = StackFramePtr(env->mode64);
446 vassert(n < 256 && (n%16) == 0);
447 addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp,
448 PPCRH_Imm(True,toUShort(n)) ));
452 returns a quadword aligned address on the stack
453 - copies SP, adds 16bytes, aligns to quadword.
454 use sub_from_sp(32) before calling this,
455 as expects to have 32 bytes to play with.
457 static HReg get_sp_aligned16 ( ISelEnv* env )
459 HReg r = newVRegI(env);
460 HReg align16 = newVRegI(env);
461 addInstr(env, mk_iMOVds_RR(r, StackFramePtr(env->mode64)));
463 addInstr(env, PPCInstr_Alu( Palu_ADD, r, r,
464 PPCRH_Imm(True,toUShort(16)) ));
467 PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64));
468 addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16)));
474 /* Load 2*I32 regs to fp reg */
475 static HReg mk_LoadRR32toFPR ( ISelEnv* env,
476 HReg r_srcHi, HReg r_srcLo )
478 HReg fr_dst = newVRegF(env);
479 PPCAMode *am_addr0, *am_addr1;
481 vassert(!env->mode64);
482 vassert(hregClass(r_srcHi) == HRcInt32);
483 vassert(hregClass(r_srcLo) == HRcInt32);
485 sub_from_sp( env, 16 ); // Move SP down 16 bytes
486 am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
487 am_addr1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
489 // store hi,lo as Ity_I32's
490 addInstr(env, PPCInstr_Store( 4, am_addr0, r_srcHi, env->mode64 ));
491 addInstr(env, PPCInstr_Store( 4, am_addr1, r_srcLo, env->mode64 ));
494 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
496 add_to_sp( env, 16 ); // Reset SP
500 /* Load I64 reg to fp reg */
501 static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src )
503 HReg fr_dst = newVRegF(env);
506 vassert(env->mode64);
507 vassert(hregClass(r_src) == HRcInt64);
509 sub_from_sp( env, 16 ); // Move SP down 16 bytes
510 am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
513 addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 ));
516 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
518 add_to_sp( env, 16 ); // Reset SP
523 /* Given an amode, return one which references 4 bytes further
526 static PPCAMode* advance4 ( ISelEnv* env, PPCAMode* am )
528 PPCAMode* am4 = dopyPPCAMode( am );
529 if (am4->tag == Pam_IR
530 && am4->Pam.IR.index + 4 <= 32767) {
531 am4->Pam.IR.index += 4;
533 vpanic("advance4(ppc,host)");
539 /* Given a guest-state array descriptor, an index expression and a
540 bias, generate a PPCAMode pointing at the relevant piece of
543 PPCAMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
544 IRExpr* off, Int bias )
547 Int elemSz = sizeofIRType(descr->elemTy);
548 Int nElems = descr->nElems;
551 /* Throw out any cases we don't need. In theory there might be a
552 day where we need to handle others, but not today. */
554 if (nElems != 16 && nElems != 32)
555 vpanic("genGuestArrayOffset(ppc host)(1)");
558 case 4: shift = 2; break;
559 case 8: shift = 3; break;
560 default: vpanic("genGuestArrayOffset(ppc host)(2)");
563 if (bias < -100 || bias > 100) /* somewhat arbitrarily */
564 vpanic("genGuestArrayOffset(ppc host)(3)");
565 if (descr->base < 0 || descr->base > 5000) /* somewhat arbitrarily */
566 vpanic("genGuestArrayOffset(ppc host)(4)");
568 /* Compute off into a reg, %off. Then return:
570 addi %tmp, %off, bias (if bias != 0)
573 addi %tmp, %tmp, base
574 ... Baseblockptr + %tmp ...
576 roff = iselWordExpr_R(env, off);
577 rtmp = newVRegI(env);
578 addInstr(env, PPCInstr_Alu(
581 PPCRH_Imm(True/*signed*/, toUShort(bias))));
582 addInstr(env, PPCInstr_Alu(
585 PPCRH_Imm(False/*unsigned*/, toUShort(nElems-1))));
586 addInstr(env, PPCInstr_Shft(
588 env->mode64 ? False : True/*F:64-bit, T:32-bit shift*/,
590 PPCRH_Imm(False/*unsigned*/, toUShort(shift))));
591 addInstr(env, PPCInstr_Alu(
594 PPCRH_Imm(True/*signed*/, toUShort(descr->base))));
596 PPCAMode_RR( GuestStatePtr(env->mode64), rtmp );
600 /*---------------------------------------------------------*/
601 /*--- ISEL: Function call helpers ---*/
602 /*---------------------------------------------------------*/
604 /* Used only in doHelperCall. See big comment in doHelperCall re
605 handling of register-parameter args. This function figures out
606 whether evaluation of an expression might require use of a fixed
607 register. If in doubt return True (safe but suboptimal).
610 Bool mightRequireFixedRegs ( IRExpr* e )
613 case Iex_RdTmp: case Iex_Const: case Iex_Get:
621 /* Do a complete function call. guard is a Ity_Bit expression
622 indicating whether or not the call happens. If guard==NULL, the
623 call is unconditional. */
626 void doHelperCall ( ISelEnv* env,
628 IRExpr* guard, IRCallee* cee, IRExpr** args )
631 HReg argregs[PPC_N_REGPARMS];
632 HReg tmpregs[PPC_N_REGPARMS];
634 Int n_args, i, argreg;
637 Bool mode64 = env->mode64;
639 /* Do we need to force use of an odd-even reg pair for 64-bit
642 = (!mode64) && env->vbi->host_ppc32_regalign_int64_args;
644 /* Marshal args for a call and do the call.
646 If passBBP is True, %rbp (the baseblock pointer) is to be passed
649 This function only deals with a tiny set of possibilities, which
650 cover all helpers in practice. The restrictions are that only
651 arguments in registers are supported, hence only PPC_N_REGPARMS x
652 (mode32:32 | mode64:64) integer bits in total can be passed.
653 In fact the only supported arg type is (mode32:I32 | mode64:I64).
655 Generating code which is both efficient and correct when
656 parameters are to be passed in registers is difficult, for the
657 reasons elaborated in detail in comments attached to
658 doHelperCall() in priv/host-x86/isel.c. Here, we use a variant
659 of the method described in those comments.
661 The problem is split into two cases: the fast scheme and the
662 slow scheme. In the fast scheme, arguments are computed
663 directly into the target (real) registers. This is only safe
664 when we can be sure that computation of each argument will not
665 trash any real registers set by computation of any other
668 In the slow scheme, all args are first computed into vregs, and
669 once they are all done, they are moved to the relevant real
670 regs. This always gives correct code, but it also gives a bunch
671 of vreg-to-rreg moves which are usually redundant but are hard
672 for the register allocator to get rid of.
674 To decide which scheme to use, all argument expressions are
675 first examined. If they are all so simple that it is clear they
676 will be evaluated without use of any fixed registers, use the
677 fast scheme, else use the slow scheme. Note also that only
678 unconditional calls may use the fast scheme, since having to
679 compute a condition expression could itself trash real
682 Note this requires being able to examine an expression and
683 determine whether or not evaluation of it might use a fixed
684 register. That requires knowledge of how the rest of this insn
685 selector works. Currently just the following 3 are regarded as
686 safe -- hopefully they cover the majority of arguments in
687 practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
690 /* Note that the cee->regparms field is meaningless on PPC32/64 host
691 (since there is only one calling convention) and so we always
695 for (i = 0; args[i]; i++)
698 if (PPC_N_REGPARMS < n_args + (passBBP ? 1 : 0)) {
699 vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
703 argregs[0] = hregPPC_GPR3(mode64);
704 argregs[1] = hregPPC_GPR4(mode64);
705 argregs[2] = hregPPC_GPR5(mode64);
706 argregs[3] = hregPPC_GPR6(mode64);
707 argregs[4] = hregPPC_GPR7(mode64);
708 argregs[5] = hregPPC_GPR8(mode64);
709 argregs[6] = hregPPC_GPR9(mode64);
710 argregs[7] = hregPPC_GPR10(mode64);
713 tmpregs[0] = tmpregs[1] = tmpregs[2] =
714 tmpregs[3] = tmpregs[4] = tmpregs[5] =
715 tmpregs[6] = tmpregs[7] = INVALID_HREG;
717 /* First decide which scheme (slow or fast) is to be used. First
718 assume the fast scheme, and select slow if any contraindications
724 if (guard->tag == Iex_Const
725 && guard->Iex.Const.con->tag == Ico_U1
726 && guard->Iex.Const.con->Ico.U1 == True) {
729 /* Not manifestly unconditional -- be conservative. */
735 for (i = 0; i < n_args; i++) {
736 if (mightRequireFixedRegs(args[i])) {
743 /* At this point the scheme to use has been established. Generate
744 code to get the arg values into the argument rregs. */
751 argiregs |= (1 << (argreg+3));
752 addInstr(env, mk_iMOVds_RR( argregs[argreg],
753 GuestStatePtr(mode64) ));
757 for (i = 0; i < n_args; i++) {
758 vassert(argreg < PPC_N_REGPARMS);
759 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
760 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
762 if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
763 argiregs |= (1 << (argreg+3));
765 mk_iMOVds_RR( argregs[argreg],
766 iselWordExpr_R(env, args[i]) ));
769 if (regalign_int64s && (argreg%2) == 1)
770 // ppc32 ELF abi spec for passing LONG_LONG
771 argreg++; // XXX: odd argreg => even rN
772 vassert(argreg < PPC_N_REGPARMS-1);
773 iselInt64Expr(&rHi,&rLo, env, args[i]);
774 argiregs |= (1 << (argreg+3));
775 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
776 argiregs |= (1 << (argreg+3));
777 addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
780 argiregs |= (1 << (argreg+3));
781 addInstr(env, mk_iMOVds_RR( argregs[argreg],
782 iselWordExpr_R(env, args[i]) ));
787 /* Fast scheme only applies for unconditional calls. Hence: */
788 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
792 /* SLOW SCHEME; move via temporaries */
796 /* This is pretty stupid; better to move directly to r3
797 after the rest of the args are done. */
798 tmpregs[argreg] = newVRegI(env);
799 addInstr(env, mk_iMOVds_RR( tmpregs[argreg],
800 GuestStatePtr(mode64) ));
804 for (i = 0; i < n_args; i++) {
805 vassert(argreg < PPC_N_REGPARMS);
806 vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
807 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
809 if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
810 tmpregs[argreg] = iselWordExpr_R(env, args[i]);
813 if (regalign_int64s && (argreg%2) == 1)
814 // ppc32 ELF abi spec for passing LONG_LONG
815 argreg++; // XXX: odd argreg => even rN
816 vassert(argreg < PPC_N_REGPARMS-1);
817 iselInt64Expr(&rHi,&rLo, env, args[i]);
818 tmpregs[argreg++] = rHi;
819 tmpregs[argreg] = rLo;
822 tmpregs[argreg] = iselWordExpr_R(env, args[i]);
827 /* Now we can compute the condition. We can't do it earlier
828 because the argument computations could trash the condition
829 codes. Be a bit clever to handle the common case where the
831 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
833 if (guard->tag == Iex_Const
834 && guard->Iex.Const.con->tag == Ico_U1
835 && guard->Iex.Const.con->Ico.U1 == True) {
836 /* unconditional -- do nothing */
838 cc = iselCondCode( env, guard );
842 /* Move the args to their final destinations. */
843 for (i = 0; i < argreg; i++) {
844 if (tmpregs[i] == INVALID_HREG) // Skip invalid regs
846 /* None of these insns, including any spill code that might
847 be generated, may alter the condition codes. */
848 argiregs |= (1 << (i+3));
849 addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
854 target = mode64 ? Ptr_to_ULong(cee->addr) :
855 toUInt(Ptr_to_ULong(cee->addr));
857 /* Finally, the call itself. */
858 addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs ));
862 /*---------------------------------------------------------*/
863 /*--- ISEL: FP rounding mode helpers ---*/
864 /*---------------------------------------------------------*/
866 ///* Set FPU's rounding mode to the default */
868 //void set_FPU_rounding_default ( ISelEnv* env )
870 // HReg fr_src = newVRegF(env);
871 // HReg r_src = newVRegI(env);
873 // /* Default rounding mode = 0x0
874 // Only supporting the rounding-mode bits - the rest of FPSCR is 0x0
875 // - so we can set the whole register at once (faster)
876 // note: upper 32 bits ignored by FpLdFPSCR
878 // addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64));
879 // if (env->mode64) {
880 // fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
882 // fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
884 // addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
887 /* Convert IR rounding mode to PPC encoding */
888 static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
891 rounding mode | PPC | IR
892 ------------------------
895 to +infinity | 10 | 10
896 to -infinity | 11 | 01
898 HReg r_rmPPC = newVRegI(env);
899 HReg r_tmp1 = newVRegI(env);
901 vassert(hregClass(r_rmIR) == HRcGPR(env->mode64));
903 // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3
905 // slwi tmp1, r_rmIR, 1
906 // xor tmp1, r_rmIR, tmp1
907 // andi r_rmPPC, tmp1, 3
909 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
910 r_tmp1, r_rmIR, PPCRH_Imm(False,1)));
912 addInstr(env, PPCInstr_Alu( Palu_XOR, r_tmp1, r_rmIR,
913 PPCRH_Reg(r_tmp1) ));
915 addInstr(env, PPCInstr_Alu( Palu_AND, r_rmPPC, r_tmp1,
916 PPCRH_Imm(False,3) ));
922 /* Set the FPU's rounding mode: 'mode' is an I32-typed expression
923 denoting a value in the range 0 .. 3, indicating a round mode
924 encoded as per type IRRoundingMode. Set the PPC FPSCR to have the
927 For speed & simplicity, we're setting the *entire* FPSCR here.
929 Setting the rounding mode is expensive. So this function tries to
930 avoid repeatedly setting the rounding mode to the same thing by
931 first comparing 'mode' to the 'mode' tree supplied in the previous
932 call to this function, if any. (The previous value is stored in
933 env->previous_rm.) If 'mode' is a single IR temporary 't' and
934 env->previous_rm is also just 't', then the setting is skipped.
936 This is safe because of the SSA property of IR: an IR temporary can
937 only be defined once and so will have the same value regardless of
938 where it appears in the block. Cool stuff, SSA.
940 A safety condition: all attempts to set the RM must be aware of
941 this mechanism - by being routed through the functions here.
943 Of course this only helps if blocks where the RM is set more than
944 once and it is set to the same value each time, *and* that value is
945 held in the same IR temporary each time. In order to assure the
946 latter as much as possible, the IR optimiser takes care to do CSE
947 on any block with any sign of floating point activity.
950 void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
952 HReg fr_src = newVRegF(env);
955 vassert(typeOfIRExpr(env->type_env,mode) == Ity_I32);
957 /* Do we need to do anything? */
959 && env->previous_rm->tag == Iex_RdTmp
960 && mode->tag == Iex_RdTmp
961 && env->previous_rm->Iex.RdTmp.tmp == mode->Iex.RdTmp.tmp) {
962 /* no - setting it to what it was before. */
963 vassert(typeOfIRExpr(env->type_env, env->previous_rm) == Ity_I32);
967 /* No luck - we better set it, and remember what we set it to. */
968 env->previous_rm = mode;
970 /* Only supporting the rounding-mode bits - the rest of FPSCR is
971 0x0 - so we can set the whole register at once (faster). */
973 // Resolve rounding mode and convert to PPC representation
974 r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode) );
977 fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
979 fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
983 addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
987 /*---------------------------------------------------------*/
988 /*--- ISEL: vector helpers ---*/
989 /*---------------------------------------------------------*/
991 /* Generate all-zeroes into a new vector register.
993 static HReg generate_zeroes_V128 ( ISelEnv* env )
995 HReg dst = newVRegV(env);
996 addInstr(env, PPCInstr_AvBinary(Pav_XOR, dst, dst, dst));
1000 /* Generate all-ones into a new vector register.
1002 static HReg generate_ones_V128 ( ISelEnv* env )
1004 HReg dst = newVRegV(env);
1005 PPCVI5s * src = PPCVI5s_Imm(-1);
1006 addInstr(env, PPCInstr_AvSplat(8, dst, src));
1012 Generates code for AvSplat
1013 - takes in IRExpr* of type 8|16|32
1014 returns vector reg of duplicated lanes of input
1015 - uses AvSplat(imm) for imms up to simm6.
1016 otherwise must use store reg & load vector
1018 static HReg mk_AvDuplicateRI( ISelEnv* env, IRExpr* e )
1021 HReg dst = newVRegV(env);
1022 PPCRI* ri = iselWordExpr_RI(env, e);
1023 IRType ty = typeOfIRExpr(env->type_env,e);
1024 UInt sz = (ty == Ity_I8) ? 8 : (ty == Ity_I16) ? 16 : 32;
1025 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1027 /* special case: immediate */
1028 if (ri->tag == Pri_Imm) {
1029 Int simm32 = (Int)ri->Pri.Imm;
1031 /* figure out if it's do-able with imm splats. */
1032 if (simm32 >= -32 && simm32 <= 31) {
1033 Char simm6 = (Char)simm32;
1034 if (simm6 > 15) { /* 16:31 inclusive */
1035 HReg v1 = newVRegV(env);
1036 HReg v2 = newVRegV(env);
1037 addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1038 addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6-16)));
1040 (sz== 8) ? PPCInstr_AvBin8x16(Pav_SUBU, dst, v2, v1) :
1041 (sz==16) ? PPCInstr_AvBin16x8(Pav_SUBU, dst, v2, v1)
1042 : PPCInstr_AvBin32x4(Pav_SUBU, dst, v2, v1) );
1045 if (simm6 < -16) { /* -32:-17 inclusive */
1046 HReg v1 = newVRegV(env);
1047 HReg v2 = newVRegV(env);
1048 addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1049 addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6+16)));
1051 (sz== 8) ? PPCInstr_AvBin8x16(Pav_ADDU, dst, v2, v1) :
1052 (sz==16) ? PPCInstr_AvBin16x8(Pav_ADDU, dst, v2, v1)
1053 : PPCInstr_AvBin32x4(Pav_ADDU, dst, v2, v1) );
1056 /* simplest form: -16:15 inclusive */
1057 addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6)));
1061 /* no luck; use the Slow way. */
1062 r_src = newVRegI(env);
1063 addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64));
1066 r_src = ri->Pri.Reg;
1069 /* default case: store r_src in lowest lane of 16-aligned mem,
1070 load vector, splat lowest lane to dst */
1072 /* CAB: Maybe faster to store r_src multiple times (sz dependent),
1073 and simply load the vector? */
1075 HReg v_src = newVRegV(env);
1078 sub_from_sp( env, 32 ); // Move SP down
1079 /* Get a 16-aligned address within our stack space */
1080 r_aligned16 = get_sp_aligned16( env );
1081 am_off12 = PPCAMode_IR( 12, r_aligned16 );
1083 /* Store r_src in low word of 16-aligned mem */
1084 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, env->mode64 ));
1086 /* Load src to vector[low lane] */
1087 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, v_src, am_off12 ) );
1088 add_to_sp( env, 32 ); // Reset SP
1090 /* Finally, splat v_src[low_lane] to dst */
1091 addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Reg(v_src)));
1097 /* for each lane of vSrc: lane == nan ? laneX = all 1's : all 0's */
1098 static HReg isNan ( ISelEnv* env, HReg vSrc )
1100 HReg zeros, msk_exp, msk_mnt, expt, mnts, vIsNan;
1102 vassert(hregClass(vSrc) == HRcVec128);
1104 zeros = mk_AvDuplicateRI(env, mkU32(0));
1105 msk_exp = mk_AvDuplicateRI(env, mkU32(0x7F800000));
1106 msk_mnt = mk_AvDuplicateRI(env, mkU32(0x7FFFFF));
1107 expt = newVRegV(env);
1108 mnts = newVRegV(env);
1109 vIsNan = newVRegV(env);
1111 /* 32bit float => sign(1) | exponent(8) | mantissa(23)
1112 nan => exponent all ones, mantissa > 0 */
1114 addInstr(env, PPCInstr_AvBinary(Pav_AND, expt, vSrc, msk_exp));
1115 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, expt, expt, msk_exp));
1116 addInstr(env, PPCInstr_AvBinary(Pav_AND, mnts, vSrc, msk_mnt));
1117 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPGTU, mnts, mnts, zeros));
1118 addInstr(env, PPCInstr_AvBinary(Pav_AND, vIsNan, expt, mnts));
1123 /*---------------------------------------------------------*/
1124 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1125 /*---------------------------------------------------------*/
1127 /* Select insns for an integer-typed expression, and add them to the
1128 code list. Return a reg holding the result. This reg will be a
1129 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1130 want to modify it, ask for a new vreg, copy it in there, and modify
1131 the copy. The register allocator will do its best to map both
1132 vregs to the same real register, so the copies will often disappear
1135 This should handle expressions of 64, 32, 16 and 8-bit type.
1136 All results are returned in a (mode64 ? 64bit : 32bit) register.
1137 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1138 are arbitrary, so you should mask or sign extend partial values
1142 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e )
1144 HReg r = iselWordExpr_R_wrk(env, e);
1145 /* sanity checks ... */
1147 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1150 vassert(hregClass(r) == HRcGPR(env->mode64));
1151 vassert(hregIsVirtual(r));
1155 /* DO NOT CALL THIS DIRECTLY ! */
1156 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
1158 Bool mode64 = env->mode64;
1160 DECLARE_PATTERN(p_32to1_then_1Uto8);
1162 IRType ty = typeOfIRExpr(env->type_env,e);
1163 vassert(ty == Ity_I8 || ty == Ity_I16 ||
1164 ty == Ity_I32 || ((ty == Ity_I64) && mode64));
1168 /* --------- TEMP --------- */
1170 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1172 /* --------- LOAD --------- */
1176 if (e->Iex.Load.end != Iend_BE)
1178 r_dst = newVRegI(env);
1179 am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/ );
1180 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1181 r_dst, am_addr, mode64 ));
1186 /* --------- BINARY OP --------- */
1191 /* Is it an addition or logical style op? */
1192 switch (e->Iex.Binop.op) {
1193 case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64:
1194 aluOp = Palu_ADD; break;
1195 case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64:
1196 aluOp = Palu_SUB; break;
1197 case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64:
1198 aluOp = Palu_AND; break;
1199 case Iop_Or8: case Iop_Or16: case Iop_Or32: case Iop_Or64:
1200 aluOp = Palu_OR; break;
1201 case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: case Iop_Xor64:
1202 aluOp = Palu_XOR; break;
1204 aluOp = Palu_INVALID; break;
1206 /* For commutative ops we assume any literal
1207 values are on the second operand. */
1208 if (aluOp != Palu_INVALID) {
1209 HReg r_dst = newVRegI(env);
1210 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1211 PPCRH* ri_srcR = NULL;
1212 /* get right arg into an RH, in the appropriate way */
1214 case Palu_ADD: case Palu_SUB:
1215 ri_srcR = iselWordExpr_RH(env, True/*signed*/,
1218 case Palu_AND: case Palu_OR: case Palu_XOR:
1219 ri_srcR = iselWordExpr_RH(env, False/*signed*/,
1223 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
1225 addInstr(env, PPCInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
1230 switch (e->Iex.Binop.op) {
1231 case Iop_Shl8: case Iop_Shl16: case Iop_Shl32: case Iop_Shl64:
1232 shftOp = Pshft_SHL; break;
1233 case Iop_Shr8: case Iop_Shr16: case Iop_Shr32: case Iop_Shr64:
1234 shftOp = Pshft_SHR; break;
1235 case Iop_Sar8: case Iop_Sar16: case Iop_Sar32: case Iop_Sar64:
1236 shftOp = Pshft_SAR; break;
1238 shftOp = Pshft_INVALID; break;
1240 /* we assume any literal values are on the second operand. */
1241 if (shftOp != Pshft_INVALID) {
1242 HReg r_dst = newVRegI(env);
1243 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1244 PPCRH* ri_srcR = NULL;
1245 /* get right arg into an RH, in the appropriate way */
1247 case Pshft_SHL: case Pshft_SHR: case Pshft_SAR:
1249 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2);
1251 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
1254 vpanic("iselIntExpr_R_wrk-shftOp-arg2");
1256 /* widen the left arg if needed */
1257 if (shftOp == Pshft_SHR || shftOp == Pshft_SAR) {
1258 if (ty == Ity_I8 || ty == Ity_I16) {
1259 PPCRH* amt = PPCRH_Imm(False,
1260 toUShort(ty == Ity_I8 ? 24 : 16));
1261 HReg tmp = newVRegI(env);
1262 addInstr(env, PPCInstr_Shft(Pshft_SHL,
1263 True/*32bit shift*/,
1265 addInstr(env, PPCInstr_Shft(shftOp,
1266 True/*32bit shift*/,
1269 vassert(0); /* AWAITING TEST CASE */
1272 /* Only 64 expressions need 64bit shifts,
1273 32bit shifts are fine for all others */
1274 if (ty == Ity_I64) {
1276 addInstr(env, PPCInstr_Shft(shftOp, False/*64bit shift*/,
1277 r_dst, r_srcL, ri_srcR));
1279 addInstr(env, PPCInstr_Shft(shftOp, True/*32bit shift*/,
1280 r_dst, r_srcL, ri_srcR));
1285 /* How about a div? */
1286 if (e->Iex.Binop.op == Iop_DivS32 ||
1287 e->Iex.Binop.op == Iop_DivU32) {
1288 Bool syned = toBool(e->Iex.Binop.op == Iop_DivS32);
1289 HReg r_dst = newVRegI(env);
1290 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1291 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1292 addInstr(env, PPCInstr_Div(syned, True/*32bit div*/,
1293 r_dst, r_srcL, r_srcR));
1296 if (e->Iex.Binop.op == Iop_DivS64 ||
1297 e->Iex.Binop.op == Iop_DivU64) {
1298 Bool syned = toBool(e->Iex.Binop.op == Iop_DivS64);
1299 HReg r_dst = newVRegI(env);
1300 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1301 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1303 addInstr(env, PPCInstr_Div(syned, False/*64bit div*/,
1304 r_dst, r_srcL, r_srcR));
1308 /* No? Anyone for a mul? */
1309 if (e->Iex.Binop.op == Iop_Mul32
1310 || e->Iex.Binop.op == Iop_Mul64) {
1312 Bool sz32 = (e->Iex.Binop.op != Iop_Mul64);
1313 HReg r_dst = newVRegI(env);
1314 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1315 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1316 addInstr(env, PPCInstr_MulL(syned, False/*lo32*/, sz32,
1317 r_dst, r_srcL, r_srcR));
1321 /* 32 x 32 -> 64 multiply */
1323 && (e->Iex.Binop.op == Iop_MullU32
1324 || e->Iex.Binop.op == Iop_MullS32)) {
1325 HReg tLo = newVRegI(env);
1326 HReg tHi = newVRegI(env);
1327 HReg r_dst = newVRegI(env);
1328 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
1329 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1330 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1331 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
1332 False/*lo32*/, True/*32bit mul*/,
1333 tLo, r_srcL, r_srcR));
1334 addInstr(env, PPCInstr_MulL(syned,
1335 True/*hi32*/, True/*32bit mul*/,
1336 tHi, r_srcL, r_srcR));
1337 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1338 r_dst, tHi, PPCRH_Imm(False,32)));
1339 addInstr(env, PPCInstr_Alu(Palu_OR,
1340 r_dst, r_dst, PPCRH_Reg(tLo)));
1344 /* El-mutanto 3-way compare? */
1345 if (e->Iex.Binop.op == Iop_CmpORD32S
1346 || e->Iex.Binop.op == Iop_CmpORD32U) {
1347 Bool syned = toBool(e->Iex.Binop.op == Iop_CmpORD32S);
1348 HReg dst = newVRegI(env);
1349 HReg srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1350 PPCRH* srcR = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
1351 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
1352 7/*cr*/, srcL, srcR));
1353 addInstr(env, PPCInstr_MfCR(dst));
1354 addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1355 PPCRH_Imm(False,7<<1)));
1359 if (e->Iex.Binop.op == Iop_CmpORD64S
1360 || e->Iex.Binop.op == Iop_CmpORD64U) {
1361 Bool syned = toBool(e->Iex.Binop.op == Iop_CmpORD64S);
1362 HReg dst = newVRegI(env);
1363 HReg srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1364 PPCRH* srcR = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
1366 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
1367 7/*cr*/, srcL, srcR));
1368 addInstr(env, PPCInstr_MfCR(dst));
1369 addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1370 PPCRH_Imm(False,7<<1)));
1374 if (e->Iex.Binop.op == Iop_Max32U) {
1375 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
1376 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
1377 HReg rdst = newVRegI(env);
1378 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
1379 addInstr(env, mk_iMOVds_RR(rdst, r1));
1380 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1381 7/*cr*/, rdst, PPCRH_Reg(r2)));
1382 addInstr(env, PPCInstr_CMov(cc, rdst, PPCRI_Reg(r2)));
1386 if (e->Iex.Binop.op == Iop_32HLto64) {
1387 HReg r_Hi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1388 HReg r_Lo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1389 HReg r_dst = newVRegI(env);
1390 HReg msk = newVRegI(env);
1392 /* r_dst = OR( r_Hi<<32, r_Lo ) */
1393 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1394 r_dst, r_Hi, PPCRH_Imm(False,32)));
1395 addInstr(env, PPCInstr_LI(msk, 0xFFFFFFFF, mode64));
1396 addInstr(env, PPCInstr_Alu( Palu_AND, r_Lo, r_Lo,
1398 addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst,
1403 if (e->Iex.Binop.op == Iop_CmpF64) {
1404 HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
1405 HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
1407 HReg r_ccPPC = newVRegI(env);
1408 HReg r_ccIR = newVRegI(env);
1409 HReg r_ccIR_b0 = newVRegI(env);
1410 HReg r_ccIR_b2 = newVRegI(env);
1411 HReg r_ccIR_b6 = newVRegI(env);
1413 addInstr(env, PPCInstr_FpCmp(r_ccPPC, fr_srcL, fr_srcR));
1415 /* Map compare result from PPC to IR,
1416 conforming to CmpF64 definition. */
1418 FP cmp result | PPC | IR
1419 --------------------------
1426 // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1427 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1429 PPCRH_Imm(False,0x3)));
1430 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR_b0,
1431 r_ccPPC, PPCRH_Reg(r_ccIR_b0)));
1432 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b0,
1433 r_ccIR_b0, PPCRH_Imm(False,0x1)));
1435 // r_ccIR_b2 = r_ccPPC[0]
1436 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1438 PPCRH_Imm(False,0x2)));
1439 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b2,
1440 r_ccIR_b2, PPCRH_Imm(False,0x4)));
1442 // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
1443 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1445 PPCRH_Imm(False,0x1)));
1446 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR_b6,
1447 r_ccPPC, PPCRH_Reg(r_ccIR_b6)));
1448 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1449 r_ccIR_b6, r_ccIR_b6,
1450 PPCRH_Imm(False,0x6)));
1451 addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b6,
1452 r_ccIR_b6, PPCRH_Imm(False,0x40)));
1454 // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
1455 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1456 r_ccIR_b0, PPCRH_Reg(r_ccIR_b2)));
1457 addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1458 r_ccIR, PPCRH_Reg(r_ccIR_b6)));
1462 if (e->Iex.Binop.op == Iop_F64toI32S) {
1463 /* This works in both mode64 and mode32. */
1464 HReg r1 = StackFramePtr(env->mode64);
1465 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1466 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2);
1467 HReg ftmp = newVRegF(env);
1468 HReg idst = newVRegI(env);
1470 /* Set host rounding mode */
1471 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
1473 sub_from_sp( env, 16 );
1474 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, True/*int32*/,
1475 True/*syned*/, True/*flt64*/,
1477 addInstr(env, PPCInstr_FpSTFIW(r1, ftmp));
1478 addInstr(env, PPCInstr_Load(4, idst, zero_r1, mode64));
1480 /* in 64-bit mode we need to sign-widen idst. */
1482 addInstr(env, PPCInstr_Unary(Pun_EXTSW, idst, idst));
1484 add_to_sp( env, 16 );
1486 ///* Restore default FPU rounding. */
1487 //set_FPU_rounding_default( env );
1491 if (e->Iex.Binop.op == Iop_F64toI64S) {
1493 HReg r1 = StackFramePtr(env->mode64);
1494 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1495 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2);
1496 HReg idst = newVRegI(env);
1497 HReg ftmp = newVRegF(env);
1499 /* Set host rounding mode */
1500 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
1502 sub_from_sp( env, 16 );
1503 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, True,
1505 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1506 addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1507 add_to_sp( env, 16 );
1509 ///* Restore default FPU rounding. */
1510 //set_FPU_rounding_default( env );
1518 /* --------- UNARY OP --------- */
1520 IROp op_unop = e->Iex.Unop.op;
1522 /* 1Uto8(32to1(expr32)) */
1523 DEFINE_PATTERN(p_32to1_then_1Uto8,
1524 unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1525 if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1526 IRExpr* expr32 = mi.bindee[0];
1527 HReg r_dst = newVRegI(env);
1528 HReg r_src = iselWordExpr_R(env, expr32);
1529 addInstr(env, PPCInstr_Alu(Palu_AND, r_dst,
1530 r_src, PPCRH_Imm(False,1)));
1534 /* 16Uto32(LDbe:I16(expr32)) */
1536 DECLARE_PATTERN(p_LDbe16_then_16Uto32);
1537 DEFINE_PATTERN(p_LDbe16_then_16Uto32,
1539 IRExpr_Load(Iend_BE,Ity_I16,bind(0))) );
1540 if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
1541 HReg r_dst = newVRegI(env);
1543 = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/ );
1544 addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
1555 HReg r_dst = newVRegI(env);
1556 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1557 UShort mask = toUShort(op_unop==Iop_16Uto64 ? 0xFFFF :
1558 op_unop==Iop_16Uto32 ? 0xFFFF : 0xFF);
1559 addInstr(env, PPCInstr_Alu(Palu_AND,r_dst,r_src,
1560 PPCRH_Imm(False,mask)));
1564 HReg r_dst = newVRegI(env);
1565 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1568 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1569 r_dst, r_src, PPCRH_Imm(False,32)));
1571 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1572 r_dst, r_dst, PPCRH_Imm(False,32)));
1578 HReg r_dst = newVRegI(env);
1579 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1580 UShort amt = toUShort(op_unop==Iop_16Sto32 ? 16 : 24);
1582 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1583 r_dst, r_src, PPCRH_Imm(False,amt)));
1585 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1586 r_dst, r_dst, PPCRH_Imm(False,amt)));
1591 HReg r_dst = newVRegI(env);
1592 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1593 UShort amt = toUShort(op_unop==Iop_8Sto64 ? 56 :
1594 op_unop==Iop_16Sto64 ? 48 : 32);
1597 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1598 r_dst, r_src, PPCRH_Imm(False,amt)));
1600 PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1601 r_dst, r_dst, PPCRH_Imm(False,amt)));
1605 HReg r_dst = newVRegI(env);
1606 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1608 /* According to the IBM docs, in 64 bit mode, srawi r,r,0
1609 sign extends the lower 32 bits into the upper 32 bits. */
1611 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1612 r_dst, r_src, PPCRH_Imm(False,0)));
1619 if (op_unop == Iop_Not64) vassert(mode64);
1620 HReg r_dst = newVRegI(env);
1621 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1622 addInstr(env, PPCInstr_Unary(Pun_NOT,r_dst,r_src));
1625 case Iop_64HIto32: {
1628 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1629 return rHi; /* and abandon rLo .. poor wee thing :-) */
1631 HReg r_dst = newVRegI(env);
1632 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1634 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1635 r_dst, r_src, PPCRH_Imm(False,32)));
1642 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1643 return rLo; /* similar stupid comment to the above ... */
1645 /* This is a no-op. */
1646 return iselWordExpr_R(env, e->Iex.Unop.arg);
1650 if (mode64) { /* This is a no-op. */
1651 return iselWordExpr_R(env, e->Iex.Unop.arg);
1653 break; /* evidently not used in 32-bit mode */
1656 case Iop_32HIto16: {
1657 HReg r_dst = newVRegI(env);
1658 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1659 UShort shift = toUShort(op_unop == Iop_16HIto8 ? 8 : 16);
1661 PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1662 r_dst, r_src, PPCRH_Imm(False,shift)));
1668 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1669 return rHi; /* and abandon rLo .. poor wee thing :-) */
1675 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1676 return rLo; /* similar stupid comment to the above ... */
1681 HReg r_dst = newVRegI(env);
1682 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1683 addInstr(env, PPCInstr_Set(cond,r_dst));
1689 /* could do better than this, but for now ... */
1690 HReg r_dst = newVRegI(env);
1691 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1692 addInstr(env, PPCInstr_Set(cond,r_dst));
1694 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1695 r_dst, r_dst, PPCRH_Imm(False,31)));
1697 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1698 r_dst, r_dst, PPCRH_Imm(False,31)));
1703 /* could do better than this, but for now ... */
1704 HReg r_dst = newVRegI(env);
1705 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1706 addInstr(env, PPCInstr_Set(cond,r_dst));
1707 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1708 r_dst, r_dst, PPCRH_Imm(False,63)));
1709 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1710 r_dst, r_dst, PPCRH_Imm(False,63)));
1717 PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 :
1719 if (op_unop == Iop_Clz64 && !mode64)
1721 /* Count leading zeroes. */
1722 r_dst = newVRegI(env);
1723 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1724 addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
1732 if (op_unop == Iop_Left64 && !mode64)
1734 r_dst = newVRegI(env);
1735 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1736 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1737 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1741 case Iop_CmpwNEZ32: {
1742 HReg r_dst = newVRegI(env);
1743 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1744 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1745 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1746 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1747 r_dst, r_dst, PPCRH_Imm(False, 31)));
1751 case Iop_CmpwNEZ64: {
1752 HReg r_dst = newVRegI(env);
1753 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1754 if (!mode64) goto irreducible;
1755 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1756 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1757 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1758 r_dst, r_dst, PPCRH_Imm(False, 63)));
1762 case Iop_V128to32: {
1764 HReg dst = newVRegI(env);
1765 HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
1766 PPCAMode *am_off0, *am_off12;
1767 sub_from_sp( env, 32 ); // Move SP down 32 bytes
1769 // get a quadword aligned address within our stack space
1770 r_aligned16 = get_sp_aligned16( env );
1771 am_off0 = PPCAMode_IR( 0, r_aligned16 );
1772 am_off12 = PPCAMode_IR( 12,r_aligned16 );
1774 // store vec, load low word to dst
1776 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
1778 PPCInstr_Load( 4, dst, am_off12, mode64 ));
1780 add_to_sp( env, 32 ); // Reset SP
1785 case Iop_V128HIto64:
1788 HReg dst = newVRegI(env);
1789 HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
1790 PPCAMode *am_off0, *am_off8;
1791 sub_from_sp( env, 32 ); // Move SP down 32 bytes
1793 // get a quadword aligned address within our stack space
1794 r_aligned16 = get_sp_aligned16( env );
1795 am_off0 = PPCAMode_IR( 0, r_aligned16 );
1796 am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
1798 // store vec, load low word (+8) or high (+0) to dst
1800 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
1804 op_unop == Iop_V128HIto64 ? am_off0 : am_off8,
1807 add_to_sp( env, 32 ); // Reset SP
1815 /* These are no-ops. */
1816 return iselWordExpr_R(env, e->Iex.Unop.arg);
1818 /* ReinterpF64asI64(e) */
1819 /* Given an IEEE754 double, produce an I64 with the same bit
1821 case Iop_ReinterpF64asI64:
1824 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
1825 HReg r_dst = newVRegI(env);
1827 sub_from_sp( env, 16 ); // Move SP down 16 bytes
1828 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
1831 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
1834 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
1836 add_to_sp( env, 16 ); // Reset SP
1841 /* ReinterpF32asI32(e) */
1842 /* Given an IEEE754 float, produce an I32 with the same bit
1844 case Iop_ReinterpF32asI32: {
1845 /* I believe this generates correct code for both 32- and
1848 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1849 HReg r_dst = newVRegI(env);
1851 sub_from_sp( env, 16 ); // Move SP down 16 bytes
1852 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
1855 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
1858 addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
1860 add_to_sp( env, 16 ); // Reset SP
1870 /* --------- GET --------- */
1872 if (ty == Ity_I8 || ty == Ity_I16 ||
1873 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
1874 HReg r_dst = newVRegI(env);
1875 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
1876 GuestStatePtr(mode64) );
1877 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1878 r_dst, am_addr, mode64 ));
1886 = genGuestArrayOffset( env, e->Iex.GetI.descr,
1887 e->Iex.GetI.ix, e->Iex.GetI.bias );
1888 HReg r_dst = newVRegI(env);
1889 if (mode64 && ty == Ity_I64) {
1890 addInstr(env, PPCInstr_Load( toUChar(8),
1891 r_dst, src_am, mode64 ));
1894 if ((!mode64) && ty == Ity_I32) {
1895 addInstr(env, PPCInstr_Load( toUChar(4),
1896 r_dst, src_am, mode64 ));
1902 /* --------- CCALL --------- */
1904 HReg r_dst = newVRegI(env);
1905 vassert(ty == Ity_I32);
1907 /* be very restrictive for now. Only 32/64-bit ints allowed
1908 for args, and 32 bits for return type. */
1909 if (e->Iex.CCall.retty != Ity_I32)
1912 /* Marshal args, do the call, clear stack. */
1913 doHelperCall( env, False, NULL,
1914 e->Iex.CCall.cee, e->Iex.CCall.args );
1916 /* GPR3 now holds the destination address from Pin_Goto */
1917 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
1921 /* --------- LITERAL --------- */
1922 /* 32/16/8-bit literals */
1925 HReg r_dst = newVRegI(env);
1926 IRConst* con = e->Iex.Const.con;
1928 case Ico_U64: if (!mode64) goto irreducible;
1929 l = (Long) con->Ico.U64; break;
1930 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
1931 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
1932 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
1933 default: vpanic("iselIntExpr_R.const(ppc)");
1935 addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64));
1939 /* --------- MULTIPLEX --------- */
1941 if ((ty == Ity_I8 || ty == Ity_I16 ||
1942 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) &&
1943 typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1944 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
1945 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
1946 HReg rX = iselWordExpr_R(env, e->Iex.Mux0X.exprX);
1947 PPCRI* r0 = iselWordExpr_RI(env, e->Iex.Mux0X.expr0);
1948 HReg r_dst = newVRegI(env);
1949 HReg r_tmp = newVRegI(env);
1950 addInstr(env, mk_iMOVds_RR(r_dst,rX));
1951 addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp,
1952 r_cond, PPCRH_Imm(False,0xFF)));
1953 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1954 7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
1955 addInstr(env, PPCInstr_CMov(cc,r_dst,r0));
1963 } /* switch (e->tag) */
1966 /* We get here if no pattern matched. */
1969 vpanic("iselIntExpr_R(ppc): cannot reduce tree");
1973 /*---------------------------------------------------------*/
1974 /*--- ISEL: Integer expression auxiliaries ---*/
1975 /*---------------------------------------------------------*/
1977 /* --------------------- AMODEs --------------------- */
1979 /* Return an AMode which computes the value of the specified
1980 expression, possibly also adding insns to the code list as a
1981 result. The expression may only be a word-size one.
1984 static Bool uInt_fits_in_16_bits ( UInt u )
1986 /* Is u the same as the sign-extend of its lower 16 bits? */
1990 return toBool(u == (UInt)i);
1993 static Bool uLong_fits_in_16_bits ( ULong u )
1995 /* Is u the same as the sign-extend of its lower 16 bits? */
1996 Long i = u & 0xFFFFULL;
1999 return toBool(u == (ULong)i);
2002 static Bool uLong_is_4_aligned ( ULong u )
2004 return toBool((u & 3ULL) == 0);
2007 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2009 Bool mode64 = env->mode64;
2012 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2013 somehow, but I think it's OK. */
2014 return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2015 hregIsVirtual(am->Pam.IR.base) &&
2016 uInt_fits_in_16_bits(am->Pam.IR.index) );
2018 return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2019 hregIsVirtual(am->Pam.RR.base) &&
2020 hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2021 hregIsVirtual(am->Pam.IR.index) );
2023 vpanic("sane_AMode: unknown ppc amode tag");
2028 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy )
2030 PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy);
2031 vassert(sane_AMode(env, am));
2035 /* DO NOT CALL THIS DIRECTLY ! */
2036 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy )
2038 IRType ty = typeOfIRExpr(env->type_env,e);
2042 /* If the data load/store type is I32 or I64, this amode might
2043 be destined for use in ld/ldu/lwa/st/stu. In which case
2044 insist that if it comes out as an _IR, the immediate must
2045 have its bottom two bits be zero. This does assume that for
2046 any other type (I8/I16/I128/F32/F64/V128) the amode will not
2047 be parked in any such instruction. But that seems a
2048 reasonable assumption. */
2049 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2051 vassert(ty == Ity_I64);
2053 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2054 if (e->tag == Iex_Binop
2055 && e->Iex.Binop.op == Iop_Add64
2056 && e->Iex.Binop.arg2->tag == Iex_Const
2057 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2058 && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2
2059 ->Iex.Const.con->Ico.U64)
2061 && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2062 ->Iex.Const.con->Ico.U64)) {
2063 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2064 iselWordExpr_R(env, e->Iex.Binop.arg1) );
2067 /* Add64(expr,expr) */
2068 if (e->tag == Iex_Binop
2069 && e->Iex.Binop.op == Iop_Add64) {
2070 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
2071 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
2072 return PPCAMode_RR( r_idx, r_base );
2077 vassert(ty == Ity_I32);
2079 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2080 if (e->tag == Iex_Binop
2081 && e->Iex.Binop.op == Iop_Add32
2082 && e->Iex.Binop.arg2->tag == Iex_Const
2083 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2084 && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2085 ->Iex.Const.con->Ico.U32)) {
2086 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2087 iselWordExpr_R(env, e->Iex.Binop.arg1) );
2090 /* Add32(expr,expr) */
2091 if (e->tag == Iex_Binop
2092 && e->Iex.Binop.op == Iop_Add32) {
2093 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
2094 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
2095 return PPCAMode_RR( r_idx, r_base );
2100 /* Doesn't match anything in particular. Generate it into
2101 a register and use that. */
2102 return PPCAMode_IR( 0, iselWordExpr_R(env,e) );
2106 /* --------------------- RH --------------------- */
2108 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2109 (reg-or-halfword-immediate). It's important to specify whether the
2110 immediate is to be regarded as signed or not. If yes, this will
2111 never return -32768 as an immediate; this guaranteed that all
2112 signed immediates that are return can have their sign inverted if
2115 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e )
2117 PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e);
2118 /* sanity checks ... */
2121 vassert(ri->Prh.Imm.syned == syned);
2123 vassert(ri->Prh.Imm.imm16 != 0x8000);
2126 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2127 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2130 vpanic("iselIntExpr_RH: unknown ppc RH tag");
2134 /* DO NOT CALL THIS DIRECTLY ! */
2135 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e )
2139 IRType ty = typeOfIRExpr(env->type_env,e);
2140 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2141 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2143 /* special case: immediate */
2144 if (e->tag == Iex_Const) {
2145 IRConst* con = e->Iex.Const.con;
2146 /* What value are we aiming to generate? */
2148 /* Note: Not sign-extending - we carry 'syned' around */
2149 case Ico_U64: vassert(env->mode64);
2150 u = con->Ico.U64; break;
2151 case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2152 case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2153 case Ico_U8: u = 0x000000FF & con->Ico.U8; break;
2154 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2157 /* Now figure out if it's representable. */
2158 if (!syned && u <= 65535) {
2159 return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2161 if (syned && l >= -32767 && l <= 32767) {
2162 return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2164 /* no luck; use the Slow Way. */
2167 /* default case: calculate into a register and return that */
2168 return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2172 /* --------------------- RIs --------------------- */
2174 /* Calculate an expression into an PPCRI operand. As with
2175 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2176 in 64-bit mode, 64 bits. */
2178 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e )
2180 PPCRI* ri = iselWordExpr_RI_wrk(env, e);
2181 /* sanity checks ... */
2186 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2187 vassert(hregIsVirtual(ri->Pri.Reg));
2190 vpanic("iselIntExpr_RI: unknown ppc RI tag");
2194 /* DO NOT CALL THIS DIRECTLY ! */
2195 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
2198 IRType ty = typeOfIRExpr(env->type_env,e);
2199 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2200 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2202 /* special case: immediate */
2203 if (e->tag == Iex_Const) {
2204 IRConst* con = e->Iex.Const.con;
2206 case Ico_U64: vassert(env->mode64);
2207 l = (Long) con->Ico.U64; break;
2208 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
2209 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2210 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
2211 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2213 return PPCRI_Imm((ULong)l);
2216 /* default case: calculate into a register and return that */
2217 return PPCRI_Reg( iselWordExpr_R ( env, e ) );
2221 /* --------------------- RH5u --------------------- */
2223 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2224 being an immediate in the range 1 .. 31 inclusive. Used for doing
2225 shift amounts. Only used in 32-bit mode. */
2227 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e )
2230 vassert(!env->mode64);
2231 ri = iselWordExpr_RH5u_wrk(env, e);
2232 /* sanity checks ... */
2235 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2236 vassert(!ri->Prh.Imm.syned);
2239 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2240 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2243 vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2247 /* DO NOT CALL THIS DIRECTLY ! */
2248 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e )
2250 IRType ty = typeOfIRExpr(env->type_env,e);
2251 vassert(ty == Ity_I8);
2253 /* special case: immediate */
2254 if (e->tag == Iex_Const
2255 && e->Iex.Const.con->tag == Ico_U8
2256 && e->Iex.Const.con->Ico.U8 >= 1
2257 && e->Iex.Const.con->Ico.U8 <= 31) {
2258 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2261 /* default case: calculate into a register and return that */
2262 return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2266 /* --------------------- RH6u --------------------- */
2268 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2269 being an immediate in the range 1 .. 63 inclusive. Used for doing
2270 shift amounts. Only used in 64-bit mode. */
2272 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e )
2275 vassert(env->mode64);
2276 ri = iselWordExpr_RH6u_wrk(env, e);
2277 /* sanity checks ... */
2280 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2281 vassert(!ri->Prh.Imm.syned);
2284 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2285 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2288 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2292 /* DO NOT CALL THIS DIRECTLY ! */
2293 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e )
2295 IRType ty = typeOfIRExpr(env->type_env,e);
2296 vassert(ty == Ity_I8);
2298 /* special case: immediate */
2299 if (e->tag == Iex_Const
2300 && e->Iex.Const.con->tag == Ico_U8
2301 && e->Iex.Const.con->Ico.U8 >= 1
2302 && e->Iex.Const.con->Ico.U8 <= 63) {
2303 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2306 /* default case: calculate into a register and return that */
2307 return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2311 /* --------------------- CONDCODE --------------------- */
2313 /* Generate code to evaluated a bit-typed expression, returning the
2314 condition code which would correspond when the expression would
2315 notionally have returned 1. */
2317 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
2319 /* Uh, there's nothing we can sanity check here, unfortunately. */
2320 return iselCondCode_wrk(env,e);
2323 /* DO NOT CALL THIS DIRECTLY ! */
2324 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
2327 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2329 /* Constant 1:Bit */
2330 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2331 // Make a compare that will always be true:
2332 HReg r_zero = newVRegI(env);
2333 addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2334 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2335 7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2336 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2340 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2341 /* Generate code for the arg, and negate the test condition */
2342 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2343 cond.test = invertCondTest(cond.test);
2347 /* --- patterns rooted at: 32to1 or 64to1 --- */
2350 if (e->tag == Iex_Unop &&
2351 (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2352 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2353 HReg tmp = newVRegI(env);
2354 /* could do better, probably -- andi. */
2355 addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2356 src, PPCRH_Imm(False,1)));
2357 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2358 7/*cr*/, tmp, PPCRH_Imm(False,1)));
2359 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2362 /* --- patterns rooted at: CmpNEZ8 --- */
2365 /* could do better -- andi. */
2366 if (e->tag == Iex_Unop
2367 && e->Iex.Unop.op == Iop_CmpNEZ8) {
2368 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg);
2369 HReg tmp = newVRegI(env);
2370 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2371 PPCRH_Imm(False,0xFF)));
2372 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2373 7/*cr*/, tmp, PPCRH_Imm(False,0)));
2374 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2377 /* --- patterns rooted at: CmpNEZ32 --- */
2380 if (e->tag == Iex_Unop
2381 && e->Iex.Unop.op == Iop_CmpNEZ32) {
2382 HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg);
2383 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2384 7/*cr*/, r1, PPCRH_Imm(False,0)));
2385 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2388 /* --- patterns rooted at: Cmp*32* --- */
2391 if (e->tag == Iex_Binop
2392 && (e->Iex.Binop.op == Iop_CmpEQ32
2393 || e->Iex.Binop.op == Iop_CmpNE32
2394 || e->Iex.Binop.op == Iop_CmpLT32S
2395 || e->Iex.Binop.op == Iop_CmpLT32U
2396 || e->Iex.Binop.op == Iop_CmpLE32S
2397 || e->Iex.Binop.op == Iop_CmpLE32U)) {
2398 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2399 e->Iex.Binop.op == Iop_CmpLE32S);
2400 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2401 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
2402 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2405 switch (e->Iex.Binop.op) {
2406 case Iop_CmpEQ32: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2407 case Iop_CmpNE32: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2408 case Iop_CmpLT32U: case Iop_CmpLT32S:
2409 return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
2410 case Iop_CmpLE32U: case Iop_CmpLE32S:
2411 return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2412 default: vpanic("iselCondCode(ppc): CmpXX32");
2416 /* --- patterns rooted at: CmpNEZ64 --- */
2419 if (e->tag == Iex_Unop
2420 && e->Iex.Unop.op == Iop_CmpNEZ64) {
2423 HReg tmp = newVRegI(env);
2424 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg );
2425 addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2426 addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2427 7/*cr*/, tmp,PPCRH_Imm(False,0)));
2428 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2430 HReg r_src = iselWordExpr_R(env, e->Iex.Binop.arg1);
2431 addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2432 7/*cr*/, r_src,PPCRH_Imm(False,0)));
2433 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2437 /* --- patterns rooted at: Cmp*64* --- */
2440 if (e->tag == Iex_Binop
2441 && (e->Iex.Binop.op == Iop_CmpEQ64
2442 || e->Iex.Binop.op == Iop_CmpNE64
2443 || e->Iex.Binop.op == Iop_CmpLT64S
2444 || e->Iex.Binop.op == Iop_CmpLT64U
2445 || e->Iex.Binop.op == Iop_CmpLE64S
2446 || e->Iex.Binop.op == Iop_CmpLE64U)) {
2447 Bool syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2448 e->Iex.Binop.op == Iop_CmpLE64S);
2449 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2450 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
2451 vassert(env->mode64);
2452 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2455 switch (e->Iex.Binop.op) {
2456 case Iop_CmpEQ64: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2457 case Iop_CmpNE64: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2458 case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
2459 case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2460 default: vpanic("iselCondCode(ppc): CmpXX64");
2465 if (e->tag == Iex_RdTmp) {
2466 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2467 HReg src_masked = newVRegI(env);
2469 PPCInstr_Alu(Palu_AND, src_masked,
2470 r_src, PPCRH_Imm(False,1)));
2472 PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2473 7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2474 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2477 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
2479 vpanic("iselCondCode(ppc)");
2483 /*---------------------------------------------------------*/
2484 /*--- ISEL: Integer expressions (128 bit) ---*/
2485 /*---------------------------------------------------------*/
2487 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
2488 which is returned as the first two parameters. As with
2489 iselWordExpr_R, these may be either real or virtual regs; in any
2490 case they must not be changed by subsequent code emitted by the
2493 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
2494 ISelEnv* env, IRExpr* e )
2496 vassert(env->mode64);
2497 iselInt128Expr_wrk(rHi, rLo, env, e);
2499 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2501 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
2502 vassert(hregIsVirtual(*rHi));
2503 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
2504 vassert(hregIsVirtual(*rLo));
2507 /* DO NOT CALL THIS DIRECTLY ! */
2508 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
2509 ISelEnv* env, IRExpr* e )
2512 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
2514 /* read 128-bit IRTemp */
2515 if (e->tag == Iex_RdTmp) {
2516 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
2520 /* --------- BINARY ops --------- */
2521 if (e->tag == Iex_Binop) {
2522 switch (e->Iex.Binop.op) {
2523 /* 64 x 64 -> 128 multiply */
2526 HReg tLo = newVRegI(env);
2527 HReg tHi = newVRegI(env);
2528 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
2529 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2530 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2531 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
2532 False/*lo64*/, False/*64bit mul*/,
2533 tLo, r_srcL, r_srcR));
2534 addInstr(env, PPCInstr_MulL(syned,
2535 True/*hi64*/, False/*64bit mul*/,
2536 tHi, r_srcL, r_srcR));
2542 /* 64HLto128(e1,e2) */
2544 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2545 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2551 } /* if (e->tag == Iex_Binop) */
2554 /* --------- UNARY ops --------- */
2555 if (e->tag == Iex_Unop) {
2556 switch (e->Iex.Unop.op) {
2560 } /* if (e->tag == Iex_Unop) */
2562 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
2564 vpanic("iselInt128Expr(ppc64)");
2568 /*---------------------------------------------------------*/
2569 /*--- ISEL: Integer expressions (64 bit) ---*/
2570 /*---------------------------------------------------------*/
2572 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
2573 which is returned as the first two parameters. As with
2574 iselIntExpr_R, these may be either real or virtual regs; in any
2575 case they must not be changed by subsequent code emitted by the
2578 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
2579 ISelEnv* env, IRExpr* e )
2581 vassert(!env->mode64);
2582 iselInt64Expr_wrk(rHi, rLo, env, e);
2584 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2586 vassert(hregClass(*rHi) == HRcInt32);
2587 vassert(hregIsVirtual(*rHi));
2588 vassert(hregClass(*rLo) == HRcInt32);
2589 vassert(hregIsVirtual(*rLo));
2592 /* DO NOT CALL THIS DIRECTLY ! */
2593 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
2594 ISelEnv* env, IRExpr* e )
2597 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
2600 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
2601 HReg tLo = newVRegI(env);
2602 HReg tHi = newVRegI(env);
2603 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
2604 vassert(!env->mode64);
2605 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
2606 tHi, PPCAMode_IR( 0, r_addr ),
2607 False/*32-bit insn please*/) );
2608 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
2609 tLo, PPCAMode_IR( 4, r_addr ),
2610 False/*32-bit insn please*/) );
2616 /* 64-bit literal */
2617 if (e->tag == Iex_Const) {
2618 ULong w64 = e->Iex.Const.con->Ico.U64;
2619 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
2620 UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
2621 HReg tLo = newVRegI(env);
2622 HReg tHi = newVRegI(env);
2623 vassert(e->Iex.Const.con->tag == Ico_U64);
2624 addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
2625 addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
2631 /* read 64-bit IRTemp */
2632 if (e->tag == Iex_RdTmp) {
2633 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
2638 if (e->tag == Iex_Get) {
2639 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2640 GuestStatePtr(False/*mode32*/) );
2641 PPCAMode* am_addr4 = advance4(env, am_addr);
2642 HReg tLo = newVRegI(env);
2643 HReg tHi = newVRegI(env);
2644 addInstr(env, PPCInstr_Load( 4, tHi, am_addr, False/*mode32*/ ));
2645 addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
2652 if (e->tag == Iex_Mux0X) {
2653 HReg e0Lo, e0Hi, eXLo, eXHi;
2654 HReg tLo = newVRegI(env);
2655 HReg tHi = newVRegI(env);
2657 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2658 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
2659 HReg r_tmp = newVRegI(env);
2661 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
2662 iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX);
2663 addInstr(env, mk_iMOVds_RR(tHi,eXHi));
2664 addInstr(env, mk_iMOVds_RR(tLo,eXLo));
2666 addInstr(env, PPCInstr_Alu(Palu_AND,
2667 r_tmp, r_cond, PPCRH_Imm(False,0xFF)));
2668 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2669 7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
2671 addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(e0Hi)));
2672 addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(e0Lo)));
2678 /* --------- BINARY ops --------- */
2679 if (e->tag == Iex_Binop) {
2680 IROp op_binop = e->Iex.Binop.op;
2682 /* 32 x 32 -> 64 multiply */
2685 HReg tLo = newVRegI(env);
2686 HReg tHi = newVRegI(env);
2687 Bool syned = toBool(op_binop == Iop_MullS32);
2688 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2689 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2690 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
2691 False/*lo32*/, True/*32bit mul*/,
2692 tLo, r_srcL, r_srcR));
2693 addInstr(env, PPCInstr_MulL(syned,
2694 True/*hi32*/, True/*32bit mul*/,
2695 tHi, r_srcL, r_srcR));
2701 /* Or64/And64/Xor64 */
2705 HReg xLo, xHi, yLo, yHi;
2706 HReg tLo = newVRegI(env);
2707 HReg tHi = newVRegI(env);
2708 PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
2709 (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
2710 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2711 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2712 addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
2713 addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
2721 HReg xLo, xHi, yLo, yHi;
2722 HReg tLo = newVRegI(env);
2723 HReg tHi = newVRegI(env);
2724 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2725 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2726 addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
2728 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
2735 /* 32HLto64(e1,e2) */
2737 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2738 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2742 case Iop_F64toI64S: {
2743 HReg tLo = newVRegI(env);
2744 HReg tHi = newVRegI(env);
2745 HReg r1 = StackFramePtr(env->mode64);
2746 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
2747 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
2748 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2);
2749 HReg ftmp = newVRegF(env);
2751 vassert(!env->mode64);
2752 /* Set host rounding mode */
2753 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2755 sub_from_sp( env, 16 );
2756 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, True,
2758 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
2759 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
2760 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
2761 add_to_sp( env, 16 );
2763 ///* Restore default FPU rounding. */
2764 //set_FPU_rounding_default( env );
2773 } /* if (e->tag == Iex_Binop) */
2776 /* --------- UNARY ops --------- */
2777 if (e->tag == Iex_Unop) {
2778 switch (e->Iex.Unop.op) {
2781 case Iop_CmpwNEZ64: {
2783 HReg tmp1 = newVRegI(env);
2784 HReg tmp2 = newVRegI(env);
2785 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
2786 /* tmp1 = argHi | argLo */
2787 addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
2788 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2789 addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
2790 addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
2791 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2792 tmp2, tmp2, PPCRH_Imm(False, 31)));
2794 *rLo = tmp2; /* yes, really tmp2 */
2801 HReg zero32 = newVRegI(env);
2802 HReg resHi = newVRegI(env);
2803 HReg resLo = newVRegI(env);
2804 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
2805 vassert(env->mode64 == False);
2806 addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
2807 /* resHi:resLo = - argHi:argLo */
2808 addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
2809 resLo, zero32, argLo ));
2810 addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
2811 resHi, zero32, argHi ));
2812 /* resHi:resLo |= srcHi:srcLo */
2813 addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
2814 addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
2822 HReg tHi = newVRegI(env);
2823 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2824 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2825 tHi, src, PPCRH_Imm(False,31)));
2833 HReg tHi = newVRegI(env);
2834 HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg);
2835 addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
2842 case Iop_V128HIto64:
2843 case Iop_V128to64: {
2845 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
2846 HReg tLo = newVRegI(env);
2847 HReg tHi = newVRegI(env);
2848 HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
2849 PPCAMode *am_off0, *am_offLO, *am_offHI;
2850 sub_from_sp( env, 32 ); // Move SP down 32 bytes
2852 // get a quadword aligned address within our stack space
2853 r_aligned16 = get_sp_aligned16( env );
2854 am_off0 = PPCAMode_IR( 0, r_aligned16 );
2855 am_offHI = PPCAMode_IR( off, r_aligned16 );
2856 am_offLO = PPCAMode_IR( off+4, r_aligned16 );
2860 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2862 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
2864 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
2866 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
2868 add_to_sp( env, 32 ); // Reset SP
2874 /* could do better than this, but for now ... */
2876 HReg tLo = newVRegI(env);
2877 HReg tHi = newVRegI(env);
2878 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2879 addInstr(env, PPCInstr_Set(cond,tLo));
2880 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
2881 tLo, tLo, PPCRH_Imm(False,31)));
2882 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2883 tLo, tLo, PPCRH_Imm(False,31)));
2884 addInstr(env, mk_iMOVds_RR(tHi, tLo));
2892 HReg tmpLo = newVRegI(env);
2893 HReg tmpHi = newVRegI(env);
2894 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg);
2895 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
2896 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
2902 /* ReinterpF64asI64(e) */
2903 /* Given an IEEE754 double, produce an I64 with the same bit
2905 case Iop_ReinterpF64asI64: {
2906 PPCAMode *am_addr0, *am_addr1;
2907 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
2908 HReg r_dstLo = newVRegI(env);
2909 HReg r_dstHi = newVRegI(env);
2911 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2912 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
2913 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
2916 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2917 fr_src, am_addr0 ));
2919 // load hi,lo as Ity_I32's
2920 addInstr(env, PPCInstr_Load( 4, r_dstHi,
2921 am_addr0, False/*mode32*/ ));
2922 addInstr(env, PPCInstr_Load( 4, r_dstLo,
2923 am_addr1, False/*mode32*/ ));
2927 add_to_sp( env, 16 ); // Reset SP
2934 } /* if (e->tag == Iex_Unop) */
2936 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
2938 vpanic("iselInt64Expr(ppc)");
2942 /*---------------------------------------------------------*/
2943 /*--- ISEL: Floating point expressions (32 bit) ---*/
2944 /*---------------------------------------------------------*/
2946 /* Nothing interesting here; really just wrappers for
2949 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
2951 HReg r = iselFltExpr_wrk( env, e );
2953 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2955 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
2956 vassert(hregIsVirtual(r));
2960 /* DO NOT CALL THIS DIRECTLY */
2961 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
2963 Bool mode64 = env->mode64;
2965 IRType ty = typeOfIRExpr(env->type_env,e);
2966 vassert(ty == Ity_F32);
2968 if (e->tag == Iex_RdTmp) {
2969 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2972 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
2974 HReg r_dst = newVRegF(env);
2975 vassert(e->Iex.Load.ty == Ity_F32);
2976 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/);
2977 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
2981 if (e->tag == Iex_Get) {
2982 HReg r_dst = newVRegF(env);
2983 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2984 GuestStatePtr(env->mode64) );
2985 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
2989 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
2990 /* This is quite subtle. The only way to do the relevant
2991 truncation is to do a single-precision store and then a
2992 double precision load to get it back into a register. The
2993 problem is, if the data is then written to memory a second
2996 STbe(...) = TruncF64asF32(...)
2998 then will the second truncation further alter the value? The
2999 answer is no: flds (as generated here) followed by fsts
3000 (generated for the STbe) is the identity function on 32-bit
3001 floats, so we are safe.
3003 Another upshot of this is that if iselStmt can see the
3006 STbe(...) = TruncF64asF32(arg)
3008 then it can short circuit having to deal with TruncF64asF32
3009 individually; instead just compute arg into a 64-bit FP
3010 register and do 'fsts' (since that itself does the
3013 We generate pretty poor code here (should be ok both for
3014 32-bit and 64-bit mode); but it is expected that for the most
3015 part the latter optimisation will apply and hence this code
3016 will not often be used.
3018 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
3019 HReg fdst = newVRegF(env);
3020 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3022 sub_from_sp( env, 16 );
3023 // store as F32, hence truncating
3024 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3026 // and reload. Good huh?! (sigh)
3027 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3029 add_to_sp( env, 16 );
3033 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3035 HReg fdst = newVRegF(env);
3036 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
3037 HReg r1 = StackFramePtr(env->mode64);
3038 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3040 /* Set host rounding mode */
3041 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3043 sub_from_sp( env, 16 );
3045 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3046 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3047 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3051 add_to_sp( env, 16 );
3053 ///* Restore default FPU rounding. */
3054 //set_FPU_rounding_default( env );
3058 HReg fdst = newVRegF(env);
3059 HReg isrcHi, isrcLo;
3060 HReg r1 = StackFramePtr(env->mode64);
3061 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3062 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3064 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2);
3066 /* Set host rounding mode */
3067 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3069 sub_from_sp( env, 16 );
3071 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3072 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3073 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3074 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3078 add_to_sp( env, 16 );
3080 ///* Restore default FPU rounding. */
3081 //set_FPU_rounding_default( env );
3087 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3089 vpanic("iselFltExpr_wrk(ppc)");
3093 /*---------------------------------------------------------*/
3094 /*--- ISEL: Floating point expressions (64 bit) ---*/
3095 /*---------------------------------------------------------*/
3097 /* Compute a 64-bit floating point value into a register, the identity
3098 of which is returned. As with iselIntExpr_R, the reg may be either
3099 real or virtual; in any case it must not be changed by subsequent
3100 code emitted by the caller. */
3102 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3104 Type S (1 bit) E (11 bits) F (52 bits)
3105 ---- --------- ----------- -----------
3106 signalling NaN u 2047 (max) .0uuuuu---u
3109 quiet NaN u 2047 (max) .1uuuuu---u
3111 negative infinity 1 2047 (max) .000000---0
3113 positive infinity 0 2047 (max) .000000---0
3115 negative zero 1 0 .000000---0
3117 positive zero 0 0 .000000---0
3120 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
3122 HReg r = iselDblExpr_wrk( env, e );
3124 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3126 vassert(hregClass(r) == HRcFlt64);
3127 vassert(hregIsVirtual(r));
3131 /* DO NOT CALL THIS DIRECTLY */
3132 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
3134 Bool mode64 = env->mode64;
3135 IRType ty = typeOfIRExpr(env->type_env,e);
3137 vassert(ty == Ity_F64);
3139 if (e->tag == Iex_RdTmp) {
3140 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3143 /* --------- LITERAL --------- */
3144 if (e->tag == Iex_Const) {
3145 union { UInt u32x2[2]; ULong u64; Double f64; } u;
3146 vassert(sizeof(u) == 8);
3147 vassert(sizeof(u.u64) == 8);
3148 vassert(sizeof(u.f64) == 8);
3149 vassert(sizeof(u.u32x2) == 8);
3151 if (e->Iex.Const.con->tag == Ico_F64) {
3152 u.f64 = e->Iex.Const.con->Ico.F64;
3154 else if (e->Iex.Const.con->tag == Ico_F64i) {
3155 u.u64 = e->Iex.Const.con->Ico.F64i;
3158 vpanic("iselDblExpr(ppc): const");
3161 HReg r_srcHi = newVRegI(env);
3162 HReg r_srcLo = newVRegI(env);
3163 addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3164 addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3165 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3167 HReg r_src = newVRegI(env);
3168 addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3169 return mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
3173 /* --------- LOAD --------- */
3174 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
3175 HReg r_dst = newVRegF(env);
3177 vassert(e->Iex.Load.ty == Ity_F64);
3178 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/);
3179 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3183 /* --------- GET --------- */
3184 if (e->tag == Iex_Get) {
3185 HReg r_dst = newVRegF(env);
3186 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3187 GuestStatePtr(mode64) );
3188 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
3192 /* --------- OPS --------- */
3193 if (e->tag == Iex_Qop) {
3194 PPCFpOp fpop = Pfp_INVALID;
3195 switch (e->Iex.Qop.op) {
3196 case Iop_MAddF64: fpop = Pfp_MADDD; break;
3197 case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
3198 case Iop_MSubF64: fpop = Pfp_MSUBD; break;
3199 case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
3202 if (fpop != Pfp_INVALID) {
3203 HReg r_dst = newVRegF(env);
3204 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.arg2);
3205 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.arg3);
3206 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.arg4);
3207 set_FPU_rounding_mode( env, e->Iex.Qop.arg1 );
3208 addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
3209 r_srcML, r_srcMR, r_srcAcc));
3214 if (e->tag == Iex_Triop) {
3215 PPCFpOp fpop = Pfp_INVALID;
3216 switch (e->Iex.Triop.op) {
3217 case Iop_AddF64: fpop = Pfp_ADDD; break;
3218 case Iop_SubF64: fpop = Pfp_SUBD; break;
3219 case Iop_MulF64: fpop = Pfp_MULD; break;
3220 case Iop_DivF64: fpop = Pfp_DIVD; break;
3221 case Iop_AddF64r32: fpop = Pfp_ADDS; break;
3222 case Iop_SubF64r32: fpop = Pfp_SUBS; break;
3223 case Iop_MulF64r32: fpop = Pfp_MULS; break;
3224 case Iop_DivF64r32: fpop = Pfp_DIVS; break;
3227 if (fpop != Pfp_INVALID) {
3228 HReg r_dst = newVRegF(env);
3229 HReg r_srcL = iselDblExpr(env, e->Iex.Triop.arg2);
3230 HReg r_srcR = iselDblExpr(env, e->Iex.Triop.arg3);
3231 set_FPU_rounding_mode( env, e->Iex.Triop.arg1 );
3232 addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
3237 if (e->tag == Iex_Binop) {
3238 PPCFpOp fpop = Pfp_INVALID;
3239 switch (e->Iex.Binop.op) {
3240 case Iop_SqrtF64: fpop = Pfp_SQRT; break;
3243 if (fpop != Pfp_INVALID) {
3244 HReg fr_dst = newVRegF(env);
3245 HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2);
3246 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3247 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
3252 if (e->tag == Iex_Binop) {
3254 if (e->Iex.Binop.op == Iop_RoundF64toF32) {
3255 HReg r_dst = newVRegF(env);
3256 HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2);
3257 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3258 addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
3259 //set_FPU_rounding_default( env );
3263 if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
3265 HReg fdst = newVRegF(env);
3266 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
3267 HReg r1 = StackFramePtr(env->mode64);
3268 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3270 /* Set host rounding mode */
3271 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3273 sub_from_sp( env, 16 );
3275 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3276 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3277 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3278 e->Iex.Binop.op == Iop_I64StoF64,
3279 True/*fdst is 64 bit*/,
3282 add_to_sp( env, 16 );
3284 ///* Restore default FPU rounding. */
3285 //set_FPU_rounding_default( env );
3289 HReg fdst = newVRegF(env);
3290 HReg isrcHi, isrcLo;
3291 HReg r1 = StackFramePtr(env->mode64);
3292 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3293 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3295 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2);
3297 /* Set host rounding mode */
3298 set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3300 sub_from_sp( env, 16 );
3302 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3303 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3304 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3305 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3306 e->Iex.Binop.op == Iop_I64StoF64,
3307 True/*fdst is 64 bit*/,
3310 add_to_sp( env, 16 );
3312 ///* Restore default FPU rounding. */
3313 //set_FPU_rounding_default( env );
3320 if (e->tag == Iex_Unop) {
3321 PPCFpOp fpop = Pfp_INVALID;
3322 switch (e->Iex.Unop.op) {
3323 case Iop_NegF64: fpop = Pfp_NEG; break;
3324 case Iop_AbsF64: fpop = Pfp_ABS; break;
3325 case Iop_Est5FRSqrt: fpop = Pfp_RSQRTE; break;
3326 case Iop_RoundF64toF64_NegINF: fpop = Pfp_FRIM; break;
3327 case Iop_RoundF64toF64_PosINF: fpop = Pfp_FRIP; break;
3328 case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
3329 case Iop_RoundF64toF64_ZERO: fpop = Pfp_FRIZ; break;
3332 if (fpop != Pfp_INVALID) {
3333 HReg fr_dst = newVRegF(env);
3334 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
3335 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
3340 if (e->tag == Iex_Unop) {
3341 switch (e->Iex.Unop.op) {
3342 case Iop_ReinterpI64asF64: {
3343 /* Given an I64, produce an IEEE754 double with the same
3346 HReg r_srcHi, r_srcLo;
3347 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg);
3348 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3350 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3351 return mk_LoadR64toFPR( env, r_src );
3354 case Iop_F32toF64: {
3355 /* this is a no-op */
3356 HReg res = iselFltExpr(env, e->Iex.Unop.arg);
3364 /* --------- MULTIPLEX --------- */
3365 if (e->tag == Iex_Mux0X) {
3367 && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
3368 PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3369 HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
3370 HReg frX = iselDblExpr(env, e->Iex.Mux0X.exprX);
3371 HReg fr0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
3372 HReg fr_dst = newVRegF(env);
3373 HReg r_tmp = newVRegI(env);
3374 addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp,
3375 r_cond, PPCRH_Imm(False,0xFF)));
3376 addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, frX ));
3377 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3378 7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
3379 addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr0 ));
3384 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
3386 vpanic("iselDblExpr_wrk(ppc)");
3390 /*---------------------------------------------------------*/
3391 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
3392 /*---------------------------------------------------------*/
3394 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
3396 HReg r = iselVecExpr_wrk( env, e );
3398 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3400 vassert(hregClass(r) == HRcVec128);
3401 vassert(hregIsVirtual(r));
3405 /* DO NOT CALL THIS DIRECTLY */
3406 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
3408 Bool mode64 = env->mode64;
3409 PPCAvOp op = Pav_INVALID;
3410 PPCAvFpOp fpop = Pavfp_INVALID;
3411 IRType ty = typeOfIRExpr(env->type_env,e);
3413 vassert(ty == Ity_V128);
3415 if (e->tag == Iex_RdTmp) {
3416 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3419 if (e->tag == Iex_Get) {
3420 /* Guest state vectors are 16byte aligned,
3421 so don't need to worry here */
3422 HReg dst = newVRegV(env);
3424 PPCInstr_AvLdSt( True/*load*/, 16, dst,
3425 PPCAMode_IR( e->Iex.Get.offset,
3426 GuestStatePtr(mode64) )));
3430 if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
3432 HReg v_dst = newVRegV(env);
3433 vassert(e->Iex.Load.ty == Ity_V128);
3434 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_V128/*xfer*/);
3435 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, v_dst, am_addr));
3439 if (e->tag == Iex_Unop) {
3440 switch (e->Iex.Unop.op) {
3443 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3444 HReg dst = newVRegV(env);
3445 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
3449 case Iop_CmpNEZ8x16: {
3450 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3451 HReg zero = newVRegV(env);
3452 HReg dst = newVRegV(env);
3453 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3454 addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
3455 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3459 case Iop_CmpNEZ16x8: {
3460 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3461 HReg zero = newVRegV(env);
3462 HReg dst = newVRegV(env);
3463 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3464 addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
3465 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3469 case Iop_CmpNEZ32x4: {
3470 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3471 HReg zero = newVRegV(env);
3472 HReg dst = newVRegV(env);
3473 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3474 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
3475 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3479 case Iop_Recip32Fx4: fpop = Pavfp_RCPF; goto do_32Fx4_unary;
3480 case Iop_RSqrt32Fx4: fpop = Pavfp_RSQRTF; goto do_32Fx4_unary;
3481 case Iop_I32UtoFx4: fpop = Pavfp_CVTU2F; goto do_32Fx4_unary;
3482 case Iop_I32StoFx4: fpop = Pavfp_CVTS2F; goto do_32Fx4_unary;
3483 case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
3484 case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
3485 case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM; goto do_32Fx4_unary;
3486 case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP; goto do_32Fx4_unary;
3487 case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN; goto do_32Fx4_unary;
3488 case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ; goto do_32Fx4_unary;
3491 HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3492 HReg dst = newVRegV(env);
3493 addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
3497 case Iop_32UtoV128: {
3498 HReg r_aligned16, r_zeros;
3499 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3500 HReg dst = newVRegV(env);
3501 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
3502 sub_from_sp( env, 32 ); // Move SP down
3504 /* Get a quadword aligned address within our stack space */
3505 r_aligned16 = get_sp_aligned16( env );
3506 am_off0 = PPCAMode_IR( 0, r_aligned16 );
3507 am_off4 = PPCAMode_IR( 4, r_aligned16 );
3508 am_off8 = PPCAMode_IR( 8, r_aligned16 );
3509 am_off12 = PPCAMode_IR( 12, r_aligned16 );
3512 r_zeros = newVRegI(env);
3513 addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
3514 addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
3515 addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
3516 addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
3518 /* Store r_src in low word of quadword-aligned mem */
3519 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
3521 /* Load word into low word of quadword vector reg */
3522 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
3524 add_to_sp( env, 32 ); // Reset SP
3531 return mk_AvDuplicateRI(env, e->Iex.Binop.arg1);
3535 } /* switch (e->Iex.Unop.op) */
3536 } /* if (e->tag == Iex_Unop) */
3538 if (e->tag == Iex_Binop) {
3539 switch (e->Iex.Binop.op) {
3541 case Iop_64HLtoV128: {
3543 HReg r3, r2, r1, r0, r_aligned16;
3544 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
3545 HReg dst = newVRegV(env);
3546 /* do this via the stack (easy, convenient, etc) */
3547 sub_from_sp( env, 32 ); // Move SP down
3549 // get a quadword aligned address within our stack space
3550 r_aligned16 = get_sp_aligned16( env );
3551 am_off0 = PPCAMode_IR( 0, r_aligned16 );
3552 am_off4 = PPCAMode_IR( 4, r_aligned16 );
3553 am_off8 = PPCAMode_IR( 8, r_aligned16 );
3554 am_off12 = PPCAMode_IR( 12, r_aligned16 );
3556 /* Do the less significant 64 bits */
3557 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2);
3558 addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
3559 addInstr(env, PPCInstr_Store( 4, am_off8, r1, mode64 ));
3560 /* Do the more significant 64 bits */
3561 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1);
3562 addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
3563 addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
3565 /* Fetch result back from stack. */
3566 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
3568 add_to_sp( env, 32 ); // Reset SP
3571 HReg rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
3572 HReg rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
3573 HReg dst = newVRegV(env);
3575 PPCAMode *am_off0, *am_off8;
3576 /* do this via the stack (easy, convenient, etc) */
3577 sub_from_sp( env, 32 ); // Move SP down
3579 // get a quadword aligned address within our stack space
3580 r_aligned16 = get_sp_aligned16( env );
3581 am_off0 = PPCAMode_IR( 0, r_aligned16 );
3582 am_off8 = PPCAMode_IR( 8, r_aligned16 );
3584 /* Store 2*I64 to stack */
3585 addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
3586 addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
3588 /* Fetch result back from stack. */
3589 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
3591 add_to_sp( env, 32 ); // Reset SP
3596 case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4;
3597 case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4;
3598 case Iop_Max32Fx4: fpop = Pavfp_MAXF; goto do_32Fx4;
3599 case Iop_Min32Fx4: fpop = Pavfp_MINF; goto do_32Fx4;
3600 case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4;
3601 case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
3602 case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
3603 case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
3606 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3607 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3608 HReg dst = newVRegV(env);
3609 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
3613 case Iop_CmpLE32Fx4: {
3614 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3615 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3616 HReg dst = newVRegV(env);
3618 /* stay consistent with native ppc compares:
3619 if a left/right lane holds a nan, return zeros for that lane
3620 so: le == NOT(gt OR isNan)
3622 HReg isNanLR = newVRegV(env);
3623 HReg isNanL = isNan(env, argL);
3624 HReg isNanR = isNan(env, argR);
3625 addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
3628 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
3630 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
3631 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3635 case Iop_AndV128: op = Pav_AND; goto do_AvBin;
3636 case Iop_OrV128: op = Pav_OR; goto do_AvBin;
3637 case Iop_XorV128: op = Pav_XOR; goto do_AvBin;
3639 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3640 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3641 HReg dst = newVRegV(env);
3642 addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
3646 case Iop_Shl8x16: op = Pav_SHL; goto do_AvBin8x16;
3647 case Iop_Shr8x16: op = Pav_SHR; goto do_AvBin8x16;
3648 case Iop_Sar8x16: op = Pav_SAR; goto do_AvBin8x16;
3649 case Iop_Rol8x16: op = Pav_ROTL; goto do_AvBin8x16;
3650 case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16;
3651 case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16;
3652 case Iop_Add8x16: op = Pav_ADDU; goto do_AvBin8x16;
3653 case Iop_QAdd8Ux16: op = Pav_QADDU; goto do_AvBin8x16;
3654 case Iop_QAdd8Sx16: op = Pav_QADDS; goto do_AvBin8x16;
3655 case Iop_Sub8x16: op = Pav_SUBU; goto do_AvBin8x16;
3656 case Iop_QSub8Ux16: op = Pav_QSUBU; goto do_AvBin8x16;
3657 case Iop_QSub8Sx16: op = Pav_QSUBS; goto do_AvBin8x16;
3658 case Iop_Avg8Ux16: op = Pav_AVGU; goto do_AvBin8x16;
3659 case Iop_Avg8Sx16: op = Pav_AVGS; goto do_AvBin8x16;
3660 case Iop_Max8Ux16: op = Pav_MAXU; goto do_AvBin8x16;
3661 case Iop_Max8Sx16: op = Pav_MAXS; goto do_AvBin8x16;
3662 case Iop_Min8Ux16: op = Pav_MINU; goto do_AvBin8x16;
3663 case Iop_Min8Sx16: op = Pav_MINS; goto do_AvBin8x16;
3664 case Iop_MullEven8Ux16: op = Pav_OMULU; goto do_AvBin8x16;
3665 case Iop_MullEven8Sx16: op = Pav_OMULS; goto do_AvBin8x16;
3666 case Iop_CmpEQ8x16: op = Pav_CMPEQU; goto do_AvBin8x16;
3667 case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
3668 case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
3670 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3671 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3672 HReg dst = newVRegV(env);
3673 addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
3677 case Iop_Shl16x8: op = Pav_SHL; goto do_AvBin16x8;
3678 case Iop_Shr16x8: op = Pav_SHR; goto do_AvBin16x8;
3679 case Iop_Sar16x8: op = Pav_SAR; goto do_AvBin16x8;
3680 case Iop_Rol16x8: op = Pav_ROTL; goto do_AvBin16x8;
3681 case Iop_Narrow16x8: op = Pav_PACKUU; goto do_AvBin16x8;
3682 case Iop_QNarrow16Ux8: op = Pav_QPACKUU; goto do_AvBin16x8;
3683 case Iop_QNarrow16Sx8: op = Pav_QPACKSS; goto do_AvBin16x8;
3684 case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8;
3685 case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8;
3686 case Iop_Add16x8: op = Pav_ADDU; goto do_AvBin16x8;
3687 case Iop_QAdd16Ux8: op = Pav_QADDU; goto do_AvBin16x8;
3688 case Iop_QAdd16Sx8: op = Pav_QADDS; goto do_AvBin16x8;
3689 case Iop_Sub16x8: op = Pav_SUBU; goto do_AvBin16x8;
3690 case Iop_QSub16Ux8: op = Pav_QSUBU; goto do_AvBin16x8;
3691 case Iop_QSub16Sx8: op = Pav_QSUBS; goto do_AvBin16x8;
3692 case Iop_Avg16Ux8: op = Pav_AVGU; goto do_AvBin16x8;
3693 case Iop_Avg16Sx8: op = Pav_AVGS; goto do_AvBin16x8;
3694 case Iop_Max16Ux8: op = Pav_MAXU; goto do_AvBin16x8;
3695 case Iop_Max16Sx8: op = Pav_MAXS; goto do_AvBin16x8;
3696 case Iop_Min16Ux8: op = Pav_MINU; goto do_AvBin16x8;
3697 case Iop_Min16Sx8: op = Pav_MINS; goto do_AvBin16x8;
3698 case Iop_MullEven16Ux8: op = Pav_OMULU; goto do_AvBin16x8;
3699 case Iop_MullEven16Sx8: op = Pav_OMULS; goto do_AvBin16x8;
3700 case Iop_CmpEQ16x8: op = Pav_CMPEQU; goto do_AvBin16x8;
3701 case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
3702 case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
3704 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3705 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3706 HReg dst = newVRegV(env);
3707 addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
3711 case Iop_Shl32x4: op = Pav_SHL; goto do_AvBin32x4;
3712 case Iop_Shr32x4: op = Pav_SHR; goto do_AvBin32x4;
3713 case Iop_Sar32x4: op = Pav_SAR; goto do_AvBin32x4;
3714 case Iop_Rol32x4: op = Pav_ROTL; goto do_AvBin32x4;
3715 case Iop_Narrow32x4: op = Pav_PACKUU; goto do_AvBin32x4;
3716 case Iop_QNarrow32Ux4: op = Pav_QPACKUU; goto do_AvBin32x4;
3717 case Iop_QNarrow32Sx4: op = Pav_QPACKSS; goto do_AvBin32x4;
3718 case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4;
3719 case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4;
3720 case Iop_Add32x4: op = Pav_ADDU; goto do_AvBin32x4;
3721 case Iop_QAdd32Ux4: op = Pav_QADDU; goto do_AvBin32x4;
3722 case Iop_QAdd32Sx4: op = Pav_QADDS; goto do_AvBin32x4;
3723 case Iop_Sub32x4: op = Pav_SUBU; goto do_AvBin32x4;
3724 case Iop_QSub32Ux4: op = Pav_QSUBU; goto do_AvBin32x4;
3725 case Iop_QSub32Sx4: op = Pav_QSUBS; goto do_AvBin32x4;
3726 case Iop_Avg32Ux4: op = Pav_AVGU; goto do_AvBin32x4;
3727 case Iop_Avg32Sx4: op = Pav_AVGS; goto do_AvBin32x4;
3728 case Iop_Max32Ux4: op = Pav_MAXU; goto do_AvBin32x4;
3729 case Iop_Max32Sx4: op = Pav_MAXS; goto do_AvBin32x4;
3730 case Iop_Min32Ux4: op = Pav_MINU; goto do_AvBin32x4;
3731 case Iop_Min32Sx4: op = Pav_MINS; goto do_AvBin32x4;
3732 case Iop_CmpEQ32x4: op = Pav_CMPEQU; goto do_AvBin32x4;
3733 case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
3734 case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
3736 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3737 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3738 HReg dst = newVRegV(env);
3739 addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
3743 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
3744 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
3746 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
3747 HReg dst = newVRegV(env);
3748 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3749 addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
3753 case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
3754 case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
3755 case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
3757 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
3758 HReg dst = newVRegV(env);
3759 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3760 addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
3764 case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
3765 case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
3766 case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
3768 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
3769 HReg dst = newVRegV(env);
3770 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3771 addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
3775 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
3776 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
3778 HReg dst = newVRegV(env);
3779 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1);
3780 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3781 /* Note: shift value gets masked by 127 */
3782 addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
3786 case Iop_Perm8x16: {
3787 HReg dst = newVRegV(env);
3788 HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1);
3789 HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2);
3790 addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
3796 } /* switch (e->Iex.Binop.op) */
3797 } /* if (e->tag == Iex_Binop) */
3799 if (e->tag == Iex_Const ) {
3800 vassert(e->Iex.Const.con->tag == Ico_V128);
3801 if (e->Iex.Const.con->Ico.V128 == 0x0000) {
3802 return generate_zeroes_V128(env);
3804 else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
3805 return generate_ones_V128(env);
3809 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
3810 LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
3813 vpanic("iselVecExpr_wrk(ppc)");
3817 /*---------------------------------------------------------*/
3818 /*--- ISEL: Statements ---*/
3819 /*---------------------------------------------------------*/
3821 static void iselStmt ( ISelEnv* env, IRStmt* stmt )
3823 Bool mode64 = env->mode64;
3824 if (vex_traceflags & VEX_TRACE_VCODE) {
3825 vex_printf("\n -- ");
3830 switch (stmt->tag) {
3832 /* --------- STORE --------- */
3834 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
3835 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3836 IREndness end = stmt->Ist.Store.end;
3840 if (!mode64 && (tya != Ity_I32))
3842 if (mode64 && (tya != Ity_I64))
3845 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
3846 (mode64 && (tyd == Ity_I64))) {
3848 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3849 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
3850 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
3851 am_addr, r_src, mode64 ));
3854 if (tyd == Ity_F64) {
3856 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3857 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
3859 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
3862 if (tyd == Ity_F32) {
3864 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3865 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3867 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
3870 if (tyd == Ity_V128) {
3872 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3873 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data);
3875 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
3878 if (tyd == Ity_I64 && !mode64) {
3879 /* Just calculate the address in the register. Life is too
3880 short to arse around trying and possibly failing to adjust
3881 the offset in a 'reg+offset' style amode. */
3883 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
3884 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data );
3885 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
3886 PPCAMode_IR( 0, r_addr ),
3888 False/*32-bit insn please*/) );
3889 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
3890 PPCAMode_IR( 4, r_addr ),
3892 False/*32-bit insn please*/) );
3898 /* --------- PUT --------- */
3900 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3901 if (ty == Ity_I8 || ty == Ity_I16 ||
3902 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
3903 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
3904 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3905 GuestStatePtr(mode64) );
3906 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
3907 am_addr, r_src, mode64 ));
3910 if (!mode64 && ty == Ity_I64) {
3912 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3913 GuestStatePtr(mode64) );
3914 PPCAMode* am_addr4 = advance4(env, am_addr);
3915 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data);
3916 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
3917 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
3920 if (ty == Ity_V128) {
3921 /* Guest state vectors are 16byte aligned,
3922 so don't need to worry here */
3923 HReg v_src = iselVecExpr(env, stmt->Ist.Put.data);
3924 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3925 GuestStatePtr(mode64) );
3927 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
3930 if (ty == Ity_F64) {
3931 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data);
3932 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3933 GuestStatePtr(mode64) );
3934 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3941 /* --------- Indexed PUT --------- */
3944 = genGuestArrayOffset(
3945 env, stmt->Ist.PutI.descr,
3946 stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
3947 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
3948 if (mode64 && ty == Ity_I64) {
3949 HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data);
3950 addInstr(env, PPCInstr_Store( toUChar(8),
3951 dst_am, r_src, mode64 ));
3954 if ((!mode64) && ty == Ity_I32) {
3955 HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data);
3956 addInstr(env, PPCInstr_Store( toUChar(4),
3957 dst_am, r_src, mode64 ));
3963 /* --------- TMP --------- */
3965 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3966 IRType ty = typeOfIRTemp(env->type_env, tmp);
3967 if (ty == Ity_I8 || ty == Ity_I16 ||
3968 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
3969 HReg r_dst = lookupIRTemp(env, tmp);
3970 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3971 addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
3974 if (!mode64 && ty == Ity_I64) {
3975 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
3976 iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
3977 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
3978 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
3979 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
3982 if (mode64 && ty == Ity_I128) {
3983 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
3984 iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
3985 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
3986 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
3987 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
3991 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
3992 HReg r_dst = lookupIRTemp(env, tmp);
3993 addInstr(env, PPCInstr_Set(cond, r_dst));
3996 if (ty == Ity_F64) {
3997 HReg fr_dst = lookupIRTemp(env, tmp);
3998 HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data);
3999 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
4002 if (ty == Ity_F32) {
4003 HReg fr_dst = lookupIRTemp(env, tmp);
4004 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
4005 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
4008 if (ty == Ity_V128) {
4009 HReg v_dst = lookupIRTemp(env, tmp);
4010 HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data);
4011 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
4017 /* --------- Load Linked or Store Conditional --------- */
4019 IRTemp res = stmt->Ist.LLSC.result;
4020 IRType tyRes = typeOfIRTemp(env->type_env, res);
4021 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
4023 if (stmt->Ist.LLSC.end != Iend_BE)
4025 if (!mode64 && (tyAddr != Ity_I32))
4027 if (mode64 && (tyAddr != Ity_I64))
4030 if (stmt->Ist.LLSC.storedata == NULL) {
4032 HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr );
4033 HReg r_dst = lookupIRTemp(env, res);
4034 if (tyRes == Ity_I32) {
4035 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
4038 if (tyRes == Ity_I64 && mode64) {
4039 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
4045 HReg r_res = lookupIRTemp(env, res); /* :: Ity_I1 */
4046 HReg r_a = iselWordExpr_R(env, stmt->Ist.LLSC.addr);
4047 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
4048 HReg r_tmp = newVRegI(env);
4049 IRType tyData = typeOfIRExpr(env->type_env,
4050 stmt->Ist.LLSC.storedata);
4051 vassert(tyRes == Ity_I1);
4052 if (tyData == Ity_I32 || (tyData == Ity_I64 && mode64)) {
4053 addInstr(env, PPCInstr_StoreC( tyData==Ity_I32 ? 4 : 8,
4054 r_a, r_src, mode64 ));
4055 addInstr(env, PPCInstr_MfCR( r_tmp ));
4056 addInstr(env, PPCInstr_Shft(
4058 env->mode64 ? False : True
4059 /*F:64-bit, T:32-bit shift*/,
4061 PPCRH_Imm(False/*unsigned*/, 29)));
4062 /* Probably unnecessary, since the IR dest type is Ity_I1,
4063 and so we are entitled to leave whatever junk we like
4064 drifting round in the upper 31 or 63 bits of r_res.
4065 However, for the sake of conservativeness .. */
4066 addInstr(env, PPCInstr_Alu(
4069 PPCRH_Imm(False/*signed*/, 1)));
4078 /* --------- Call to DIRTY helper --------- */
4081 IRDirty* d = stmt->Ist.Dirty.details;
4082 Bool passBBP = False;
4084 if (d->nFxState == 0)
4085 vassert(!d->needsBBP);
4086 passBBP = toBool(d->nFxState > 0 && d->needsBBP);
4088 /* Marshal args, do the call, clear stack. */
4089 doHelperCall( env, passBBP, d->guard, d->cee, d->args );
4091 /* Now figure out what to do with the returned value, if any. */
4092 if (d->tmp == IRTemp_INVALID)
4093 /* No return value. Nothing to do. */
4096 retty = typeOfIRTemp(env->type_env, d->tmp);
4097 if (!mode64 && retty == Ity_I64) {
4098 HReg r_dstHi, r_dstLo;
4099 /* The returned value is in %r3:%r4. Park it in the
4100 register-pair associated with tmp. */
4101 lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
4102 addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
4103 addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
4106 if (retty == Ity_I8 || retty == Ity_I16 ||
4107 retty == Ity_I32 || ((retty == Ity_I64) && mode64)) {
4108 /* The returned value is in %r3. Park it in the register
4109 associated with tmp. */
4110 HReg r_dst = lookupIRTemp(env, d->tmp);
4111 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
4117 /* --------- MEM FENCE --------- */
4119 switch (stmt->Ist.MBE.event) {
4121 addInstr(env, PPCInstr_MFence());
4128 /* --------- INSTR MARK --------- */
4129 /* Doesn't generate any executable code ... */
4133 /* --------- ABI HINT --------- */
4134 /* These have no meaning (denotation in the IR) and so we ignore
4135 them ... if any actually made it this far. */
4139 /* --------- NO-OP --------- */
4140 /* Fairly self-explanatory, wouldn't you say? */
4144 /* --------- EXIT --------- */
4148 IRConstTag tag = stmt->Ist.Exit.dst->tag;
4149 if (!mode64 && (tag != Ico_U32))
4150 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
4151 if (mode64 && (tag != Ico_U64))
4152 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
4153 ri_dst = iselWordExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
4154 cc = iselCondCode(env,stmt->Ist.Exit.guard);
4155 addInstr(env, PPCInstr_RdWrLR(True, env->savedLR));
4156 addInstr(env, PPCInstr_Goto(stmt->Ist.Exit.jk, cc, ri_dst));
4164 vpanic("iselStmt(ppc)");
4168 /*---------------------------------------------------------*/
4169 /*--- ISEL: Basic block terminators (Nexts) ---*/
4170 /*---------------------------------------------------------*/
4172 static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
4176 if (vex_traceflags & VEX_TRACE_VCODE) {
4177 vex_printf("\n-- goto {");
4183 cond = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
4184 ri = iselWordExpr_RI(env, next);
4185 addInstr(env, PPCInstr_RdWrLR(True, env->savedLR));
4186 addInstr(env, PPCInstr_Goto(jk, cond, ri));
4190 /*---------------------------------------------------------*/
4191 /*--- Insn selector top-level ---*/
4192 /*---------------------------------------------------------*/
4194 /* Translate an entire BS to ppc code. */
4196 HInstrArray* iselSB_PPC ( IRSB* bb, VexArch arch_host,
4197 VexArchInfo* archinfo_host,
4203 UInt hwcaps_host = archinfo_host->hwcaps;
4204 Bool mode64 = False;
4205 UInt mask32, mask64;
4207 vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
4208 mode64 = arch_host == VexArchPPC64;
4210 /* do some sanity checks */
4211 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
4212 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX;
4214 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
4215 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX;
4218 vassert((hwcaps_host & mask32) == 0);
4220 vassert((hwcaps_host & mask64) == 0);
4223 /* Make up an initial environment to use. */
4224 env = LibVEX_Alloc(sizeof(ISelEnv));
4227 /* Are we being ppc32 or ppc64? */
4228 env->mode64 = mode64;
4230 /* Set up output code array. */
4231 env->code = newHInstrArray();
4233 /* Copy BB's type env. */
4234 env->type_env = bb->tyenv;
4236 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4237 change as we go along. */
4238 env->n_vregmap = bb->tyenv->types_used;
4239 env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4240 env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4242 /* and finally ... */
4243 env->hwcaps = hwcaps_host;
4244 env->previous_rm = NULL;
4247 /* For each IR temporary, allocate a suitably-kinded virtual
4250 for (i = 0; i < env->n_vregmap; i++) {
4251 hregHI = hreg = INVALID_HREG;
4252 switch (bb->tyenv->types[i]) {
4257 if (mode64) { hreg = mkHReg(j++, HRcInt64, True); break;
4258 } else { hreg = mkHReg(j++, HRcInt32, True); break;
4261 if (mode64) { hreg = mkHReg(j++, HRcInt64, True); break;
4262 } else { hreg = mkHReg(j++, HRcInt32, True);
4263 hregHI = mkHReg(j++, HRcInt32, True); break;
4265 case Ity_I128: vassert(mode64);
4266 hreg = mkHReg(j++, HRcInt64, True);
4267 hregHI = mkHReg(j++, HRcInt64, True); break;
4269 case Ity_F64: hreg = mkHReg(j++, HRcFlt64, True); break;
4270 case Ity_V128: hreg = mkHReg(j++, HRcVec128, True); break;
4272 ppIRType(bb->tyenv->types[i]);
4273 vpanic("iselBB(ppc): IRTemp type");
4275 env->vregmap[i] = hreg;
4276 env->vregmapHI[i] = hregHI;
4280 /* Keep a copy of the link reg, so helper functions don't kill it. */
4281 env->savedLR = newVRegI(env);
4282 addInstr(env, PPCInstr_RdWrLR(False, env->savedLR));
4284 /* Ok, finally we can iterate over the statements. */
4285 for (i = 0; i < bb->stmts_used; i++)
4287 iselStmt(env,bb->stmts[i]);
4289 iselNext(env,bb->next,bb->jumpkind);
4291 /* record the number of vregs we used. */
4292 env->code->n_vregs = env->vreg_ctr;
4297 /*---------------------------------------------------------------*/
4298 /*--- end host_ppc_isel.c ---*/
4299 /*---------------------------------------------------------------*/