2 /*---------------------------------------------------------------*/
3 /*--- begin host_ppc_isel.c ---*/
4 /*---------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2004-2017 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_generic_simd64.h"
45 #include "host_ppc_defs.h"
47 /* GPR register class for ppc32/64 */
48 #define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
51 /*---------------------------------------------------------*/
52 /*--- Register Usage Conventions ---*/
53 /*---------------------------------------------------------*/
59 GPR2 not used - TOC pointer
61 GPR11 if mode64: not used - calls by ptr / env ptr for some langs
62 GPR12 if mode64: not used - exceptions / global linkage code
63 GPR13 not used - Thread-specific pointer
65 GPR29 Unused by us (reserved for the dispatcher)
66 GPR30 AltiVec temp spill register
67 GPR31 GuestStatePointer
71 GPR3:10 Caller-saved regs
73 GPR3:12 Caller-saved regs
74 GPR14:29 Callee-saved regs
76 GPR3 [Return | Parameter] - carrying reg
77 GPR4:10 Parameter-carrying regs
84 FPR0 Caller-saved - scratch reg
86 FPR1:13 Caller-saved - param & return regs
88 FPR1:8 Caller-saved - param & return regs
89 FPR9:13 Caller-saved regs
90 FPR14:31 Callee-saved regs
93 Vector Regs (on processors with the VMX feature)
95 VR0-VR1 Volatile scratch registers
96 VR2-VR13 Volatile vector parameters registers
97 VR14-VR19 Volatile scratch registers
98 VR20-VR31 Non-volatile registers
99 VRSAVE Non-volatile 32-bit register
103 /*---------------------------------------------------------*/
104 /*--- PPC FP Status & Control Register Conventions ---*/
105 /*---------------------------------------------------------*/
107 Vex-generated code expects to run with the FPU set as follows: all
108 exceptions masked. The rounding mode is set appropriately before
109 each floating point insn emitted (or left unchanged if known to be
110 correct already). There are a few fp insns (fmr,fneg,fabs,fnabs),
111 which are unaffected by the rm and so the rounding mode is not set
114 At least on MPC7447A (Mac Mini), frsqrte is also not affected by
115 rounding mode. At some point the ppc docs get sufficiently vague
116 that the only way to find out is to write test programs.
118 /* Notes on the FP instruction set, 6 Feb 06.
120 What exns -> CR1 ? Sets FPRF ? Observes RM ?
121 -------------------------------------------------------------
130 fcfid[.] (Si64->dbl) if . y y
131 fcfidU[.] (Ui64->dbl) if . y y
132 fcfids[.] (Si64->sngl) if . Y Y
133 fcfidus[.] (Ui64->sngl) if . Y Y
134 fcmpo (cmp, result n n n
136 fctid[.] (dbl->i64) if . ->undef y
137 fctidz[.] (dbl->i64) if . ->undef rounds-to-zero
138 fctiw[.] (dbl->i32) if . ->undef y
139 fctiwz[.] (dbl->i32) if . ->undef rounds-to-zero
149 (note: for fnm*, rounding happens before final negation)
158 frsqrte[.] if . y apparently not
166 fpscr: bits 30-31 (ibm) is RM
167 24-29 (ibm) are exnmasks/non-IEEE bit, all zero
168 15-19 (ibm) is FPRF: class, <, =, >, UNord
170 ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF
173 mcrfs - move fpscr field to CR field
174 mtfsfi[.] - 4 bit imm moved to fpscr field
175 mtfsf[.] - move frS[low 1/2] to fpscr but using 8-bit field mask
176 mtfsb1[.] - set given fpscr bit
177 mtfsb0[.] - clear given fpscr bit
178 mffs[.] - move all fpscr to frD[low 1/2]
180 For [.] presumably cr1 is set with exn summary bits, as per
183 A single precision store truncates/denormalises the in-register value,
184 but does not round it. This is so that flds followed by fsts is
189 /*---------------------------------------------------------*/
190 /*--- misc helpers ---*/
191 /*---------------------------------------------------------*/
193 /* These are duplicated in guest-ppc/toIR.c */
194 static IRExpr
* unop ( IROp op
, IRExpr
* a
)
196 return IRExpr_Unop(op
, a
);
199 static IRExpr
* mkU32 ( UInt i
)
201 return IRExpr_Const(IRConst_U32(i
));
204 static IRExpr
* bind ( Int binder
)
206 return IRExpr_Binder(binder
);
209 static Bool
isZeroU8 ( IRExpr
* e
)
211 return e
->tag
== Iex_Const
212 && e
->Iex
.Const
.con
->tag
== Ico_U8
213 && e
->Iex
.Const
.con
->Ico
.U8
== 0;
217 /*---------------------------------------------------------*/
219 /*---------------------------------------------------------*/
221 /* This carries around:
223 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
224 might encounter. This is computed before insn selection starts,
227 - A mapping from IRTemp to HReg. This tells the insn selector
228 which virtual register(s) are associated with each IRTemp
229 temporary. This is computed before insn selection starts, and
230 does not change. We expect this mapping to map precisely the
231 same set of IRTemps as the type mapping does.
233 - vregmapLo holds the primary register for the IRTemp.
234 - vregmapMedLo holds the secondary register for the IRTemp,
235 if any is needed. That's only for Ity_I64 temps
236 in 32 bit mode or Ity_I128 temps in 64-bit mode.
237 - vregmapMedHi is only for dealing with Ity_I128 temps in
238 32 bit mode. It holds bits 95:64 (Intel numbering)
240 - vregmapHi is also only for dealing with Ity_I128 temps
241 in 32 bit mode. It holds the most significant bits
242 (127:96 in Intel numbering) of the IRTemp.
244 - The code array, that is, the insns selected so far.
246 - A counter, for generating new virtual registers.
248 - The host subarchitecture we are selecting insns for.
249 This is set at the start and does not change.
251 - A Bool to tell us if the host is 32 or 64bit.
252 This is set at the start and does not change.
254 - An IRExpr*, which may be NULL, holding the IR expression (an
255 IRRoundingMode-encoded value) to which the FPU's rounding mode
256 was most recently set. Setting to NULL is always safe. Used to
257 avoid redundant settings of the FPU's rounding mode, as
258 described in set_FPU_rounding_mode below.
260 - A VexMiscInfo*, needed for knowing how to generate
261 function calls for this target.
263 - The maximum guest address of any guest insn in this block.
264 Actually, the address of the highest-addressed byte from any
265 insn in this block. Is set at the start and does not change.
266 This is used for detecting jumps which are definitely
267 forward-edges from this block, and therefore can be made
268 (chained) to the fast entry point of the destination, thereby
269 avoiding the destination's event check.
274 /* Constant -- are set at the start and do not change. */
276 // 64-bit mode 32-bit mode
277 HReg
* vregmapLo
; // Low 64-bits [63:0] Low 32-bits [31:0]
278 HReg
* vregmapMedLo
; // high 64-bits[127:64] Next 32-bits [63:32]
279 HReg
* vregmapMedHi
; // unused Next 32-bits [95:64]
280 HReg
* vregmapHi
; // unused highest 32-bits [127:96]
283 /* 27 Jan 06: Not currently used, but should be */
288 const VexAbiInfo
* vbi
; // unused
290 Bool chainingAllowed
;
293 /* These are modified as we go along. */
302 static HReg
lookupIRTemp ( ISelEnv
* env
, IRTemp tmp
)
305 vassert(tmp
< env
->n_vregmap
);
306 return env
->vregmapLo
[tmp
];
309 static void lookupIRTempPair ( HReg
* vrHI
, HReg
* vrLO
,
310 ISelEnv
* env
, IRTemp tmp
)
313 vassert(tmp
< env
->n_vregmap
);
314 vassert(! hregIsInvalid(env
->vregmapMedLo
[tmp
]));
315 *vrLO
= env
->vregmapLo
[tmp
];
316 *vrHI
= env
->vregmapMedLo
[tmp
];
319 /* Only for used in 32-bit mode */
320 static void lookupIRTempQuad ( HReg
* vrHi
, HReg
* vrMedHi
, HReg
* vrMedLo
,
321 HReg
* vrLo
, ISelEnv
* env
, IRTemp tmp
)
323 vassert(!env
->mode64
);
325 vassert(tmp
< env
->n_vregmap
);
326 vassert(! hregIsInvalid(env
->vregmapMedLo
[tmp
]));
327 *vrHi
= env
->vregmapHi
[tmp
];
328 *vrMedHi
= env
->vregmapMedHi
[tmp
];
329 *vrMedLo
= env
->vregmapMedLo
[tmp
];
330 *vrLo
= env
->vregmapLo
[tmp
];
333 static void addInstr ( ISelEnv
* env
, PPCInstr
* instr
)
335 addHInstr(env
->code
, instr
);
336 if (vex_traceflags
& VEX_TRACE_VCODE
) {
337 ppPPCInstr(instr
, env
->mode64
);
342 static HReg
newVRegI ( ISelEnv
* env
)
345 = mkHReg(True
/*vreg*/, HRcGPR(env
->mode64
), 0/*enc*/, env
->vreg_ctr
);
350 static HReg
newVRegF ( ISelEnv
* env
)
352 HReg reg
= mkHReg(True
/*vreg*/, HRcFlt64
, 0/*enc*/, env
->vreg_ctr
);
357 static HReg
newVRegV ( ISelEnv
* env
)
359 HReg reg
= mkHReg(True
/*vreg*/, HRcVec128
, 0/*enc*/, env
->vreg_ctr
);
365 /*---------------------------------------------------------*/
366 /*--- ISEL: Forward declarations ---*/
367 /*---------------------------------------------------------*/
369 /* These are organised as iselXXX and iselXXX_wrk pairs. The
370 iselXXX_wrk do the real work, but are not to be called directly.
371 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
372 checks that all returned registers are virtual. You should not
373 call the _wrk version directly.
375 'Word' refers to the size of the native machine word, that is,
376 32-bit int in 32-bit mode and 64-bit int in 64-bit mode. '2Word'
377 therefore refers to a double-width (64/128-bit) quantity in two
380 /* 32-bit mode: compute an I8/I16/I32 into a GPR.
381 64-bit mode: compute an I8/I16/I32/I64 into a GPR. */
382 static HReg
iselWordExpr_R_wrk ( ISelEnv
* env
, const IRExpr
* e
,
383 IREndness IEndianess
);
384 static HReg
iselWordExpr_R ( ISelEnv
* env
, const IRExpr
* e
,
385 IREndness IEndianess
);
387 /* 32-bit mode: Compute an I8/I16/I32 into a RH
388 (reg-or-halfword-immediate).
389 64-bit mode: Compute an I8/I16/I32/I64 into a RH
390 (reg-or-halfword-immediate).
391 It's important to specify whether the immediate is to be regarded
392 as signed or not. If yes, this will never return -32768 as an
393 immediate; this guaranteed that all signed immediates that are
394 return can have their sign inverted if need be.
396 static PPCRH
* iselWordExpr_RH_wrk ( ISelEnv
* env
,
397 Bool syned
, const IRExpr
* e
,
398 IREndness IEndianess
);
399 static PPCRH
* iselWordExpr_RH ( ISelEnv
* env
,
400 Bool syned
, const IRExpr
* e
,
401 IREndness IEndianess
);
403 /* 32-bit mode: compute an I32 into a RI (reg or 32-bit immediate).
404 64-bit mode: compute an I64 into a RI (reg or 64-bit immediate). */
405 static PPCRI
* iselWordExpr_RI_wrk ( ISelEnv
* env
, const IRExpr
* e
,
406 IREndness IEndianess
);
407 static PPCRI
* iselWordExpr_RI ( ISelEnv
* env
, const IRExpr
* e
,
408 IREndness IEndianess
);
410 /* In 32 bit mode ONLY, compute an I8 into a
411 reg-or-5-bit-unsigned-immediate, the latter being an immediate in
412 the range 1 .. 31 inclusive. Used for doing shift amounts. */
413 static PPCRH
* iselWordExpr_RH5u_wrk ( ISelEnv
* env
, const IRExpr
* e
,
414 IREndness IEndianess
);
415 static PPCRH
* iselWordExpr_RH5u ( ISelEnv
* env
, const IRExpr
* e
,
416 IREndness IEndianess
);
418 /* In 64-bit mode ONLY, compute an I8 into a
419 reg-or-6-bit-unsigned-immediate, the latter being an immediate in
420 the range 1 .. 63 inclusive. Used for doing shift amounts. */
421 static PPCRH
* iselWordExpr_RH6u_wrk ( ISelEnv
* env
, const IRExpr
* e
,
422 IREndness IEndianess
);
423 static PPCRH
* iselWordExpr_RH6u ( ISelEnv
* env
, const IRExpr
* e
,
424 IREndness IEndianess
);
426 /* 32-bit mode: compute an I32 into an AMode.
427 64-bit mode: compute an I64 into an AMode.
429 Requires to know (xferTy) the type of data to be loaded/stored
430 using this amode. That is so that, for 64-bit code generation, any
431 PPCAMode_IR returned will have an index (immediate offset) field
432 that is guaranteed to be 4-aligned, if there is any chance that the
433 amode is to be used in ld/ldu/lda/std/stdu.
435 Since there are no such restrictions on 32-bit insns, xferTy is
436 ignored for 32-bit code generation. */
437 static PPCAMode
* iselWordExpr_AMode_wrk ( ISelEnv
* env
, const IRExpr
* e
,
439 IREndness IEndianess
);
440 static PPCAMode
* iselWordExpr_AMode ( ISelEnv
* env
, const IRExpr
* e
,
442 IREndness IEndianess
);
444 static void iselInt128Expr_to_32x4_wrk ( HReg
* rHi
, HReg
* rMedHi
,
445 HReg
* rMedLo
, HReg
* rLo
,
446 ISelEnv
* env
, const IRExpr
* e
,
447 IREndness IEndianess
);
448 static void iselInt128Expr_to_32x4 ( HReg
* rHi
, HReg
* rMedHi
,
449 HReg
* rMedLo
, HReg
* rLo
,
450 ISelEnv
* env
, const IRExpr
* e
,
451 IREndness IEndianess
);
454 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */
455 static void iselInt64Expr_wrk ( HReg
* rHi
, HReg
* rLo
,
456 ISelEnv
* env
, const IRExpr
* e
,
457 IREndness IEndianess
);
458 static void iselInt64Expr ( HReg
* rHi
, HReg
* rLo
,
459 ISelEnv
* env
, const IRExpr
* e
,
460 IREndness IEndianess
);
462 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
463 static void iselInt128Expr_wrk ( HReg
* rHi
, HReg
* rLo
,
464 ISelEnv
* env
, const IRExpr
* e
,
465 IREndness IEndianess
);
467 static void iselInt128Expr ( HReg
* rHi
, HReg
* rLo
,
468 ISelEnv
* env
, const IRExpr
* e
,
469 IREndness IEndianess
);
471 static PPCCondCode
iselCondCode_wrk ( ISelEnv
* env
, const IRExpr
* e
,
472 IREndness IEndianess
);
473 static PPCCondCode
iselCondCode ( ISelEnv
* env
, const IRExpr
* e
,
474 IREndness IEndianess
);
476 static HReg
iselDblExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
477 IREndness IEndianess
);
478 static HReg
iselDblExpr ( ISelEnv
* env
, const IRExpr
* e
,
479 IREndness IEndianess
);
481 static HReg
iselFltExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
482 IREndness IEndianess
);
483 static HReg
iselFltExpr ( ISelEnv
* env
, const IRExpr
* e
,
484 IREndness IEndianess
);
486 static HReg
iselVecExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
487 IREndness IEndianess
);
488 static HReg
iselVecExpr ( ISelEnv
* env
, const IRExpr
* e
,
489 IREndness IEndianess
);
491 /* 64-bit mode ONLY. */
492 static HReg
iselDfp32Expr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
493 IREndness IEndianess
);
494 static HReg
iselDfp32Expr ( ISelEnv
* env
, const IRExpr
* e
,
495 IREndness IEndianess
);
496 static HReg
iselDfp64Expr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
497 IREndness IEndianess
);
498 static HReg
iselDfp64Expr ( ISelEnv
* env
, const IRExpr
* e
,
499 IREndness IEndianess
);
500 static HReg
iselFp128Expr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
501 IREndness IEndianess
);
502 static HReg
iselFp128Expr ( ISelEnv
* env
, const IRExpr
* e
,
503 IREndness IEndianess
);
505 /* 64-bit mode ONLY: compute an D128 into a GPR64 pair. */
506 static void iselDfp128Expr_wrk ( HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
,
507 const IRExpr
* e
, IREndness IEndianess
);
508 static void iselDfp128Expr ( HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
,
509 const IRExpr
* e
, IREndness IEndianess
);
511 /*---------------------------------------------------------*/
512 /*--- ISEL: Misc helpers ---*/
513 /*---------------------------------------------------------*/
515 /* Make an int reg-reg move. */
517 static PPCInstr
* mk_iMOVds_RR ( HReg r_dst
, HReg r_src
)
519 vassert(hregClass(r_dst
) == hregClass(r_src
));
520 vassert(hregClass(r_src
) == HRcInt32
||
521 hregClass(r_src
) == HRcInt64
);
522 return PPCInstr_Alu(Palu_OR
, r_dst
, r_src
, PPCRH_Reg(r_src
));
525 /* Advance/retreat %r1 by n. */
527 static void add_to_sp ( ISelEnv
* env
, UInt n
)
529 HReg sp
= StackFramePtr(env
->mode64
);
530 vassert(n
<= 1024 && (n
%16) == 0);
531 addInstr(env
, PPCInstr_Alu( Palu_ADD
, sp
, sp
,
532 PPCRH_Imm(True
,toUShort(n
)) ));
535 static void sub_from_sp ( ISelEnv
* env
, UInt n
)
537 HReg sp
= StackFramePtr(env
->mode64
);
538 vassert(n
<= 1024 && (n
%16) == 0);
539 addInstr(env
, PPCInstr_Alu( Palu_SUB
, sp
, sp
,
540 PPCRH_Imm(True
,toUShort(n
)) ));
544 returns a quadword aligned address on the stack
545 - copies SP, adds 16bytes, aligns to quadword.
546 use sub_from_sp(32) before calling this,
547 as expects to have 32 bytes to play with.
549 static HReg
get_sp_aligned16 ( ISelEnv
* env
)
551 HReg r
= newVRegI(env
);
552 HReg align16
= newVRegI(env
);
553 addInstr(env
, mk_iMOVds_RR(r
, StackFramePtr(env
->mode64
)));
555 addInstr(env
, PPCInstr_Alu( Palu_ADD
, r
, r
,
556 PPCRH_Imm(True
,toUShort(16)) ));
559 PPCInstr_LI(align16
, 0xFFFFFFFFFFFFFFF0ULL
, env
->mode64
));
560 addInstr(env
, PPCInstr_Alu(Palu_AND
, r
,r
, PPCRH_Reg(align16
)));
566 /* Load 2*I32 regs to fp reg */
567 static HReg
mk_LoadRR32toFPR ( ISelEnv
* env
,
568 HReg r_srcHi
, HReg r_srcLo
)
570 HReg fr_dst
= newVRegF(env
);
571 PPCAMode
*am_addr0
, *am_addr1
;
573 vassert(!env
->mode64
);
574 vassert(hregClass(r_srcHi
) == HRcInt32
);
575 vassert(hregClass(r_srcLo
) == HRcInt32
);
577 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
578 am_addr0
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
579 am_addr1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
581 // store hi,lo as Ity_I32's
582 addInstr(env
, PPCInstr_Store( 4, am_addr0
, r_srcHi
, env
->mode64
));
583 addInstr(env
, PPCInstr_Store( 4, am_addr1
, r_srcLo
, env
->mode64
));
586 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_dst
, am_addr0
));
588 add_to_sp( env
, 16 ); // Reset SP
592 /* Load I64 reg to fp reg */
593 static HReg
mk_LoadR64toFPR ( ISelEnv
* env
, HReg r_src
)
595 HReg fr_dst
= newVRegF(env
);
598 vassert(env
->mode64
);
599 vassert(hregClass(r_src
) == HRcInt64
);
601 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
602 am_addr0
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
605 addInstr(env
, PPCInstr_Store( 8, am_addr0
, r_src
, env
->mode64
));
608 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_dst
, am_addr0
));
610 add_to_sp( env
, 16 ); // Reset SP
615 /* Given an amode, return one which references 4 bytes further
618 static PPCAMode
* advance4 ( ISelEnv
* env
, PPCAMode
* am
)
620 PPCAMode
* am4
= dopyPPCAMode( am
);
621 if (am4
->tag
== Pam_IR
622 && am4
->Pam
.IR
.index
+ 4 <= 32767) {
623 am4
->Pam
.IR
.index
+= 4;
625 vpanic("advance4(ppc,host)");
631 /* Given a guest-state array descriptor, an index expression and a
632 bias, generate a PPCAMode pointing at the relevant piece of
635 PPCAMode
* genGuestArrayOffset ( ISelEnv
* env
, IRRegArray
* descr
,
636 IRExpr
* off
, Int bias
, IREndness IEndianess
)
639 Int elemSz
= sizeofIRType(descr
->elemTy
);
640 Int nElems
= descr
->nElems
;
643 /* Throw out any cases we don't need. In theory there might be a
644 day where we need to handle others, but not today. */
646 if (nElems
!= 16 && nElems
!= 32)
647 vpanic("genGuestArrayOffset(ppc host)(1)");
650 case 4: shift
= 2; break;
651 case 8: shift
= 3; break;
652 default: vpanic("genGuestArrayOffset(ppc host)(2)");
655 if (bias
< -100 || bias
> 100) /* somewhat arbitrarily */
656 vpanic("genGuestArrayOffset(ppc host)(3)");
657 if (descr
->base
< 0 || descr
->base
> 5000) /* somewhat arbitrarily */
658 vpanic("genGuestArrayOffset(ppc host)(4)");
660 /* Compute off into a reg, %off. Then return:
662 addi %tmp, %off, bias (if bias != 0)
665 addi %tmp, %tmp, base
666 ... Baseblockptr + %tmp ...
668 roff
= iselWordExpr_R(env
, off
, IEndianess
);
669 rtmp
= newVRegI(env
);
670 addInstr(env
, PPCInstr_Alu(
673 PPCRH_Imm(True
/*signed*/, toUShort(bias
))));
674 addInstr(env
, PPCInstr_Alu(
677 PPCRH_Imm(False
/*unsigned*/, toUShort(nElems
-1))));
678 addInstr(env
, PPCInstr_Shft(
680 env
->mode64
? False
: True
/*F:64-bit, T:32-bit shift*/,
682 PPCRH_Imm(False
/*unsigned*/, toUShort(shift
))));
683 addInstr(env
, PPCInstr_Alu(
686 PPCRH_Imm(True
/*signed*/, toUShort(descr
->base
))));
688 PPCAMode_RR( GuestStatePtr(env
->mode64
), rtmp
);
692 /*---------------------------------------------------------*/
693 /*--- ISEL: Function call helpers ---*/
694 /*---------------------------------------------------------*/
696 /* Used only in doHelperCall. See big comment in doHelperCall re
697 handling of register-parameter args. This function figures out
698 whether evaluation of an expression might require use of a fixed
699 register. If in doubt return True (safe but suboptimal).
702 Bool
mightRequireFixedRegs ( IRExpr
* e
)
705 case Iex_RdTmp
: case Iex_Const
: case Iex_Get
:
713 /* Do a complete function call. |guard| is a Ity_Bit expression
714 indicating whether or not the call happens. If guard==NULL, the
715 call is unconditional. |retloc| is set to indicate where the
716 return value is after the call. The caller (of this fn) must
717 generate code to add |stackAdjustAfterCall| to the stack pointer
718 after the call is done. */
721 void doHelperCall ( /*OUT*/UInt
* stackAdjustAfterCall
,
722 /*OUT*/RetLoc
* retloc
,
725 IRCallee
* cee
, IRType retTy
, IRExpr
** args
,
726 IREndness IEndianess
)
729 HReg argregs
[PPC_N_REGPARMS
];
730 HReg tmpregs
[PPC_N_REGPARMS
];
732 Int n_args
, i
, argreg
;
734 Bool mode64
= env
->mode64
;
736 /* Set default returns. We'll update them later if needed. */
737 *stackAdjustAfterCall
= 0;
738 *retloc
= mk_RetLoc_INVALID();
740 /* These are used for cross-checking that IR-level constraints on
741 the use of IRExpr_VECRET() and IRExpr_GSPTR() are observed. */
745 /* Marshal args for a call and do the call.
747 This function only deals with a tiny set of possibilities, which
748 cover all helpers in practice. The restrictions are that only
749 arguments in registers are supported, hence only PPC_N_REGPARMS x
750 (mode32:32 | mode64:64) integer bits in total can be passed.
751 In fact the only supported arg type is (mode32:I32 | mode64:I64).
753 The return type can be I{64,32,16,8} or V{128,256}. In the
754 latter two cases, it is expected that |args| will contain the
755 special node IRExpr_VECRET(), in which case this routine
756 generates code to allocate space on the stack for the vector
757 return value. Since we are not passing any scalars on the
758 stack, it is enough to preallocate the return space before
759 marshalling any arguments, in this case.
761 |args| may also contain IRExpr_GSPTR(), in which case the value
762 in the guest state pointer register is passed as the
763 corresponding argument.
765 Generating code which is both efficient and correct when
766 parameters are to be passed in registers is difficult, for the
767 reasons elaborated in detail in comments attached to
768 doHelperCall() in priv/host-x86/isel.c. Here, we use a variant
769 of the method described in those comments.
771 The problem is split into two cases: the fast scheme and the
772 slow scheme. In the fast scheme, arguments are computed
773 directly into the target (real) registers. This is only safe
774 when we can be sure that computation of each argument will not
775 trash any real registers set by computation of any other
778 In the slow scheme, all args are first computed into vregs, and
779 once they are all done, they are moved to the relevant real
780 regs. This always gives correct code, but it also gives a bunch
781 of vreg-to-rreg moves which are usually redundant but are hard
782 for the register allocator to get rid of.
784 To decide which scheme to use, all argument expressions are
785 first examined. If they are all so simple that it is clear they
786 will be evaluated without use of any fixed registers, use the
787 fast scheme, else use the slow scheme. Note also that only
788 unconditional calls may use the fast scheme, since having to
789 compute a condition expression could itself trash real
792 Note this requires being able to examine an expression and
793 determine whether or not evaluation of it might use a fixed
794 register. That requires knowledge of how the rest of this insn
795 selector works. Currently just the following 3 are regarded as
796 safe -- hopefully they cover the majority of arguments in
797 practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
800 /* Note that the cee->regparms field is meaningless on PPC32/64 host
801 (since there is only one calling convention) and so we always
805 for (i
= 0; args
[i
]; i
++)
808 if (n_args
> PPC_N_REGPARMS
) {
809 vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
813 /* This is kind of stupid .. the arrays are sized as PPC_N_REGPARMS
814 but we then assume that that value is 8. */
815 vassert(PPC_N_REGPARMS
== 8);
817 argregs
[0] = hregPPC_GPR3(mode64
);
818 argregs
[1] = hregPPC_GPR4(mode64
);
819 argregs
[2] = hregPPC_GPR5(mode64
);
820 argregs
[3] = hregPPC_GPR6(mode64
);
821 argregs
[4] = hregPPC_GPR7(mode64
);
822 argregs
[5] = hregPPC_GPR8(mode64
);
823 argregs
[6] = hregPPC_GPR9(mode64
);
824 argregs
[7] = hregPPC_GPR10(mode64
);
827 tmpregs
[0] = tmpregs
[1] = tmpregs
[2] =
828 tmpregs
[3] = tmpregs
[4] = tmpregs
[5] =
829 tmpregs
[6] = tmpregs
[7] = INVALID_HREG
;
831 /* First decide which scheme (slow or fast) is to be used. First
832 assume the fast scheme, and select slow if any contraindications
837 /* We'll need space on the stack for the return value. Avoid
838 possible complications with nested calls by using the slow
840 if (retTy
== Ity_V128
|| retTy
== Ity_V256
)
843 if (go_fast
&& guard
) {
844 if (guard
->tag
== Iex_Const
845 && guard
->Iex
.Const
.con
->tag
== Ico_U1
846 && guard
->Iex
.Const
.con
->Ico
.U1
== True
) {
849 /* Not manifestly unconditional -- be conservative. */
855 for (i
= 0; i
< n_args
; i
++) {
856 IRExpr
* arg
= args
[i
];
857 if (UNLIKELY(arg
->tag
== Iex_GSPTR
)) {
860 else if (UNLIKELY(arg
->tag
== Iex_VECRET
)) {
861 /* This implies ill-formed IR, since if the IR was
862 well-formed, the return-type test above would have
864 vpanic("doHelperCall(PPC): invalid IR");
866 else if (mightRequireFixedRegs(arg
)) {
873 /* At this point the scheme to use has been established. Generate
874 code to get the arg values into the argument rregs. */
881 for (i
= 0; i
< n_args
; i
++) {
882 IRExpr
* arg
= args
[i
];
883 vassert(argreg
< PPC_N_REGPARMS
);
885 if (arg
->tag
== Iex_GSPTR
) {
886 argiregs
|= (1 << (argreg
+3));
887 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
],
888 GuestStatePtr(mode64
) ));
891 vassert(arg
->tag
!= Iex_VECRET
);
892 IRType ty
= typeOfIRExpr(env
->type_env
, arg
);
893 vassert(ty
== Ity_I32
|| ty
== Ity_I64
);
896 argiregs
|= (1 << (argreg
+3));
898 mk_iMOVds_RR( argregs
[argreg
],
899 iselWordExpr_R(env
, arg
,
901 } else { // Ity_I64 in 32-bit mode
904 // ppc32 ELF abi spec for passing LONG_LONG
905 argreg
++; // XXX: odd argreg => even rN
906 vassert(argreg
< PPC_N_REGPARMS
-1);
907 iselInt64Expr(&rHi
,&rLo
, env
, arg
, IEndianess
);
908 argiregs
|= (1 << (argreg
+3));
909 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++], rHi
));
910 argiregs
|= (1 << (argreg
+3));
911 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
], rLo
));
914 argiregs
|= (1 << (argreg
+3));
915 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
],
916 iselWordExpr_R(env
, arg
,
920 } /* if (arg == IRExprP__BBPR) */
923 /* Fast scheme only applies for unconditional calls. Hence: */
924 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
928 /* SLOW SCHEME; move via temporaries */
931 /* If we have a vector return type, allocate a place for it on
932 the stack and record its address. Rather than figure out the
933 complexities of PPC{32,64} ELF ABI stack frame layout, simply
934 drop the SP by 1024 and allocate the return point in the
935 middle. I think this should comfortably clear any ABI
936 mandated register save areas. Note that it doesn't maintain
937 the backchain as it should, since we're not doing st{d,w}u to
938 adjust the SP, but .. that doesn't seem to be a big deal.
939 Since we're not expecting to have to unwind out of here. */
940 HReg r_vecRetAddr
= INVALID_HREG
;
941 if (retTy
== Ity_V128
) {
942 r_vecRetAddr
= newVRegI(env
);
943 sub_from_sp(env
, 512);
944 addInstr(env
, mk_iMOVds_RR( r_vecRetAddr
, StackFramePtr(mode64
) ));
945 sub_from_sp(env
, 512);
947 else if (retTy
== Ity_V256
) {
949 r_vecRetAddr
= newVRegI(env
);
950 sub_from_sp(env
, 512);
951 addInstr(env
, mk_iMOVds_RR( r_vecRetAddr
, StackFramePtr(mode64
) ));
952 sub_from_sp(env
, 512);
955 vassert(n_args
>= 0 && n_args
<= 8);
956 for (i
= 0; i
< n_args
; i
++) {
957 IRExpr
* arg
= args
[i
];
958 vassert(argreg
< PPC_N_REGPARMS
);
959 if (UNLIKELY(arg
->tag
== Iex_GSPTR
)) {
960 tmpregs
[argreg
] = newVRegI(env
);
961 addInstr(env
, mk_iMOVds_RR( tmpregs
[argreg
],
962 GuestStatePtr(mode64
) ));
965 else if (UNLIKELY(arg
->tag
== Iex_VECRET
)) {
966 /* We stashed the address of the return slot earlier, so just
968 vassert(!hregIsInvalid(r_vecRetAddr
));
969 tmpregs
[i
] = r_vecRetAddr
;
973 IRType ty
= typeOfIRExpr(env
->type_env
, arg
);
974 vassert(ty
== Ity_I32
|| ty
== Ity_I64
);
977 tmpregs
[argreg
] = iselWordExpr_R(env
, arg
, IEndianess
);
978 } else { // Ity_I64 in 32-bit mode
981 // ppc32 ELF abi spec for passing LONG_LONG
982 argreg
++; // XXX: odd argreg => even rN
983 vassert(argreg
< PPC_N_REGPARMS
-1);
984 iselInt64Expr(&rHi
,&rLo
, env
, arg
, IEndianess
);
985 tmpregs
[argreg
++] = rHi
;
986 tmpregs
[argreg
] = rLo
;
989 tmpregs
[argreg
] = iselWordExpr_R(env
, arg
, IEndianess
);
995 /* Now we can compute the condition. We can't do it earlier
996 because the argument computations could trash the condition
997 codes. Be a bit clever to handle the common case where the
999 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
1001 if (guard
->tag
== Iex_Const
1002 && guard
->Iex
.Const
.con
->tag
== Ico_U1
1003 && guard
->Iex
.Const
.con
->Ico
.U1
== True
) {
1004 /* unconditional -- do nothing */
1006 cc
= iselCondCode( env
, guard
, IEndianess
);
1010 /* Move the args to their final destinations. */
1011 for (i
= 0; i
< argreg
; i
++) {
1012 if (hregIsInvalid(tmpregs
[i
])) // Skip invalid regs
1014 /* None of these insns, including any spill code that might
1015 be generated, may alter the condition codes. */
1016 argiregs
|= (1 << (i
+3));
1017 addInstr( env
, mk_iMOVds_RR( argregs
[i
], tmpregs
[i
] ) );
1022 /* Do final checks, set the return values, and generate the call
1023 instruction proper. */
1024 if (retTy
== Ity_V128
|| retTy
== Ity_V256
) {
1025 vassert(nVECRETs
== 1);
1027 vassert(nVECRETs
== 0);
1030 vassert(nGSPTRs
== 0 || nGSPTRs
== 1);
1032 vassert(*stackAdjustAfterCall
== 0);
1033 vassert(is_RetLoc_INVALID(*retloc
));
1036 /* Function doesn't return a value. */
1037 *retloc
= mk_RetLoc_simple(RLPri_None
);
1040 *retloc
= mk_RetLoc_simple(mode64
? RLPri_Int
: RLPri_2Int
);
1042 case Ity_I32
: case Ity_I16
: case Ity_I8
:
1043 *retloc
= mk_RetLoc_simple(RLPri_Int
);
1046 /* Result is 512 bytes up the stack, and after it has been
1047 retrieved, adjust SP upwards by 1024. */
1048 *retloc
= mk_RetLoc_spRel(RLPri_V128SpRel
, 512);
1049 *stackAdjustAfterCall
= 1024;
1054 *retloc
= mk_RetLoc_spRel(RLPri_V256SpRel
, 512);
1055 *stackAdjustAfterCall
= 1024;
1058 /* IR can denote other possible return types, but we don't
1059 handle those here. */
1063 /* Finally, generate the call itself. This needs the *retloc value
1064 set in the switch above, which is why it's at the end. */
1066 Addr64 target
= mode64
? (Addr
)cee
->addr
1067 : toUInt((Addr
)(cee
->addr
));
1068 addInstr(env
, PPCInstr_Call( cc
, target
, argiregs
, *retloc
));
1072 /*---------------------------------------------------------*/
1073 /*--- ISEL: FP rounding mode helpers ---*/
1074 /*---------------------------------------------------------*/
1076 ///* Set FPU's rounding mode to the default */
1078 //void set_FPU_rounding_default ( ISelEnv* env )
1080 // HReg fr_src = newVRegF(env);
1081 // HReg r_src = newVRegI(env);
1083 // /* Default rounding mode = 0x0
1084 // Only supporting the rounding-mode bits - the rest of FPSCR is 0x0
1085 // - so we can set the whole register at once (faster)
1086 // note: upper 32 bits ignored by FpLdFPSCR
1088 // addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64));
1089 // if (env->mode64) {
1090 // fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
1092 // fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1094 // addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
1097 /* Convert IR rounding mode to PPC encoding */
1098 static HReg
roundModeIRtoPPC ( ISelEnv
* env
, HReg r_rmIR
)
1101 rounding mode | PPC | IR
1102 -----------------------------------------------
1103 to nearest, ties to even | 000 | 000
1105 to +infinity | 010 | 010
1106 to -infinity | 011 | 001
1107 +++++ Below are the extended rounding modes for decimal floating point +++++
1108 to nearest, ties away from 0 | 100 | 100
1109 to nearest, ties toward 0 | 101 | 111
1110 to away from 0 | 110 | 110
1111 to prepare for shorter precision | 111 | 101
1113 HReg r_rmPPC
= newVRegI(env
);
1114 HReg r_tmp1
= newVRegI(env
);
1115 HReg r_tmp2
= newVRegI(env
);
1117 vassert(hregClass(r_rmIR
) == HRcGPR(env
->mode64
));
1119 // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3
1121 // slwi tmp1, r_rmIR, 1
1122 // xor tmp1, r_rmIR, tmp1
1123 // andi r_rmPPC, tmp1, 3
1125 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
1126 r_tmp1
, r_rmIR
, PPCRH_Imm(False
,1)));
1128 addInstr( env
, PPCInstr_Alu( Palu_AND
,
1129 r_tmp2
, r_tmp1
, PPCRH_Imm( False
, 3 ) ) );
1131 addInstr( env
, PPCInstr_Alu( Palu_XOR
,
1132 r_rmPPC
, r_rmIR
, PPCRH_Reg( r_tmp2
) ) );
1138 /* Set the FPU's rounding mode: 'mode' is an I32-typed expression
1139 denoting a value in the range 0 .. 7, indicating a round mode
1140 encoded as per type IRRoundingMode. Set the PPC FPSCR to have the
1141 same rounding. When the dfp_rm arg is True, set the decimal
1142 floating point rounding mode bits (29:31); otherwise, set the
1143 binary floating point rounding mode bits (62:63).
1145 For speed & simplicity, we're setting the *entire* FPSCR here.
1147 Setting the rounding mode is expensive. So this function tries to
1148 avoid repeatedly setting the rounding mode to the same thing by
1149 first comparing 'mode' to the 'mode' tree supplied in the previous
1150 call to this function, if any. (The previous value is stored in
1151 env->previous_rm.) If 'mode' is a single IR temporary 't' and
1152 env->previous_rm is also just 't', then the setting is skipped.
1154 This is safe because of the SSA property of IR: an IR temporary can
1155 only be defined once and so will have the same value regardless of
1156 where it appears in the block. Cool stuff, SSA.
1158 A safety condition: all attempts to set the RM must be aware of
1159 this mechanism - by being routed through the functions here.
1161 Of course this only helps if blocks where the RM is set more than
1162 once and it is set to the same value each time, *and* that value is
1163 held in the same IR temporary each time. In order to assure the
1164 latter as much as possible, the IR optimiser takes care to do CSE
1165 on any block with any sign of floating point activity.
1168 void _set_FPU_rounding_mode ( ISelEnv
* env
, IRExpr
* mode
, Bool dfp_rm
,
1169 IREndness IEndianess
)
1171 HReg fr_src
= newVRegF(env
);
1174 vassert(typeOfIRExpr(env
->type_env
,mode
) == Ity_I32
);
1176 /* Do we need to do anything? */
1177 if (env
->previous_rm
1178 && env
->previous_rm
->tag
== Iex_RdTmp
1179 && mode
->tag
== Iex_RdTmp
1180 && env
->previous_rm
->Iex
.RdTmp
.tmp
== mode
->Iex
.RdTmp
.tmp
) {
1181 /* no - setting it to what it was before. */
1182 vassert(typeOfIRExpr(env
->type_env
, env
->previous_rm
) == Ity_I32
);
1186 /* No luck - we better set it, and remember what we set it to. */
1187 env
->previous_rm
= mode
;
1189 /* Only supporting the rounding-mode bits - the rest of FPSCR is
1190 0x0 - so we can set the whole register at once (faster). */
1192 // Resolve rounding mode and convert to PPC representation
1193 r_src
= roundModeIRtoPPC( env
, iselWordExpr_R(env
, mode
, IEndianess
) );
1198 HReg r_tmp1
= newVRegI( env
);
1200 PPCInstr_Shft( Pshft_SHL
, False
/*64bit shift*/,
1201 r_tmp1
, r_src
, PPCRH_Imm( False
, 32 ) ) );
1202 fr_src
= mk_LoadR64toFPR( env
, r_tmp1
);
1204 fr_src
= mk_LoadR64toFPR( env
, r_src
); // 1*I64 -> F64
1208 HReg r_zero
= newVRegI( env
);
1209 addInstr( env
, PPCInstr_LI( r_zero
, 0, env
->mode64
) );
1210 fr_src
= mk_LoadRR32toFPR( env
, r_src
, r_zero
);
1212 fr_src
= mk_LoadRR32toFPR( env
, r_src
, r_src
); // 2*I32 -> F64
1217 addInstr(env
, PPCInstr_FpLdFPSCR( fr_src
, dfp_rm
));
1220 static void set_FPU_rounding_mode ( ISelEnv
* env
, IRExpr
* mode
,
1221 IREndness IEndianess
)
1223 _set_FPU_rounding_mode(env
, mode
, False
, IEndianess
);
1226 static void set_FPU_DFP_rounding_mode ( ISelEnv
* env
, IRExpr
* mode
,
1227 IREndness IEndianess
)
1229 _set_FPU_rounding_mode(env
, mode
, True
, IEndianess
);
1233 Bool
FPU_rounding_mode_isOdd (IRExpr
* mode
) {
1234 /* If the rounding mode is set to odd, the the expr must be a constant U8
1235 * value equal to 8. Otherwise, it must be a bin op expressiong that
1236 * calculates the value.
1239 if (mode
->tag
!= Iex_Const
)
1242 vassert(mode
->Iex
.Const
.con
->tag
== Ico_U32
);
1243 vassert(mode
->Iex
.Const
.con
->Ico
.U32
== 0x8);
1247 /*---------------------------------------------------------*/
1248 /*--- ISEL: vector helpers ---*/
1249 /*---------------------------------------------------------*/
1251 /* Generate all-zeroes into a new vector register.
1253 static HReg
generate_zeroes_V128 ( ISelEnv
* env
)
1255 HReg dst
= newVRegV(env
);
1256 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, dst
, dst
, dst
));
1260 /* Generate all-ones into a new vector register.
1262 static HReg
generate_ones_V128 ( ISelEnv
* env
)
1264 HReg dst
= newVRegV(env
);
1265 PPCVI5s
* src
= PPCVI5s_Imm(-1);
1266 addInstr(env
, PPCInstr_AvSplat(8, dst
, src
));
1272 Generates code for AvSplat
1273 - takes in IRExpr* of type 8|16|32
1274 returns vector reg of duplicated lanes of input
1275 - uses AvSplat(imm) for imms up to simm6.
1276 otherwise must use store reg & load vector
1278 static HReg
mk_AvDuplicateRI( ISelEnv
* env
, IRExpr
* e
, IREndness IEndianess
)
1281 HReg dst
= newVRegV(env
);
1282 PPCRI
* ri
= iselWordExpr_RI(env
, e
, IEndianess
);
1283 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
1284 UInt sz
= (ty
== Ity_I8
) ? 8 : (ty
== Ity_I16
) ? 16 : 32;
1285 vassert(ty
== Ity_I8
|| ty
== Ity_I16
|| ty
== Ity_I32
);
1287 /* special case: immediate */
1288 if (ri
->tag
== Pri_Imm
) {
1289 Int simm32
= (Int
)ri
->Pri
.Imm
;
1291 /* figure out if it's do-able with imm splats. */
1292 if (simm32
>= -32 && simm32
<= 31) {
1293 Char simm6
= (Char
)simm32
;
1294 if (simm6
> 15) { /* 16:31 inclusive */
1295 HReg v1
= newVRegV(env
);
1296 HReg v2
= newVRegV(env
);
1297 addInstr(env
, PPCInstr_AvSplat(sz
, v1
, PPCVI5s_Imm(-16)));
1298 addInstr(env
, PPCInstr_AvSplat(sz
, v2
, PPCVI5s_Imm(simm6
-16)));
1300 (sz
== 8) ? PPCInstr_AvBin8x16(Pav_SUBU
, dst
, v2
, v1
) :
1301 (sz
==16) ? PPCInstr_AvBin16x8(Pav_SUBU
, dst
, v2
, v1
)
1302 : PPCInstr_AvBin32x4(Pav_SUBU
, dst
, v2
, v1
) );
1305 if (simm6
< -16) { /* -32:-17 inclusive */
1306 HReg v1
= newVRegV(env
);
1307 HReg v2
= newVRegV(env
);
1308 addInstr(env
, PPCInstr_AvSplat(sz
, v1
, PPCVI5s_Imm(-16)));
1309 addInstr(env
, PPCInstr_AvSplat(sz
, v2
, PPCVI5s_Imm(simm6
+16)));
1311 (sz
== 8) ? PPCInstr_AvBin8x16(Pav_ADDU
, dst
, v2
, v1
) :
1312 (sz
==16) ? PPCInstr_AvBin16x8(Pav_ADDU
, dst
, v2
, v1
)
1313 : PPCInstr_AvBin32x4(Pav_ADDU
, dst
, v2
, v1
) );
1316 /* simplest form: -16:15 inclusive */
1317 addInstr(env
, PPCInstr_AvSplat(sz
, dst
, PPCVI5s_Imm(simm6
)));
1321 /* no luck; use the Slow way. */
1322 r_src
= newVRegI(env
);
1323 addInstr(env
, PPCInstr_LI(r_src
, (Long
)simm32
, env
->mode64
));
1326 r_src
= ri
->Pri
.Reg
;
1330 /* Store r_src multiple times (sz dependent); then load the dest vector. */
1332 PPCAMode
*am_offset
, *am_offset_zero
;
1334 sub_from_sp( env
, 32 ); // Move SP down
1335 /* Get a 16-aligned address within our stack space */
1336 r_aligned16
= get_sp_aligned16( env
);
1339 Int stride
= (sz
== 8) ? 1 : (sz
== 16) ? 2 : 4;
1340 UChar num_bytes_to_store
= stride
;
1341 am_offset_zero
= PPCAMode_IR( 0, r_aligned16
);
1342 am_offset
= am_offset_zero
;
1343 for (i
= 0; i
< 16; i
+=stride
, am_offset
= PPCAMode_IR( i
, r_aligned16
)) {
1344 addInstr(env
, PPCInstr_Store( num_bytes_to_store
, am_offset
, r_src
, env
->mode64
));
1347 /* Effectively splat the r_src value to dst */
1348 addInstr(env
, PPCInstr_AvLdSt( True
/*ld*/, 16, dst
, am_offset_zero
) );
1349 add_to_sp( env
, 32 ); // Reset SP
1356 /* for each lane of vSrc: lane == nan ? laneX = all 1's : all 0's */
1357 static HReg
isNan ( ISelEnv
* env
, HReg vSrc
, IREndness IEndianess
)
1359 HReg zeros
, msk_exp
, msk_mnt
, expt
, mnts
, vIsNan
;
1361 vassert(hregClass(vSrc
) == HRcVec128
);
1363 zeros
= mk_AvDuplicateRI(env
, mkU32(0), IEndianess
);
1364 msk_exp
= mk_AvDuplicateRI(env
, mkU32(0x7F800000), IEndianess
);
1365 msk_mnt
= mk_AvDuplicateRI(env
, mkU32(0x7FFFFF), IEndianess
);
1366 expt
= newVRegV(env
);
1367 mnts
= newVRegV(env
);
1368 vIsNan
= newVRegV(env
);
1370 /* 32bit float => sign(1) | exponent(8) | mantissa(23)
1371 nan => exponent all ones, mantissa > 0 */
1373 addInstr(env
, PPCInstr_AvBinary(Pav_AND
, expt
, vSrc
, msk_exp
));
1374 addInstr(env
, PPCInstr_AvBin32x4(Pav_CMPEQU
, expt
, expt
, msk_exp
));
1375 addInstr(env
, PPCInstr_AvBinary(Pav_AND
, mnts
, vSrc
, msk_mnt
));
1376 addInstr(env
, PPCInstr_AvBin32x4(Pav_CMPGTU
, mnts
, mnts
, zeros
));
1377 addInstr(env
, PPCInstr_AvBinary(Pav_AND
, vIsNan
, expt
, mnts
));
1382 /*---------------------------------------------------------*/
1383 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
1384 /*---------------------------------------------------------*/
1386 /* Select insns for an integer-typed expression, and add them to the
1387 code list. Return a reg holding the result. This reg will be a
1388 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
1389 want to modify it, ask for a new vreg, copy it in there, and modify
1390 the copy. The register allocator will do its best to map both
1391 vregs to the same real register, so the copies will often disappear
1394 This should handle expressions of 64, 32, 16 and 8-bit type.
1395 All results are returned in a (mode64 ? 64bit : 32bit) register.
1396 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1397 are arbitrary, so you should mask or sign extend partial values
1401 static HReg
iselWordExpr_R ( ISelEnv
* env
, const IRExpr
* e
,
1402 IREndness IEndianess
)
1404 HReg r
= iselWordExpr_R_wrk(env
, e
, IEndianess
);
1405 /* sanity checks ... */
1407 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
1410 vassert(hregClass(r
) == HRcGPR(env
->mode64
));
1411 vassert(hregIsVirtual(r
));
1415 /* DO NOT CALL THIS DIRECTLY ! */
1416 static HReg
iselWordExpr_R_wrk ( ISelEnv
* env
, const IRExpr
* e
,
1417 IREndness IEndianess
)
1419 Bool mode64
= env
->mode64
;
1421 DECLARE_PATTERN(p_32to1_then_1Uto8
);
1423 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
1424 vassert(ty
== Ity_I8
|| ty
== Ity_I16
||
1425 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
));
1429 /* --------- TEMP --------- */
1431 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
1433 /* --------- LOAD --------- */
1437 if (e
->Iex
.Load
.end
!= IEndianess
)
1439 r_dst
= newVRegI(env
);
1440 am_addr
= iselWordExpr_AMode( env
, e
->Iex
.Load
.addr
, ty
/*of xfer*/,
1442 addInstr(env
, PPCInstr_Load( toUChar(sizeofIRType(ty
)),
1443 r_dst
, am_addr
, mode64
));
1448 /* --------- BINARY OP --------- */
1453 /* Is it an addition or logical style op? */
1454 switch (e
->Iex
.Binop
.op
) {
1455 case Iop_Add8
: case Iop_Add16
: case Iop_Add32
: case Iop_Add64
:
1456 aluOp
= Palu_ADD
; break;
1457 case Iop_Sub8
: case Iop_Sub16
: case Iop_Sub32
: case Iop_Sub64
:
1458 aluOp
= Palu_SUB
; break;
1459 case Iop_And8
: case Iop_And16
: case Iop_And32
: case Iop_And64
:
1460 aluOp
= Palu_AND
; break;
1461 case Iop_Or8
: case Iop_Or16
: case Iop_Or32
: case Iop_Or64
:
1462 aluOp
= Palu_OR
; break;
1463 case Iop_Xor8
: case Iop_Xor16
: case Iop_Xor32
: case Iop_Xor64
:
1464 aluOp
= Palu_XOR
; break;
1466 aluOp
= Palu_INVALID
; break;
1468 /* For commutative ops we assume any literal
1469 values are on the second operand. */
1470 if (aluOp
!= Palu_INVALID
) {
1471 HReg r_dst
= newVRegI(env
);
1472 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1473 PPCRH
* ri_srcR
= NULL
;
1474 /* get right arg into an RH, in the appropriate way */
1476 case Palu_ADD
: case Palu_SUB
:
1477 ri_srcR
= iselWordExpr_RH(env
, True
/*signed*/,
1478 e
->Iex
.Binop
.arg2
, IEndianess
);
1480 case Palu_AND
: case Palu_OR
: case Palu_XOR
:
1481 ri_srcR
= iselWordExpr_RH(env
, False
/*signed*/,
1482 e
->Iex
.Binop
.arg2
, IEndianess
);
1485 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
1487 addInstr(env
, PPCInstr_Alu(aluOp
, r_dst
, r_srcL
, ri_srcR
));
1492 switch (e
->Iex
.Binop
.op
) {
1493 case Iop_Shl8
: case Iop_Shl16
: case Iop_Shl32
: case Iop_Shl64
:
1494 shftOp
= Pshft_SHL
; break;
1495 case Iop_Shr8
: case Iop_Shr16
: case Iop_Shr32
: case Iop_Shr64
:
1496 shftOp
= Pshft_SHR
; break;
1497 case Iop_Sar8
: case Iop_Sar16
: case Iop_Sar32
: case Iop_Sar64
:
1498 shftOp
= Pshft_SAR
; break;
1500 shftOp
= Pshft_INVALID
; break;
1502 /* we assume any literal values are on the second operand. */
1503 if (shftOp
!= Pshft_INVALID
) {
1504 HReg r_dst
= newVRegI(env
);
1505 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1506 PPCRH
* ri_srcR
= NULL
;
1507 /* get right arg into an RH, in the appropriate way */
1509 case Pshft_SHL
: case Pshft_SHR
: case Pshft_SAR
:
1511 ri_srcR
= iselWordExpr_RH5u(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1513 ri_srcR
= iselWordExpr_RH6u(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1516 vpanic("iselIntExpr_R_wrk-shftOp-arg2");
1518 /* widen the left arg if needed */
1519 if (shftOp
== Pshft_SHR
|| shftOp
== Pshft_SAR
) {
1520 if (ty
== Ity_I8
|| ty
== Ity_I16
) {
1521 PPCRH
* amt
= PPCRH_Imm(False
,
1522 toUShort(ty
== Ity_I8
? 24 : 16));
1523 HReg tmp
= newVRegI(env
);
1524 addInstr(env
, PPCInstr_Shft(Pshft_SHL
,
1525 True
/*32bit shift*/,
1527 addInstr(env
, PPCInstr_Shft(shftOp
,
1528 True
/*32bit shift*/,
1533 /* Only 64 expressions need 64bit shifts,
1534 32bit shifts are fine for all others */
1535 if (ty
== Ity_I64
) {
1537 addInstr(env
, PPCInstr_Shft(shftOp
, False
/*64bit shift*/,
1538 r_dst
, r_srcL
, ri_srcR
));
1540 addInstr(env
, PPCInstr_Shft(shftOp
, True
/*32bit shift*/,
1541 r_dst
, r_srcL
, ri_srcR
));
1546 /* How about a div? */
1547 if (e
->Iex
.Binop
.op
== Iop_DivS32
||
1548 e
->Iex
.Binop
.op
== Iop_DivU32
||
1549 e
->Iex
.Binop
.op
== Iop_DivS32E
||
1550 e
->Iex
.Binop
.op
== Iop_DivU32E
) {
1551 Bool syned
= toBool((e
->Iex
.Binop
.op
== Iop_DivS32
) || (e
->Iex
.Binop
.op
== Iop_DivS32E
));
1552 HReg r_dst
= newVRegI(env
);
1553 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1554 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1556 PPCInstr_Div( ( ( e
->Iex
.Binop
.op
== Iop_DivU32E
)
1557 || ( e
->Iex
.Binop
.op
== Iop_DivS32E
) ) ? True
1566 if (e
->Iex
.Binop
.op
== Iop_DivS64
||
1567 e
->Iex
.Binop
.op
== Iop_DivU64
|| e
->Iex
.Binop
.op
== Iop_DivS64E
1568 || e
->Iex
.Binop
.op
== Iop_DivU64E
) {
1569 Bool syned
= toBool((e
->Iex
.Binop
.op
== Iop_DivS64
) ||(e
->Iex
.Binop
.op
== Iop_DivS64E
));
1570 HReg r_dst
= newVRegI(env
);
1571 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1572 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1575 PPCInstr_Div( ( ( e
->Iex
.Binop
.op
== Iop_DivS64E
)
1576 || ( e
->Iex
.Binop
.op
1577 == Iop_DivU64E
) ) ? True
1587 /* No? Anyone for a mul? */
1588 if (e
->Iex
.Binop
.op
== Iop_Mul32
1589 || e
->Iex
.Binop
.op
== Iop_Mul64
) {
1591 Bool sz32
= (e
->Iex
.Binop
.op
!= Iop_Mul64
);
1592 HReg r_dst
= newVRegI(env
);
1593 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1594 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1595 addInstr(env
, PPCInstr_MulL(syned
, False
/*lo32*/, sz32
,
1596 r_dst
, r_srcL
, r_srcR
));
1600 /* 32 x 32 -> 64 multiply */
1602 && (e
->Iex
.Binop
.op
== Iop_MullU32
1603 || e
->Iex
.Binop
.op
== Iop_MullS32
)) {
1604 HReg tLo
= newVRegI(env
);
1605 HReg tHi
= newVRegI(env
);
1606 HReg r_dst
= newVRegI(env
);
1607 Bool syned
= toBool(e
->Iex
.Binop
.op
== Iop_MullS32
);
1608 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1609 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1610 addInstr(env
, PPCInstr_MulL(False
/*signedness irrelevant*/,
1611 False
/*lo32*/, True
/*32bit mul*/,
1612 tLo
, r_srcL
, r_srcR
));
1613 addInstr(env
, PPCInstr_MulL(syned
,
1614 True
/*hi32*/, True
/*32bit mul*/,
1615 tHi
, r_srcL
, r_srcR
));
1616 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, False
/*64bit shift*/,
1617 r_dst
, tHi
, PPCRH_Imm(False
,32)));
1618 addInstr(env
, PPCInstr_Alu(Palu_OR
,
1619 r_dst
, r_dst
, PPCRH_Reg(tLo
)));
1623 /* El-mutanto 3-way compare? */
1624 if (e
->Iex
.Binop
.op
== Iop_CmpORD32S
1625 || e
->Iex
.Binop
.op
== Iop_CmpORD32U
) {
1626 Bool syned
= toBool(e
->Iex
.Binop
.op
== Iop_CmpORD32S
);
1627 HReg dst
= newVRegI(env
);
1628 HReg srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1629 PPCRH
* srcR
= iselWordExpr_RH(env
, syned
, e
->Iex
.Binop
.arg2
,
1631 addInstr(env
, PPCInstr_Cmp(syned
, True
/*32bit cmp*/,
1632 7/*cr*/, srcL
, srcR
));
1633 addInstr(env
, PPCInstr_MfCR(dst
));
1634 addInstr(env
, PPCInstr_Alu(Palu_AND
, dst
, dst
,
1635 PPCRH_Imm(False
,7<<1)));
1639 if (e
->Iex
.Binop
.op
== Iop_CmpORD64S
1640 || e
->Iex
.Binop
.op
== Iop_CmpORD64U
) {
1641 Bool syned
= toBool(e
->Iex
.Binop
.op
== Iop_CmpORD64S
);
1642 HReg dst
= newVRegI(env
);
1643 HReg srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1644 PPCRH
* srcR
= iselWordExpr_RH(env
, syned
, e
->Iex
.Binop
.arg2
,
1647 addInstr(env
, PPCInstr_Cmp(syned
, False
/*64bit cmp*/,
1648 7/*cr*/, srcL
, srcR
));
1649 addInstr(env
, PPCInstr_MfCR(dst
));
1650 addInstr(env
, PPCInstr_Alu(Palu_AND
, dst
, dst
,
1651 PPCRH_Imm(False
,7<<1)));
1655 if (e
->Iex
.Binop
.op
== Iop_Max32U
) {
1656 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1657 HReg r2
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1658 HReg rdst
= newVRegI(env
);
1659 PPCCondCode cc
= mk_PPCCondCode( Pct_TRUE
, Pcf_7LT
);
1660 addInstr(env
, mk_iMOVds_RR(rdst
, r1
));
1661 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
1662 7/*cr*/, rdst
, PPCRH_Reg(r2
)));
1663 addInstr(env
, PPCInstr_CMov(cc
, rdst
, PPCRI_Reg(r2
)));
1667 if (e
->Iex
.Binop
.op
== Iop_32HLto64
) {
1668 HReg r_Hi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1669 HReg r_Lo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1670 HReg r_Tmp
= newVRegI(env
);
1671 HReg r_dst
= newVRegI(env
);
1672 HReg msk
= newVRegI(env
);
1674 /* r_dst = OR( r_Hi<<32, r_Lo ) */
1675 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, False
/*64bit shift*/,
1676 r_dst
, r_Hi
, PPCRH_Imm(False
,32)));
1677 addInstr(env
, PPCInstr_LI(msk
, 0xFFFFFFFF, mode64
));
1678 addInstr(env
, PPCInstr_Alu( Palu_AND
, r_Tmp
, r_Lo
,
1680 addInstr(env
, PPCInstr_Alu( Palu_OR
, r_dst
, r_dst
,
1681 PPCRH_Reg(r_Tmp
) ));
1685 if ((e
->Iex
.Binop
.op
== Iop_CmpF64
) ||
1686 (e
->Iex
.Binop
.op
== Iop_CmpD64
) ||
1687 (e
->Iex
.Binop
.op
== Iop_CmpD128
)) {
1693 HReg r_ccPPC
= newVRegI(env
);
1694 HReg r_ccIR
= newVRegI(env
);
1695 HReg r_ccIR_b0
= newVRegI(env
);
1696 HReg r_ccIR_b2
= newVRegI(env
);
1697 HReg r_ccIR_b6
= newVRegI(env
);
1699 if (e
->Iex
.Binop
.op
== Iop_CmpF64
) {
1700 fr_srcL
= iselDblExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1701 fr_srcR
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1702 addInstr(env
, PPCInstr_FpCmp(r_ccPPC
, fr_srcL
, fr_srcR
));
1704 } else if (e
->Iex
.Binop
.op
== Iop_CmpD64
) {
1705 fr_srcL
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1706 fr_srcR
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1707 addInstr(env
, PPCInstr_Dfp64Cmp(r_ccPPC
, fr_srcL
, fr_srcR
));
1709 } else { // e->Iex.Binop.op == Iop_CmpD128
1710 iselDfp128Expr(&fr_srcL
, &fr_srcL_lo
, env
, e
->Iex
.Binop
.arg1
,
1712 iselDfp128Expr(&fr_srcR
, &fr_srcR_lo
, env
, e
->Iex
.Binop
.arg2
,
1714 addInstr(env
, PPCInstr_Dfp128Cmp(r_ccPPC
, fr_srcL
, fr_srcL_lo
,
1715 fr_srcR
, fr_srcR_lo
));
1718 /* Map compare result from PPC to IR,
1719 conforming to CmpF64 definition. */
1721 FP cmp result | PPC | IR
1722 --------------------------
1729 // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1730 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, True
/*32bit shift*/,
1732 PPCRH_Imm(False
,0x3)));
1733 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_ccIR_b0
,
1734 r_ccPPC
, PPCRH_Reg(r_ccIR_b0
)));
1735 addInstr(env
, PPCInstr_Alu(Palu_AND
, r_ccIR_b0
,
1736 r_ccIR_b0
, PPCRH_Imm(False
,0x1)));
1738 // r_ccIR_b2 = r_ccPPC[0]
1739 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
1741 PPCRH_Imm(False
,0x2)));
1742 addInstr(env
, PPCInstr_Alu(Palu_AND
, r_ccIR_b2
,
1743 r_ccIR_b2
, PPCRH_Imm(False
,0x4)));
1745 // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
1746 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, True
/*32bit shift*/,
1748 PPCRH_Imm(False
,0x1)));
1749 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_ccIR_b6
,
1750 r_ccPPC
, PPCRH_Reg(r_ccIR_b6
)));
1751 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
1752 r_ccIR_b6
, r_ccIR_b6
,
1753 PPCRH_Imm(False
,0x6)));
1754 addInstr(env
, PPCInstr_Alu(Palu_AND
, r_ccIR_b6
,
1755 r_ccIR_b6
, PPCRH_Imm(False
,0x40)));
1757 // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
1758 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_ccIR
,
1759 r_ccIR_b0
, PPCRH_Reg(r_ccIR_b2
)));
1760 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_ccIR
,
1761 r_ccIR
, PPCRH_Reg(r_ccIR_b6
)));
1765 if ( e
->Iex
.Binop
.op
== Iop_F64toI32S
||
1766 e
->Iex
.Binop
.op
== Iop_F64toI32U
) {
1767 /* This works in both mode64 and mode32. */
1768 HReg r1
= StackFramePtr(env
->mode64
);
1769 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
1770 HReg fsrc
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1771 HReg ftmp
= newVRegF(env
);
1772 HReg idst
= newVRegI(env
);
1774 /* Set host rounding mode */
1775 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1777 sub_from_sp( env
, 16 );
1778 addInstr(env
, PPCInstr_FpCftI(False
/*F->I*/, True
/*int32*/,
1779 e
->Iex
.Binop
.op
== Iop_F64toI32S
? True
/*syned*/
1783 addInstr(env
, PPCInstr_FpSTFIW(r1
, ftmp
));
1784 addInstr(env
, PPCInstr_Load(4, idst
, zero_r1
, mode64
));
1786 /* in 64-bit mode we need to sign-widen idst. */
1788 addInstr(env
, PPCInstr_Unary(Pun_EXTSW
, idst
, idst
));
1790 add_to_sp( env
, 16 );
1792 ///* Restore default FPU rounding. */
1793 //set_FPU_rounding_default( env );
1797 if (e
->Iex
.Binop
.op
== Iop_F64toI64S
|| e
->Iex
.Binop
.op
== Iop_F64toI64U
) {
1799 HReg r1
= StackFramePtr(env
->mode64
);
1800 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
1801 HReg fsrc
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
,
1803 HReg idst
= newVRegI(env
);
1804 HReg ftmp
= newVRegF(env
);
1806 /* Set host rounding mode */
1807 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1809 sub_from_sp( env
, 16 );
1810 addInstr(env
, PPCInstr_FpCftI(False
/*F->I*/, False
/*int64*/,
1811 ( e
->Iex
.Binop
.op
== Iop_F64toI64S
) ? True
1814 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
1815 addInstr(env
, PPCInstr_Load(8, idst
, zero_r1
, True
/*mode64*/));
1816 add_to_sp( env
, 16 );
1818 ///* Restore default FPU rounding. */
1819 //set_FPU_rounding_default( env );
1824 if (e
->Iex
.Binop
.op
== Iop_D64toI64S
) {
1825 HReg r1
= StackFramePtr(env
->mode64
);
1826 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
1827 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
1828 HReg idst
= newVRegI(env
);
1829 HReg ftmp
= newVRegF(env
);
1831 /* Set host rounding mode */
1832 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1833 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DCTFIX
, ftmp
, fr_src
));
1834 sub_from_sp( env
, 16 );
1835 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
1836 addInstr(env
, PPCInstr_Load(8, idst
, zero_r1
, mode64
));
1838 add_to_sp( env
, 16 );
1840 ///* Restore default FPU rounding. */
1841 //set_FPU_rounding_default( env );
1845 if (e
->Iex
.Binop
.op
== Iop_D128toI64S
) {
1846 PPCFpOp fpop
= Pfp_DCTFIXQ
;
1847 HReg r_srcHi
= newVRegF(env
);
1848 HReg r_srcLo
= newVRegF(env
);
1849 HReg idst
= newVRegI(env
);
1850 HReg ftmp
= newVRegF(env
);
1851 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
1853 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
1854 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
1856 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, ftmp
, r_srcHi
, r_srcLo
));
1858 // put the D64 result into an integer register
1859 sub_from_sp( env
, 16 );
1860 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
1861 addInstr(env
, PPCInstr_Load(8, idst
, zero_r1
, True
/*mode64*/));
1862 add_to_sp( env
, 16 );
1868 /* --------- UNARY OP --------- */
1870 IROp op_unop
= e
->Iex
.Unop
.op
;
1872 /* 1Uto8(32to1(expr32)) */
1873 DEFINE_PATTERN(p_32to1_then_1Uto8
,
1874 unop(Iop_1Uto8
,unop(Iop_32to1
,bind(0))));
1875 if (matchIRExpr(&mi
,p_32to1_then_1Uto8
,e
)) {
1876 const IRExpr
* expr32
= mi
.bindee
[0];
1877 HReg r_dst
= newVRegI(env
);
1878 HReg r_src
= iselWordExpr_R(env
, expr32
, IEndianess
);
1879 addInstr(env
, PPCInstr_Alu(Palu_AND
, r_dst
,
1880 r_src
, PPCRH_Imm(False
,1)));
1884 /* 16Uto32(LDbe:I16(expr32)) */
1886 DECLARE_PATTERN(p_LDbe16_then_16Uto32
);
1887 DEFINE_PATTERN(p_LDbe16_then_16Uto32
,
1889 IRExpr_Load(IEndianess
,Ity_I16
,bind(0))) );
1890 if (matchIRExpr(&mi
,p_LDbe16_then_16Uto32
,e
)) {
1891 HReg r_dst
= newVRegI(env
);
1893 = iselWordExpr_AMode( env
, mi
.bindee
[0], Ity_I16
/*xfer*/,
1895 addInstr(env
, PPCInstr_Load(2,r_dst
,amode
, mode64
));
1906 HReg r_dst
= newVRegI(env
);
1907 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1908 UShort mask
= toUShort(op_unop
==Iop_16Uto64
? 0xFFFF :
1909 op_unop
==Iop_16Uto32
? 0xFFFF : 0xFF);
1910 addInstr(env
, PPCInstr_Alu(Palu_AND
,r_dst
,r_src
,
1911 PPCRH_Imm(False
,mask
)));
1915 HReg r_dst
= newVRegI(env
);
1916 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1919 PPCInstr_Shft(Pshft_SHL
, False
/*64bit shift*/,
1920 r_dst
, r_src
, PPCRH_Imm(False
,32)));
1922 PPCInstr_Shft(Pshft_SHR
, False
/*64bit shift*/,
1923 r_dst
, r_dst
, PPCRH_Imm(False
,32)));
1929 HReg r_dst
= newVRegI(env
);
1930 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1931 UShort amt
= toUShort(op_unop
==Iop_16Sto32
? 16 : 24);
1933 PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
1934 r_dst
, r_src
, PPCRH_Imm(False
,amt
)));
1936 PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
1937 r_dst
, r_dst
, PPCRH_Imm(False
,amt
)));
1942 HReg r_dst
= newVRegI(env
);
1943 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1944 UShort amt
= toUShort(op_unop
==Iop_8Sto64
? 56 : 48);
1947 PPCInstr_Shft(Pshft_SHL
, False
/*64bit shift*/,
1948 r_dst
, r_src
, PPCRH_Imm(False
,amt
)));
1950 PPCInstr_Shft(Pshft_SAR
, False
/*64bit shift*/,
1951 r_dst
, r_dst
, PPCRH_Imm(False
,amt
)));
1955 HReg r_dst
= newVRegI(env
);
1956 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1958 /* According to the IBM docs, in 64 bit mode, srawi r,r,0
1959 sign extends the lower 32 bits into the upper 32 bits. */
1961 PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
1962 r_dst
, r_src
, PPCRH_Imm(False
,0)));
1969 if (op_unop
== Iop_Not64
) vassert(mode64
);
1970 HReg r_dst
= newVRegI(env
);
1971 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1972 addInstr(env
, PPCInstr_Unary(Pun_NOT
,r_dst
,r_src
));
1975 case Iop_64HIto32
: {
1978 iselInt64Expr(&rHi
,&rLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
1979 return rHi
; /* and abandon rLo .. poor wee thing :-) */
1981 HReg r_dst
= newVRegI(env
);
1982 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
1984 PPCInstr_Shft(Pshft_SHR
, False
/*64bit shift*/,
1985 r_dst
, r_src
, PPCRH_Imm(False
,32)));
1992 iselInt64Expr(&rHi
,&rLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
1993 return rLo
; /* similar stupid comment to the above ... */
1995 /* This is a no-op. */
1996 return iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2000 if (mode64
) { /* This is a no-op. */
2001 return iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2003 break; /* evidently not used in 32-bit mode */
2006 case Iop_32HIto16
: {
2007 HReg r_dst
= newVRegI(env
);
2008 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2009 UShort shift
= toUShort(op_unop
== Iop_16HIto8
? 8 : 16);
2011 PPCInstr_Shft(Pshft_SHR
, True
/*32bit shift*/,
2012 r_dst
, r_src
, PPCRH_Imm(False
,shift
)));
2018 iselInt128Expr(&rHi
,&rLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
2019 return rHi
; /* and abandon rLo .. poor wee thing :-) */
2025 iselInt128Expr(&rHi
,&rLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
2026 return rLo
; /* similar stupid comment to the above ... */
2032 if ((op_unop
!= Iop_1Uto64
) || mode64
) {
2033 HReg r_dst
= newVRegI(env
);
2034 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2035 addInstr(env
, PPCInstr_Set(cond
,r_dst
));
2042 /* could do better than this, but for now ... */
2043 HReg r_dst
= newVRegI(env
);
2044 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2045 addInstr(env
, PPCInstr_Set(cond
,r_dst
));
2047 PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
2048 r_dst
, r_dst
, PPCRH_Imm(False
,31)));
2050 PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
2051 r_dst
, r_dst
, PPCRH_Imm(False
,31)));
2056 /* could do better than this, but for now ... */
2057 HReg r_dst
= newVRegI(env
);
2058 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2059 addInstr(env
, PPCInstr_Set(cond
,r_dst
));
2060 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, False
/*64bit shift*/,
2061 r_dst
, r_dst
, PPCRH_Imm(False
,63)));
2062 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, False
/*64bit shift*/,
2063 r_dst
, r_dst
, PPCRH_Imm(False
,63)));
2068 case Iop_Clz32
: case Iop_ClzNat32
:
2069 case Iop_Clz64
: case Iop_ClzNat64
: {
2070 // cntlz is available even in the most basic (earliest) ppc
2071 // variants, so it's safe to generate it unconditionally.
2073 PPCUnaryOp op_clz
= (op_unop
== Iop_Clz32
|| op_unop
== Iop_ClzNat32
)
2074 ? Pun_CLZ32
: Pun_CLZ64
;
2075 if ((op_unop
== Iop_Clz64
|| op_unop
== Iop_ClzNat64
) && !mode64
)
2077 /* Count leading zeroes. */
2078 r_dst
= newVRegI(env
);
2079 r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2080 addInstr(env
, PPCInstr_Unary(op_clz
,r_dst
,r_src
));
2089 // Generate code using Clz, because we can't assume the host has
2090 // Ctz. In particular, part of the fix for bug 386945 involves
2091 // creating a Ctz in ir_opt.c from smaller fragments.
2092 PPCUnaryOp op_clz
= Pun_CLZ64
;
2094 if (op_unop
== Iop_Ctz32
|| op_unop
== Iop_CtzNat32
) {
2098 /* Compute ctz(arg) = wordsize - clz(~arg & (arg - 1)), thusly:
2107 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2108 HReg t1
= newVRegI(env
);
2109 HReg t2
= newVRegI(env
);
2110 addInstr(env
, PPCInstr_Alu(Palu_SUB
, t1
, arg
, PPCRH_Imm(True
, 1)));
2111 addInstr(env
, PPCInstr_Unary(Pun_NOT
, t2
, arg
));
2112 addInstr(env
, PPCInstr_Alu(Palu_AND
, t2
, t2
, PPCRH_Reg(t1
)));
2113 addInstr(env
, PPCInstr_Unary(op_clz
, t2
, t2
));
2114 addInstr(env
, PPCInstr_LI(t1
, WS
, False
/*!64-bit imm*/));
2115 addInstr(env
, PPCInstr_Alu(Palu_SUB
, t2
, t1
, PPCRH_Reg(t2
)));
2119 case Iop_PopCount64
: {
2120 // popcnt{x,d} is only available in later arch revs (ISA 3.0,
2121 // maybe) so it's not really correct to emit it here without a caps
2122 // check for the host.
2124 HReg r_dst
= newVRegI(env
);
2125 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2126 addInstr(env
, PPCInstr_Unary(Pun_POP64
, r_dst
, r_src
));
2129 // We don't expect to be required to handle this in 32-bit mode.
2133 case Iop_PopCount32
: {
2134 // Similar comment as for Ctz just above applies -- we really
2135 // should have a caps check here.
2137 HReg r_dst
= newVRegI(env
);
2138 // This actually generates popcntw, which in 64 bit mode does a
2139 // 32-bit count individually for both low and high halves of the
2140 // word. Per the comment at the top of iselIntExpr_R, in the 64
2141 // bit mode case, the user of this result is required to ignore
2142 // the upper 32 bits of the result. In 32 bit mode this is all
2143 // moot. It is however unclear from the PowerISA 3.0 docs that
2144 // the instruction exists in 32 bit mode; however our own front
2145 // end (guest_ppc_toIR.c) accepts it, so I guess it does exist.
2146 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2147 addInstr(env
, PPCInstr_Unary(Pun_POP32
, r_dst
, r_src
));
2151 case Iop_Reverse8sIn32_x1
: {
2152 // A bit of a mouthful, but simply .. 32-bit byte swap.
2153 // This is pretty rubbish code. We could do vastly better if
2154 // rotates, and better, rotate-inserts, were allowed. Note that
2155 // even on a 64 bit target, the right shifts must be done as 32-bit
2156 // so as to introduce zero bits in the right places. So it seems
2157 // simplest to do the whole sequence in 32-bit insns.
2159 r = <argument> // working temporary, initial byte order ABCD
2166 r = or tHi, tLo // now r has order BADC
2167 and repeat for 16 bit chunks ..
2174 r = or tHi, tLo // now r has order DCBA
2176 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2177 HReg rr
= newVRegI(env
);
2178 HReg rMask
= newVRegI(env
);
2179 HReg rnMask
= newVRegI(env
);
2180 HReg rtHi
= newVRegI(env
);
2181 HReg rtLo
= newVRegI(env
);
2182 // Copy r_src since we need to modify it
2183 addInstr(env
, mk_iMOVds_RR(rr
, r_src
));
2184 // Swap within 16-bit lanes
2185 addInstr(env
, PPCInstr_LI(rMask
, 0x00FF00FFULL
,
2186 False
/* !64bit imm*/));
2187 addInstr(env
, PPCInstr_Unary(Pun_NOT
, rnMask
, rMask
));
2188 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtHi
, rr
, PPCRH_Reg(rMask
)));
2189 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32 bit shift*/,
2191 PPCRH_Imm(False
/*!signed imm*/, 8)));
2192 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtLo
, rr
, PPCRH_Reg(rnMask
)));
2193 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, True
/*32 bit shift*/,
2195 PPCRH_Imm(False
/*!signed imm*/, 8)));
2196 addInstr(env
, PPCInstr_Alu(Palu_OR
, rr
, rtHi
, PPCRH_Reg(rtLo
)));
2197 // And now swap the two 16-bit chunks
2198 addInstr(env
, PPCInstr_LI(rMask
, 0x0000FFFFULL
,
2199 False
/* !64bit imm*/));
2200 addInstr(env
, PPCInstr_Unary(Pun_NOT
, rnMask
, rMask
));
2201 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtHi
, rr
, PPCRH_Reg(rMask
)));
2202 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32 bit shift*/,
2204 PPCRH_Imm(False
/*!signed imm*/, 16)));
2205 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtLo
, rr
, PPCRH_Reg(rnMask
)));
2206 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, True
/*32 bit shift*/,
2208 PPCRH_Imm(False
/*!signed imm*/, 16)));
2209 addInstr(env
, PPCInstr_Alu(Palu_OR
, rr
, rtHi
, PPCRH_Reg(rtLo
)));
2213 case Iop_Reverse8sIn64_x1
: {
2214 /* See Iop_Reverse8sIn32_x1, but extended to 64bit.
2215 Can only be used in 64bit mode. */
2218 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2219 HReg rr
= newVRegI(env
);
2220 HReg rMask
= newVRegI(env
);
2221 HReg rnMask
= newVRegI(env
);
2222 HReg rtHi
= newVRegI(env
);
2223 HReg rtLo
= newVRegI(env
);
2225 // Copy r_src since we need to modify it
2226 addInstr(env
, mk_iMOVds_RR(rr
, r_src
));
2228 // r = (r & 0x00FF00FF00FF00FF) << 8 | (r & 0xFF00FF00FF00FF00) >> 8
2229 addInstr(env
, PPCInstr_LI(rMask
, 0x00FF00FF00FF00FFULL
,
2230 True
/* 64bit imm*/));
2231 addInstr(env
, PPCInstr_Unary(Pun_NOT
, rnMask
, rMask
));
2232 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtHi
, rr
, PPCRH_Reg(rMask
)));
2233 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, False
/*64 bit shift*/,
2235 PPCRH_Imm(False
/*!signed imm*/, 8)));
2236 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtLo
, rr
, PPCRH_Reg(rnMask
)));
2237 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, False
/*64 bit shift*/,
2239 PPCRH_Imm(False
/*!signed imm*/, 8)));
2240 addInstr(env
, PPCInstr_Alu(Palu_OR
, rr
, rtHi
, PPCRH_Reg(rtLo
)));
2242 // r = (r & 0x0000FFFF0000FFFF) << 16 | (r & 0xFFFF0000FFFF0000) >> 16
2243 addInstr(env
, PPCInstr_LI(rMask
, 0x0000FFFF0000FFFFULL
,
2244 True
/* !64bit imm*/));
2245 addInstr(env
, PPCInstr_Unary(Pun_NOT
, rnMask
, rMask
));
2246 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtHi
, rr
, PPCRH_Reg(rMask
)));
2247 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, False
/*64 bit shift*/,
2249 PPCRH_Imm(False
/*!signed imm*/, 16)));
2250 addInstr(env
, PPCInstr_Alu(Palu_AND
, rtLo
, rr
, PPCRH_Reg(rnMask
)));
2251 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, False
/*64 bit shift*/,
2253 PPCRH_Imm(False
/*!signed imm*/, 16)));
2254 addInstr(env
, PPCInstr_Alu(Palu_OR
, rr
, rtHi
, PPCRH_Reg(rtLo
)));
2256 // r = (r & 0x00000000FFFFFFFF) << 32 | (r & 0xFFFFFFFF00000000) >> 32
2257 /* We don't need to mask anymore, just two more shifts and an or. */
2258 addInstr(env
, mk_iMOVds_RR(rtLo
, rr
));
2259 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, False
/*64 bit shift*/,
2261 PPCRH_Imm(False
/*!signed imm*/, 32)));
2262 addInstr(env
, PPCInstr_Shft(Pshft_SHR
, False
/*64 bit shift*/,
2264 PPCRH_Imm(False
/*!signed imm*/, 32)));
2265 addInstr(env
, PPCInstr_Alu(Palu_OR
, rr
, rr
, PPCRH_Reg(rtLo
)));
2275 if (op_unop
== Iop_Left64
&& !mode64
)
2277 r_dst
= newVRegI(env
);
2278 r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2279 addInstr(env
, PPCInstr_Unary(Pun_NEG
,r_dst
,r_src
));
2280 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_dst
, r_dst
, PPCRH_Reg(r_src
)));
2284 case Iop_CmpwNEZ32
: {
2285 HReg r_dst
= newVRegI(env
);
2286 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2287 addInstr(env
, PPCInstr_Unary(Pun_NEG
,r_dst
,r_src
));
2288 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_dst
, r_dst
, PPCRH_Reg(r_src
)));
2289 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
2290 r_dst
, r_dst
, PPCRH_Imm(False
, 31)));
2294 case Iop_CmpwNEZ64
: {
2295 HReg r_dst
= newVRegI(env
);
2296 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2297 if (!mode64
) goto irreducible
;
2298 addInstr(env
, PPCInstr_Unary(Pun_NEG
,r_dst
,r_src
));
2299 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_dst
, r_dst
, PPCRH_Reg(r_src
)));
2300 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, False
/*64bit shift*/,
2301 r_dst
, r_dst
, PPCRH_Imm(False
, 63)));
2305 case Iop_V128to32
: {
2307 HReg dst
= newVRegI(env
);
2308 HReg vec
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2309 PPCAMode
*am_off0
, *am_off_word0
;
2310 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
2312 // get a quadword aligned address within our stack space
2313 r_aligned16
= get_sp_aligned16( env
);
2314 am_off0
= PPCAMode_IR( 0, r_aligned16
);
2316 /* Note that the store below (done via PPCInstr_AvLdSt) uses
2317 * stvx, which stores the vector in proper LE format,
2318 * with byte zero (far right byte of the register in LE format)
2319 * stored at the lowest memory address. Therefore, to obtain
2320 * integer word zero, we need to use that lowest memory address
2321 * as the base for the load.
2323 if (IEndianess
== Iend_LE
)
2324 am_off_word0
= am_off0
;
2326 am_off_word0
= PPCAMode_IR( 12,r_aligned16
);
2328 // store vec, load low word to dst
2330 PPCInstr_AvLdSt( False
/*store*/, 16, vec
, am_off0
));
2332 PPCInstr_Load( 4, dst
, am_off_word0
, mode64
));
2334 add_to_sp( env
, 32 ); // Reset SP
2339 case Iop_V128HIto64
:
2342 HReg dst
= newVRegI(env
);
2343 HReg vec
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2344 PPCAMode
*am_off0
, *am_off8
, *am_off_arg
;
2345 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
2347 // get a quadword aligned address within our stack space
2348 r_aligned16
= get_sp_aligned16( env
);
2349 am_off0
= PPCAMode_IR( 0, r_aligned16
);
2350 am_off8
= PPCAMode_IR( 8 ,r_aligned16
);
2352 // store vec, load low word or high to dst
2354 PPCInstr_AvLdSt( False
/*store*/, 16, vec
, am_off0
));
2355 if (IEndianess
== Iend_LE
) {
2356 if (op_unop
== Iop_V128HIto64
)
2357 am_off_arg
= am_off8
;
2359 am_off_arg
= am_off0
;
2361 if (op_unop
== Iop_V128HIto64
)
2362 am_off_arg
= am_off0
;
2364 am_off_arg
= am_off8
;
2372 add_to_sp( env
, 32 ); // Reset SP
2380 /* These are no-ops. */
2381 return iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2383 /* ReinterpF64asI64(e) */
2384 /* Given an IEEE754 double, produce an I64 with the same bit
2386 case Iop_ReinterpF64asI64
:
2389 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2390 HReg r_dst
= newVRegI(env
);
2392 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
2393 am_addr
= PPCAMode_IR( 0, StackFramePtr(mode64
) );
2396 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
2399 addInstr(env
, PPCInstr_Load( 8, r_dst
, am_addr
, mode64
));
2401 add_to_sp( env
, 16 ); // Reset SP
2406 /* ReinterpF32asI32(e) */
2407 /* Given an IEEE754 float, produce an I32 with the same bit
2409 case Iop_ReinterpF32asI32
: {
2410 /* I believe this generates correct code for both 32- and
2413 HReg fr_src
= iselFltExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2414 HReg r_dst
= newVRegI(env
);
2416 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
2417 am_addr
= PPCAMode_IR( 0, StackFramePtr(mode64
) );
2420 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 4,
2423 addInstr(env
, PPCInstr_Load( 4, r_dst
, am_addr
, mode64
));
2425 add_to_sp( env
, 16 ); // Reset SP
2430 case Iop_ReinterpD64asI64
:
2433 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2434 HReg r_dst
= newVRegI(env
);
2436 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
2437 am_addr
= PPCAMode_IR( 0, StackFramePtr(mode64
) );
2440 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
2443 addInstr(env
, PPCInstr_Load( 8, r_dst
, am_addr
, mode64
));
2444 add_to_sp( env
, 16 ); // Reset SP
2449 case Iop_BCDtoDPB
: {
2450 /* the following is only valid in 64 bit mode */
2456 HReg r_dst
= newVRegI(env
);
2461 argregs
[0] = hregPPC_GPR3(mode64
);
2463 argiregs
|= (1 << (argreg
+3));
2464 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++],
2465 iselWordExpr_R(env
, e
->Iex
.Unop
.arg
,
2468 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
2469 if (IEndianess
== Iend_LE
) {
2470 addInstr(env
, PPCInstr_Call( cc
, (Addr
)h_calc_BCDtoDPB
,
2472 mk_RetLoc_simple(RLPri_Int
)) );
2475 fdescr
= (HWord
*)h_calc_BCDtoDPB
;
2476 addInstr(env
, PPCInstr_Call( cc
, (Addr64
)(fdescr
[0]),
2478 mk_RetLoc_simple(RLPri_Int
)) );
2481 addInstr(env
, mk_iMOVds_RR(r_dst
, argregs
[0]));
2485 case Iop_DPBtoBCD
: {
2486 /* the following is only valid in 64 bit mode */
2492 HReg r_dst
= newVRegI(env
);
2497 argregs
[0] = hregPPC_GPR3(mode64
);
2499 argiregs
|= (1 << (argreg
+3));
2500 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++],
2501 iselWordExpr_R(env
, e
->Iex
.Unop
.arg
,
2504 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
2506 if (IEndianess
== Iend_LE
) {
2507 addInstr(env
, PPCInstr_Call( cc
, (Addr
)h_calc_DPBtoBCD
,
2509 mk_RetLoc_simple(RLPri_Int
) ) );
2512 fdescr
= (HWord
*)h_calc_DPBtoBCD
;
2513 addInstr(env
, PPCInstr_Call( cc
, (Addr64
)(fdescr
[0]),
2515 mk_RetLoc_simple(RLPri_Int
) ) );
2518 addInstr(env
, mk_iMOVds_RR(r_dst
, argregs
[0]));
2521 case Iop_F32toF16x4_DEP
: {
2522 HReg vdst
= newVRegV(env
); /* V128 */
2523 HReg dst
= newVRegI(env
); /* I64*/
2524 HReg r0
= newVRegI(env
); /* I16*/
2525 HReg r1
= newVRegI(env
); /* I16*/
2526 HReg r2
= newVRegI(env
); /* I16*/
2527 HReg r3
= newVRegI(env
); /* I16*/
2528 HReg vsrc
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2529 PPCAMode
*am_off0
, *am_off2
, *am_off4
, *am_off6
, *am_off8
;
2530 PPCAMode
*am_off10
, *am_off12
, *am_off14
;
2533 sub_from_sp( env
, 32 ); // Move SP down
2535 /* issue instruction */
2536 addInstr(env
, PPCInstr_AvUnary(Pav_F32toF16x4
, vdst
, vsrc
));
2538 /* Get a quadword aligned address within our stack space */
2539 r_aligned16
= get_sp_aligned16( env
);
2540 am_off0
= PPCAMode_IR( 0, r_aligned16
);
2541 am_off2
= PPCAMode_IR( 2, r_aligned16
);
2542 am_off4
= PPCAMode_IR( 4, r_aligned16
);
2543 am_off6
= PPCAMode_IR( 6, r_aligned16
);
2544 am_off8
= PPCAMode_IR( 8, r_aligned16
);
2545 am_off10
= PPCAMode_IR( 10, r_aligned16
);
2546 am_off12
= PPCAMode_IR( 12, r_aligned16
);
2547 am_off14
= PPCAMode_IR( 14, r_aligned16
);
2549 /* Store v128 result to stack. */
2550 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, vdst
, am_off0
));
2552 /* fetch four I16 from V128, store into contiguous I64 via stack, */
2553 if (IEndianess
== Iend_LE
) {
2554 addInstr(env
, PPCInstr_Load( 2, r3
, am_off12
, mode64
));
2555 addInstr(env
, PPCInstr_Load( 2, r2
, am_off8
, mode64
));
2556 addInstr(env
, PPCInstr_Load( 2, r1
, am_off4
, mode64
));
2557 addInstr(env
, PPCInstr_Load( 2, r0
, am_off0
, mode64
));
2559 addInstr(env
, PPCInstr_Load( 2, r0
, am_off14
, mode64
));
2560 addInstr(env
, PPCInstr_Load( 2, r1
, am_off10
, mode64
));
2561 addInstr(env
, PPCInstr_Load( 2, r2
, am_off6
, mode64
));
2562 addInstr(env
, PPCInstr_Load( 2, r3
, am_off2
, mode64
));
2565 /* store in contiguous 64-bit values */
2566 addInstr(env
, PPCInstr_Store( 2, am_off6
, r3
, mode64
));
2567 addInstr(env
, PPCInstr_Store( 2, am_off4
, r2
, mode64
));
2568 addInstr(env
, PPCInstr_Store( 2, am_off2
, r1
, mode64
));
2569 addInstr(env
, PPCInstr_Store( 2, am_off0
, r0
, mode64
));
2572 addInstr(env
, PPCInstr_Load(8, dst
, am_off0
, mode64
));
2574 add_to_sp( env
, 32 ); // Reset SP
2582 switch (e
->Iex
.Unop
.op
) {
2583 case Iop_ExtractExpD64
: {
2585 HReg fr_dst
= newVRegI(env
);
2586 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2587 HReg tmp
= newVRegF(env
);
2588 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
2589 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DXEX
, tmp
, fr_src
));
2591 // put the D64 result into a integer register
2592 sub_from_sp( env
, 16 );
2593 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
2594 addInstr(env
, PPCInstr_Load(8, fr_dst
, zero_r1
, env
->mode64
));
2595 add_to_sp( env
, 16 );
2598 case Iop_ExtractExpD128
: {
2599 HReg fr_dst
= newVRegI(env
);
2602 HReg tmp
= newVRegF(env
);
2603 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
2605 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
,
2607 addInstr(env
, PPCInstr_ExtractExpD128(Pfp_DXEXQ
, tmp
,
2610 sub_from_sp( env
, 16 );
2611 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
2612 addInstr(env
, PPCInstr_Load(8, fr_dst
, zero_r1
, env
->mode64
));
2613 add_to_sp( env
, 16 );
2623 /* --------- GET --------- */
2625 if (ty
== Ity_I8
|| ty
== Ity_I16
||
2626 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) {
2627 HReg r_dst
= newVRegI(env
);
2628 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
2629 GuestStatePtr(mode64
) );
2630 addInstr(env
, PPCInstr_Load( toUChar(sizeofIRType(ty
)),
2631 r_dst
, am_addr
, mode64
));
2639 = genGuestArrayOffset( env
, e
->Iex
.GetI
.descr
,
2640 e
->Iex
.GetI
.ix
, e
->Iex
.GetI
.bias
,
2642 HReg r_dst
= newVRegI(env
);
2643 if (mode64
&& ty
== Ity_I64
) {
2644 addInstr(env
, PPCInstr_Load( toUChar(8),
2645 r_dst
, src_am
, mode64
));
2648 if ((!mode64
) && ty
== Ity_I32
) {
2649 addInstr(env
, PPCInstr_Load( toUChar(4),
2650 r_dst
, src_am
, mode64
));
2656 /* --------- CCALL --------- */
2658 vassert(ty
== e
->Iex
.CCall
.retty
); /* well-formedness of IR */
2660 /* be very restrictive for now. Only 32/64-bit ints allowed for
2661 args, and 32 bits or host machine word for return type. */
2662 if (!(ty
== Ity_I32
|| (mode64
&& ty
== Ity_I64
)))
2665 /* Marshal args, do the call, clear stack. */
2667 RetLoc rloc
= mk_RetLoc_INVALID();
2668 doHelperCall( &addToSp
, &rloc
, env
, NULL
/*guard*/,
2669 e
->Iex
.CCall
.cee
, e
->Iex
.CCall
.retty
, e
->Iex
.CCall
.args
,
2671 vassert(is_sane_RetLoc(rloc
));
2672 vassert(rloc
.pri
== RLPri_Int
);
2673 vassert(addToSp
== 0);
2675 /* GPR3 now holds the destination address from Pin_Goto */
2676 HReg r_dst
= newVRegI(env
);
2677 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
2681 /* --------- LITERAL --------- */
2682 /* 32/16/8-bit literals */
2685 HReg r_dst
= newVRegI(env
);
2686 IRConst
* con
= e
->Iex
.Const
.con
;
2688 case Ico_U64
: if (!mode64
) goto irreducible
;
2689 l
= (Long
) con
->Ico
.U64
; break;
2690 case Ico_U32
: l
= (Long
)(Int
) con
->Ico
.U32
; break;
2691 case Ico_U16
: l
= (Long
)(Int
)(Short
)con
->Ico
.U16
; break;
2692 case Ico_U8
: l
= (Long
)(Int
)(Char
)con
->Ico
.U8
; break;
2693 default: vpanic("iselIntExpr_R.const(ppc)");
2695 addInstr(env
, PPCInstr_LI(r_dst
, (ULong
)l
, mode64
));
2699 /* --------- MULTIPLEX --------- */
2700 case Iex_ITE
: { // VFD
2701 if ((ty
== Ity_I8
|| ty
== Ity_I16
||
2702 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) &&
2703 typeOfIRExpr(env
->type_env
,e
->Iex
.ITE
.cond
) == Ity_I1
) {
2704 PPCRI
* r1
= iselWordExpr_RI(env
, e
->Iex
.ITE
.iftrue
, IEndianess
);
2705 HReg r0
= iselWordExpr_R(env
, e
->Iex
.ITE
.iffalse
, IEndianess
);
2706 HReg r_dst
= newVRegI(env
);
2707 addInstr(env
, mk_iMOVds_RR(r_dst
,r0
));
2708 PPCCondCode cc
= iselCondCode(env
, e
->Iex
.ITE
.cond
, IEndianess
);
2709 addInstr(env
, PPCInstr_CMov(cc
, r_dst
, r1
));
2717 } /* switch (e->tag) */
2720 /* We get here if no pattern matched. */
2723 vpanic("iselIntExpr_R(ppc): cannot reduce tree");
2727 /*---------------------------------------------------------*/
2728 /*--- ISEL: Integer expression auxiliaries ---*/
2729 /*---------------------------------------------------------*/
2731 /* --------------------- AMODEs --------------------- */
2733 /* Return an AMode which computes the value of the specified
2734 expression, possibly also adding insns to the code list as a
2735 result. The expression may only be a word-size one.
2738 static Bool
uInt_fits_in_16_bits ( UInt u
)
2740 /* Is u the same as the sign-extend of its lower 16 bits? */
2741 UInt v
= u
& 0xFFFF;
2743 v
= (Int
)(v
<< 16) >> 16; /* sign extend */
2748 static Bool
uLong_fits_in_16_bits ( ULong u
)
2750 /* Is u the same as the sign-extend of its lower 16 bits? */
2751 ULong v
= u
& 0xFFFFULL
;
2753 v
= (Long
)(v
<< 48) >> 48; /* sign extend */
2758 static Bool
uLong_is_4_aligned ( ULong u
)
2760 return toBool((u
& 3ULL) == 0);
2763 static Bool
sane_AMode ( ISelEnv
* env
, PPCAMode
* am
)
2765 Bool mode64
= env
->mode64
;
2768 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2769 somehow, but I think it's OK. */
2770 return toBool( hregClass(am
->Pam
.IR
.base
) == HRcGPR(mode64
) &&
2771 hregIsVirtual(am
->Pam
.IR
.base
) &&
2772 uInt_fits_in_16_bits(am
->Pam
.IR
.index
) );
2774 return toBool( hregClass(am
->Pam
.RR
.base
) == HRcGPR(mode64
) &&
2775 hregIsVirtual(am
->Pam
.RR
.base
) &&
2776 hregClass(am
->Pam
.RR
.index
) == HRcGPR(mode64
) &&
2777 hregIsVirtual(am
->Pam
.RR
.index
) );
2779 vpanic("sane_AMode: unknown ppc amode tag");
2784 PPCAMode
* iselWordExpr_AMode ( ISelEnv
* env
, const IRExpr
* e
, IRType xferTy
,
2785 IREndness IEndianess
)
2787 PPCAMode
* am
= iselWordExpr_AMode_wrk(env
, e
, xferTy
, IEndianess
);
2788 vassert(sane_AMode(env
, am
));
2792 /* DO NOT CALL THIS DIRECTLY ! */
2793 static PPCAMode
* iselWordExpr_AMode_wrk ( ISelEnv
* env
, const IRExpr
* e
,
2794 IRType xferTy
, IREndness IEndianess
)
2796 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2800 /* If the data load/store type is I32 or I64, this amode might
2801 be destined for use in ld/ldu/lwa/st/stu. In which case
2802 insist that if it comes out as an _IR, the immediate must
2803 have its bottom two bits be zero. This does assume that for
2804 any other type (I8/I16/I128/F32/F64/V128) the amode will not
2805 be parked in any such instruction. But that seems a
2806 reasonable assumption. */
2807 Bool aligned4imm
= toBool(xferTy
== Ity_I32
|| xferTy
== Ity_I64
);
2809 vassert(ty
== Ity_I64
);
2811 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2812 if (e
->tag
== Iex_Binop
2813 && e
->Iex
.Binop
.op
== Iop_Add64
2814 && e
->Iex
.Binop
.arg2
->tag
== Iex_Const
2815 && e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->tag
== Ico_U64
2816 && (aligned4imm
? uLong_is_4_aligned(e
->Iex
.Binop
.arg2
2817 ->Iex
.Const
.con
->Ico
.U64
)
2819 && uLong_fits_in_16_bits(e
->Iex
.Binop
.arg2
2820 ->Iex
.Const
.con
->Ico
.U64
)) {
2821 return PPCAMode_IR( (Int
)e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->Ico
.U64
,
2822 iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
,
2826 /* Add64(expr,expr) */
2827 if (e
->tag
== Iex_Binop
2828 && e
->Iex
.Binop
.op
== Iop_Add64
) {
2829 HReg r_base
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
2830 HReg r_idx
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
2831 return PPCAMode_RR( r_idx
, r_base
);
2836 vassert(ty
== Ity_I32
);
2838 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2839 if (e
->tag
== Iex_Binop
2840 && e
->Iex
.Binop
.op
== Iop_Add32
2841 && e
->Iex
.Binop
.arg2
->tag
== Iex_Const
2842 && e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->tag
== Ico_U32
2843 && uInt_fits_in_16_bits(e
->Iex
.Binop
.arg2
2844 ->Iex
.Const
.con
->Ico
.U32
)) {
2845 return PPCAMode_IR( (Int
)e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->Ico
.U32
,
2846 iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
,
2850 /* Add32(expr,expr) */
2851 if (e
->tag
== Iex_Binop
2852 && e
->Iex
.Binop
.op
== Iop_Add32
) {
2853 HReg r_base
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
2854 HReg r_idx
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
2855 return PPCAMode_RR( r_idx
, r_base
);
2860 /* Doesn't match anything in particular. Generate it into
2861 a register and use that. */
2862 return PPCAMode_IR( 0, iselWordExpr_R(env
,e
,IEndianess
) );
2866 /* --------------------- RH --------------------- */
2868 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2869 (reg-or-halfword-immediate). It's important to specify whether the
2870 immediate is to be regarded as signed or not. If yes, this will
2871 never return -32768 as an immediate; this guaranteed that all
2872 signed immediates that are return can have their sign inverted if
2875 static PPCRH
* iselWordExpr_RH ( ISelEnv
* env
, Bool syned
, const IRExpr
* e
,
2876 IREndness IEndianess
)
2878 PPCRH
* ri
= iselWordExpr_RH_wrk(env
, syned
, e
, IEndianess
);
2879 /* sanity checks ... */
2882 vassert(ri
->Prh
.Imm
.syned
== syned
);
2884 vassert(ri
->Prh
.Imm
.imm16
!= 0x8000);
2887 vassert(hregClass(ri
->Prh
.Reg
.reg
) == HRcGPR(env
->mode64
));
2888 vassert(hregIsVirtual(ri
->Prh
.Reg
.reg
));
2891 vpanic("iselIntExpr_RH: unknown ppc RH tag");
2895 /* DO NOT CALL THIS DIRECTLY ! */
2896 static PPCRH
* iselWordExpr_RH_wrk ( ISelEnv
* env
, Bool syned
, const IRExpr
* e
,
2897 IREndness IEndianess
)
2901 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2902 vassert(ty
== Ity_I8
|| ty
== Ity_I16
||
2903 ty
== Ity_I32
|| ((ty
== Ity_I64
) && env
->mode64
));
2905 /* special case: immediate */
2906 if (e
->tag
== Iex_Const
) {
2907 IRConst
* con
= e
->Iex
.Const
.con
;
2908 /* What value are we aiming to generate? */
2910 /* Note: Not sign-extending - we carry 'syned' around */
2911 case Ico_U64
: vassert(env
->mode64
);
2912 u
= con
->Ico
.U64
; break;
2913 case Ico_U32
: u
= 0xFFFFFFFF & con
->Ico
.U32
; break;
2914 case Ico_U16
: u
= 0x0000FFFF & con
->Ico
.U16
; break;
2915 case Ico_U8
: u
= 0x000000FF & con
->Ico
.U8
; break;
2916 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2919 /* Now figure out if it's representable. */
2920 if (!syned
&& u
<= 65535) {
2921 return PPCRH_Imm(False
/*unsigned*/, toUShort(u
& 0xFFFF));
2923 if (syned
&& l
>= -32767 && l
<= 32767) {
2924 return PPCRH_Imm(True
/*signed*/, toUShort(u
& 0xFFFF));
2926 /* no luck; use the Slow Way. */
2929 /* default case: calculate into a register and return that */
2930 return PPCRH_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
2934 /* --------------------- RIs --------------------- */
2936 /* Calculate an expression into an PPCRI operand. As with
2937 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2938 in 64-bit mode, 64 bits. */
2940 static PPCRI
* iselWordExpr_RI ( ISelEnv
* env
, const IRExpr
* e
,
2941 IREndness IEndianess
)
2943 PPCRI
* ri
= iselWordExpr_RI_wrk(env
, e
, IEndianess
);
2944 /* sanity checks ... */
2949 vassert(hregClass(ri
->Pri
.Reg
) == HRcGPR(env
->mode64
));
2950 vassert(hregIsVirtual(ri
->Pri
.Reg
));
2953 vpanic("iselIntExpr_RI: unknown ppc RI tag");
2957 /* DO NOT CALL THIS DIRECTLY ! */
2958 static PPCRI
* iselWordExpr_RI_wrk ( ISelEnv
* env
, const IRExpr
* e
,
2959 IREndness IEndianess
)
2962 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2963 vassert(ty
== Ity_I8
|| ty
== Ity_I16
||
2964 ty
== Ity_I32
|| ((ty
== Ity_I64
) && env
->mode64
));
2966 /* special case: immediate */
2967 if (e
->tag
== Iex_Const
) {
2968 IRConst
* con
= e
->Iex
.Const
.con
;
2970 case Ico_U64
: vassert(env
->mode64
);
2971 l
= (Long
) con
->Ico
.U64
; break;
2972 case Ico_U32
: l
= (Long
)(Int
) con
->Ico
.U32
; break;
2973 case Ico_U16
: l
= (Long
)(Int
)(Short
)con
->Ico
.U16
; break;
2974 case Ico_U8
: l
= (Long
)(Int
)(Char
)con
->Ico
.U8
; break;
2975 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2977 return PPCRI_Imm((ULong
)l
);
2980 /* default case: calculate into a register and return that */
2981 return PPCRI_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
2985 /* --------------------- RH5u --------------------- */
2987 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2988 being an immediate in the range 1 .. 31 inclusive. Used for doing
2989 shift amounts. Only used in 32-bit mode. */
2991 static PPCRH
* iselWordExpr_RH5u ( ISelEnv
* env
, const IRExpr
* e
,
2992 IREndness IEndianess
)
2995 vassert(!env
->mode64
);
2996 ri
= iselWordExpr_RH5u_wrk(env
, e
, IEndianess
);
2997 /* sanity checks ... */
3000 vassert(ri
->Prh
.Imm
.imm16
>= 1 && ri
->Prh
.Imm
.imm16
<= 31);
3001 vassert(!ri
->Prh
.Imm
.syned
);
3004 vassert(hregClass(ri
->Prh
.Reg
.reg
) == HRcGPR(env
->mode64
));
3005 vassert(hregIsVirtual(ri
->Prh
.Reg
.reg
));
3008 vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
3012 /* DO NOT CALL THIS DIRECTLY ! */
3013 static PPCRH
* iselWordExpr_RH5u_wrk ( ISelEnv
* env
, const IRExpr
* e
,
3014 IREndness IEndianess
)
3016 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
3017 vassert(ty
== Ity_I8
);
3019 /* special case: immediate */
3020 if (e
->tag
== Iex_Const
3021 && e
->Iex
.Const
.con
->tag
== Ico_U8
3022 && e
->Iex
.Const
.con
->Ico
.U8
>= 1
3023 && e
->Iex
.Const
.con
->Ico
.U8
<= 31) {
3024 return PPCRH_Imm(False
/*unsigned*/, e
->Iex
.Const
.con
->Ico
.U8
);
3027 /* default case: calculate into a register and return that */
3028 return PPCRH_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
3032 /* --------------------- RH6u --------------------- */
3034 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
3035 being an immediate in the range 1 .. 63 inclusive. Used for doing
3036 shift amounts. Only used in 64-bit mode. */
3038 static PPCRH
* iselWordExpr_RH6u ( ISelEnv
* env
, const IRExpr
* e
,
3039 IREndness IEndianess
)
3042 vassert(env
->mode64
);
3043 ri
= iselWordExpr_RH6u_wrk(env
, e
, IEndianess
);
3044 /* sanity checks ... */
3047 vassert(ri
->Prh
.Imm
.imm16
>= 1 && ri
->Prh
.Imm
.imm16
<= 63);
3048 vassert(!ri
->Prh
.Imm
.syned
);
3051 vassert(hregClass(ri
->Prh
.Reg
.reg
) == HRcGPR(env
->mode64
));
3052 vassert(hregIsVirtual(ri
->Prh
.Reg
.reg
));
3055 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
3059 /* DO NOT CALL THIS DIRECTLY ! */
3060 static PPCRH
* iselWordExpr_RH6u_wrk ( ISelEnv
* env
, const IRExpr
* e
,
3061 IREndness IEndianess
)
3063 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
3064 vassert(ty
== Ity_I8
);
3066 /* special case: immediate */
3067 if (e
->tag
== Iex_Const
3068 && e
->Iex
.Const
.con
->tag
== Ico_U8
3069 && e
->Iex
.Const
.con
->Ico
.U8
>= 1
3070 && e
->Iex
.Const
.con
->Ico
.U8
<= 63) {
3071 return PPCRH_Imm(False
/*unsigned*/, e
->Iex
.Const
.con
->Ico
.U8
);
3074 /* default case: calculate into a register and return that */
3075 return PPCRH_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
3079 /* --------------------- CONDCODE --------------------- */
3081 /* Generate code to evaluated a bit-typed expression, returning the
3082 condition code which would correspond when the expression would
3083 notionally have returned 1. */
3085 static PPCCondCode
iselCondCode ( ISelEnv
* env
, const IRExpr
* e
,
3086 IREndness IEndianess
)
3088 /* Uh, there's nothing we can sanity check here, unfortunately. */
3089 return iselCondCode_wrk(env
,e
, IEndianess
);
3092 /* DO NOT CALL THIS DIRECTLY ! */
3093 static PPCCondCode
iselCondCode_wrk ( ISelEnv
* env
, const IRExpr
* e
,
3094 IREndness IEndianess
)
3097 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I1
);
3099 /* Constant 1:Bit */
3100 if (e
->tag
== Iex_Const
&& e
->Iex
.Const
.con
->Ico
.U1
== True
) {
3101 // Make a compare that will always be true:
3102 HReg r_zero
= newVRegI(env
);
3103 addInstr(env
, PPCInstr_LI(r_zero
, 0, env
->mode64
));
3104 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3105 7/*cr*/, r_zero
, PPCRH_Reg(r_zero
)));
3106 return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3110 if (e
->tag
== Iex_Unop
&& e
->Iex
.Unop
.op
== Iop_Not1
) {
3111 /* Generate code for the arg, and negate the test condition */
3112 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3113 cond
.test
= invertCondTest(cond
.test
);
3117 /* --- patterns rooted at: 32to1 or 64to1 --- */
3120 if (e
->tag
== Iex_Unop
&&
3121 (e
->Iex
.Unop
.op
== Iop_32to1
|| e
->Iex
.Unop
.op
== Iop_64to1
)) {
3122 HReg src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3123 HReg tmp
= newVRegI(env
);
3124 /* could do better, probably -- andi. */
3125 addInstr(env
, PPCInstr_Alu(Palu_AND
, tmp
,
3126 src
, PPCRH_Imm(False
,1)));
3127 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3128 7/*cr*/, tmp
, PPCRH_Imm(False
,1)));
3129 return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3132 /* --- patterns rooted at: CmpNEZ8 --- */
3135 /* Note this cloned as CmpNE8(x,0) below. */
3136 /* could do better -- andi. */
3137 if (e
->tag
== Iex_Unop
3138 && e
->Iex
.Unop
.op
== Iop_CmpNEZ8
) {
3139 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3140 HReg tmp
= newVRegI(env
);
3141 addInstr(env
, PPCInstr_Alu(Palu_AND
, tmp
, arg
,
3142 PPCRH_Imm(False
,0xFF)));
3143 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3144 7/*cr*/, tmp
, PPCRH_Imm(False
,0)));
3145 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3148 /* --- patterns rooted at: CmpNEZ32 --- */
3151 if (e
->tag
== Iex_Unop
3152 && e
->Iex
.Unop
.op
== Iop_CmpNEZ32
) {
3153 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3154 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3155 7/*cr*/, r1
, PPCRH_Imm(False
,0)));
3156 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3159 /* --- patterns rooted at: Cmp*32* --- */
3162 if (e
->tag
== Iex_Binop
3163 && (e
->Iex
.Binop
.op
== Iop_CmpEQ32
3164 || e
->Iex
.Binop
.op
== Iop_CmpNE32
3165 || e
->Iex
.Binop
.op
== Iop_CmpLT32S
3166 || e
->Iex
.Binop
.op
== Iop_CmpLT32U
3167 || e
->Iex
.Binop
.op
== Iop_CmpLE32S
3168 || e
->Iex
.Binop
.op
== Iop_CmpLE32U
)) {
3169 Bool syned
= (e
->Iex
.Binop
.op
== Iop_CmpLT32S
||
3170 e
->Iex
.Binop
.op
== Iop_CmpLE32S
);
3171 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3172 PPCRH
* ri2
= iselWordExpr_RH(env
, syned
, e
->Iex
.Binop
.arg2
, IEndianess
);
3173 addInstr(env
, PPCInstr_Cmp(syned
, True
/*32bit cmp*/,
3176 switch (e
->Iex
.Binop
.op
) {
3177 case Iop_CmpEQ32
: return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3178 case Iop_CmpNE32
: return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3179 case Iop_CmpLT32U
: case Iop_CmpLT32S
:
3180 return mk_PPCCondCode( Pct_TRUE
, Pcf_7LT
);
3181 case Iop_CmpLE32U
: case Iop_CmpLE32S
:
3182 return mk_PPCCondCode( Pct_FALSE
, Pcf_7GT
);
3183 default: vpanic("iselCondCode(ppc): CmpXX32");
3187 /* --- patterns rooted at: CmpNEZ64 --- */
3190 if (e
->tag
== Iex_Unop
3191 && e
->Iex
.Unop
.op
== Iop_CmpNEZ64
) {
3194 HReg tmp
= newVRegI(env
);
3195 iselInt64Expr( &hi
, &lo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3196 addInstr(env
, PPCInstr_Alu(Palu_OR
, tmp
, lo
, PPCRH_Reg(hi
)));
3197 addInstr(env
, PPCInstr_Cmp(False
/*sign*/, True
/*32bit cmp*/,
3198 7/*cr*/, tmp
,PPCRH_Imm(False
,0)));
3199 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3201 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3202 addInstr(env
, PPCInstr_Cmp(False
/*sign*/, False
/*64bit cmp*/,
3203 7/*cr*/, r_src
,PPCRH_Imm(False
,0)));
3204 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3208 /* --- patterns rooted at: Cmp*64* --- */
3211 if (e
->tag
== Iex_Binop
3212 && (e
->Iex
.Binop
.op
== Iop_CmpEQ64
3213 || e
->Iex
.Binop
.op
== Iop_CmpNE64
3214 || e
->Iex
.Binop
.op
== Iop_CmpLT64S
3215 || e
->Iex
.Binop
.op
== Iop_CmpLT64U
3216 || e
->Iex
.Binop
.op
== Iop_CmpLE64S
3217 || e
->Iex
.Binop
.op
== Iop_CmpLE64U
)) {
3218 Bool syned
= (e
->Iex
.Binop
.op
== Iop_CmpLT64S
||
3219 e
->Iex
.Binop
.op
== Iop_CmpLE64S
);
3220 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3221 PPCRH
* ri2
= iselWordExpr_RH(env
, syned
, e
->Iex
.Binop
.arg2
, IEndianess
);
3222 vassert(env
->mode64
);
3223 addInstr(env
, PPCInstr_Cmp(syned
, False
/*64bit cmp*/,
3226 switch (e
->Iex
.Binop
.op
) {
3227 case Iop_CmpEQ64
: return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3228 case Iop_CmpNE64
: return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3229 case Iop_CmpLT64U
: return mk_PPCCondCode( Pct_TRUE
, Pcf_7LT
);
3230 case Iop_CmpLE64U
: return mk_PPCCondCode( Pct_FALSE
, Pcf_7GT
);
3231 default: vpanic("iselCondCode(ppc): CmpXX64");
3235 /* --- patterns rooted at: CmpNE8 --- */
3238 /* Note this is a direct copy of CmpNEZ8 above. */
3239 /* could do better -- andi. */
3240 if (e
->tag
== Iex_Binop
3241 && e
->Iex
.Binop
.op
== Iop_CmpNE8
3242 && isZeroU8(e
->Iex
.Binop
.arg2
)) {
3243 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3244 HReg tmp
= newVRegI(env
);
3245 addInstr(env
, PPCInstr_Alu(Palu_AND
, tmp
, arg
,
3246 PPCRH_Imm(False
,0xFF)));
3247 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3248 7/*cr*/, tmp
, PPCRH_Imm(False
,0)));
3249 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3253 if (e
->tag
== Iex_RdTmp
) {
3254 HReg r_src
= lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
3255 HReg src_masked
= newVRegI(env
);
3257 PPCInstr_Alu(Palu_AND
, src_masked
,
3258 r_src
, PPCRH_Imm(False
,1)));
3260 PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3261 7/*cr*/, src_masked
, PPCRH_Imm(False
,1)));
3262 return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3265 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e
->tag
);
3267 vpanic("iselCondCode(ppc)");
3271 /*---------------------------------------------------------*/
3272 /*--- ISEL: Integer expressions (128 bit) ---*/
3273 /*---------------------------------------------------------*/
3275 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3276 which is returned as the first two parameters. As with
3277 iselWordExpr_R, these may be either real or virtual regs; in any
3278 case they must not be changed by subsequent code emitted by the
3281 static void iselInt128Expr ( HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
,
3282 const IRExpr
* e
, IREndness IEndianess
)
3284 vassert(env
->mode64
);
3285 iselInt128Expr_wrk(rHi
, rLo
, env
, e
, IEndianess
);
3287 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
3289 vassert(hregClass(*rHi
) == HRcGPR(env
->mode64
));
3290 vassert(hregIsVirtual(*rHi
));
3291 vassert(hregClass(*rLo
) == HRcGPR(env
->mode64
));
3292 vassert(hregIsVirtual(*rLo
));
3295 /* DO NOT CALL THIS DIRECTLY ! */
3296 static void iselInt128Expr_wrk ( HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
,
3297 const IRExpr
* e
, IREndness IEndianess
)
3299 Bool mode64
= env
->mode64
;
3302 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I128
);
3304 /* read 128-bit IRTemp */
3305 if (e
->tag
== Iex_RdTmp
) {
3306 lookupIRTempPair( rHi
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
3311 if (e
->tag
== Iex_Get
) {
3312 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
3313 GuestStatePtr(mode64
) );
3314 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
3315 HReg tLo
= newVRegI(env
);
3316 HReg tHi
= newVRegI(env
);
3318 addInstr(env
, PPCInstr_Load( 8, tHi
, am_addr
, mode64
));
3319 addInstr(env
, PPCInstr_Load( 8, tLo
, am_addr4
, mode64
));
3325 /* --------- BINARY ops --------- */
3326 if (e
->tag
== Iex_Binop
) {
3327 switch (e
->Iex
.Binop
.op
) {
3328 /* 64 x 64 -> 128 multiply */
3331 HReg tLo
= newVRegI(env
);
3332 HReg tHi
= newVRegI(env
);
3333 Bool syned
= toBool(e
->Iex
.Binop
.op
== Iop_MullS64
);
3334 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3335 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3336 addInstr(env
, PPCInstr_MulL(False
/*signedness irrelevant*/,
3337 False
/*lo64*/, False
/*64bit mul*/,
3338 tLo
, r_srcL
, r_srcR
));
3339 addInstr(env
, PPCInstr_MulL(syned
,
3340 True
/*hi64*/, False
/*64bit mul*/,
3341 tHi
, r_srcL
, r_srcR
));
3347 /* 64HLto128(e1,e2) */
3349 *rHi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3350 *rLo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3355 } /* if (e->tag == Iex_Binop) */
3358 /* --------- UNARY ops --------- */
3359 if (e
->tag
== Iex_Unop
) {
3360 switch (e
->Iex
.Unop
.op
) {
3364 } /* if (e->tag == Iex_Unop) */
3366 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e
->tag
);
3368 vpanic("iselInt128Expr(ppc64)");
3372 /*---------------------------------------------------------*/
3373 /*--- ISEL: Integer expressions (64 bit) ---*/
3374 /*---------------------------------------------------------*/
3376 /* 32-bit mode ONLY: compute a 128-bit value into a register quad */
3377 static void iselInt128Expr_to_32x4 ( HReg
* rHi
, HReg
* rMedHi
, HReg
* rMedLo
,
3378 HReg
* rLo
, ISelEnv
* env
, const IRExpr
* e
,
3379 IREndness IEndianess
)
3381 vassert(!env
->mode64
);
3382 iselInt128Expr_to_32x4_wrk(rHi
, rMedHi
, rMedLo
, rLo
, env
, e
, IEndianess
);
3384 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
3386 vassert(hregClass(*rHi
) == HRcInt32
);
3387 vassert(hregIsVirtual(*rHi
));
3388 vassert(hregClass(*rMedHi
) == HRcInt32
);
3389 vassert(hregIsVirtual(*rMedHi
));
3390 vassert(hregClass(*rMedLo
) == HRcInt32
);
3391 vassert(hregIsVirtual(*rMedLo
));
3392 vassert(hregClass(*rLo
) == HRcInt32
);
3393 vassert(hregIsVirtual(*rLo
));
3396 static void iselInt128Expr_to_32x4_wrk ( HReg
* rHi
, HReg
* rMedHi
,
3397 HReg
* rMedLo
, HReg
* rLo
,
3398 ISelEnv
* env
, const IRExpr
* e
,
3399 IREndness IEndianess
)
3402 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I128
);
3404 /* read 128-bit IRTemp */
3405 if (e
->tag
== Iex_RdTmp
) {
3406 lookupIRTempQuad( rHi
, rMedHi
, rMedLo
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
3410 if (e
->tag
== Iex_Binop
) {
3412 IROp op_binop
= e
->Iex
.Binop
.op
;
3415 iselInt64Expr(rHi
, rMedHi
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3416 iselInt64Expr(rMedLo
, rLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3419 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3425 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e
->tag
);
3429 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3430 which is returned as the first two parameters. As with
3431 iselIntExpr_R, these may be either real or virtual regs; in any
3432 case they must not be changed by subsequent code emitted by the
3435 static void iselInt64Expr ( HReg
* rHi
, HReg
* rLo
,
3436 ISelEnv
* env
, const IRExpr
* e
,
3437 IREndness IEndianess
)
3439 vassert(!env
->mode64
);
3440 iselInt64Expr_wrk(rHi
, rLo
, env
, e
, IEndianess
);
3442 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
3444 vassert(hregClass(*rHi
) == HRcInt32
);
3445 vassert(hregIsVirtual(*rHi
));
3446 vassert(hregClass(*rLo
) == HRcInt32
);
3447 vassert(hregIsVirtual(*rLo
));
3450 /* DO NOT CALL THIS DIRECTLY ! */
3451 static void iselInt64Expr_wrk ( HReg
* rHi
, HReg
* rLo
,
3452 ISelEnv
* env
, const IRExpr
* e
,
3453 IREndness IEndianess
)
3456 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I64
);
3459 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
3460 HReg tLo
= newVRegI(env
);
3461 HReg tHi
= newVRegI(env
);
3462 HReg r_addr
= iselWordExpr_R(env
, e
->Iex
.Load
.addr
, IEndianess
);
3463 vassert(!env
->mode64
);
3464 addInstr(env
, PPCInstr_Load( 4/*byte-load*/,
3465 tHi
, PPCAMode_IR( 0, r_addr
),
3466 False
/*32-bit insn please*/) );
3467 addInstr(env
, PPCInstr_Load( 4/*byte-load*/,
3468 tLo
, PPCAMode_IR( 4, r_addr
),
3469 False
/*32-bit insn please*/) );
3475 /* 64-bit literal */
3476 if (e
->tag
== Iex_Const
) {
3477 ULong w64
= e
->Iex
.Const
.con
->Ico
.U64
;
3478 UInt wHi
= ((UInt
)(w64
>> 32)) & 0xFFFFFFFF;
3479 UInt wLo
= ((UInt
)w64
) & 0xFFFFFFFF;
3480 HReg tLo
= newVRegI(env
);
3481 HReg tHi
= newVRegI(env
);
3482 vassert(e
->Iex
.Const
.con
->tag
== Ico_U64
);
3483 addInstr(env
, PPCInstr_LI(tHi
, (Long
)(Int
)wHi
, False
/*mode32*/));
3484 addInstr(env
, PPCInstr_LI(tLo
, (Long
)(Int
)wLo
, False
/*mode32*/));
3490 /* read 64-bit IRTemp */
3491 if (e
->tag
== Iex_RdTmp
) {
3492 lookupIRTempPair( rHi
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
3497 if (e
->tag
== Iex_Get
) {
3498 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
3499 GuestStatePtr(False
/*mode32*/) );
3500 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
3501 HReg tLo
= newVRegI(env
);
3502 HReg tHi
= newVRegI(env
);
3503 addInstr(env
, PPCInstr_Load( 4, tHi
, am_addr
, False
/*mode32*/ ));
3504 addInstr(env
, PPCInstr_Load( 4, tLo
, am_addr4
, False
/*mode32*/ ));
3510 /* --------- CCALL --------- */
3511 if(e
->tag
== Iex_CCall
) {
3512 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
3513 Bool mode64
= env
->mode64
;
3515 vassert(ty
== e
->Iex
.CCall
.retty
); /* well-formedness of IR */
3517 /* be very restrictive for now. Only 32-bit ints allowed for
3518 args, and 32 bits or host machine word for return type. */
3519 vassert(!(ty
== Ity_I32
|| (mode64
&& ty
== Ity_I64
)));
3521 /* Marshal args, do the call, clear stack. */
3523 RetLoc rloc
= mk_RetLoc_INVALID();
3524 doHelperCall( &addToSp
, &rloc
, env
, NULL
/*guard*/,
3525 e
->Iex
.CCall
.cee
, e
->Iex
.CCall
.retty
, e
->Iex
.CCall
.args
,
3527 vassert(is_sane_RetLoc(rloc
));
3529 vassert(rloc
.pri
== RLPri_2Int
);
3530 vassert(addToSp
== 0);
3532 /* GPR3 now holds the destination address from Pin_Goto */
3533 HReg r_dst
= newVRegI(env
);
3534 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
3541 if (e
->tag
== Iex_ITE
) { // VFD
3542 HReg e0Lo
, e0Hi
, eXLo
, eXHi
;
3543 iselInt64Expr(&eXHi
, &eXLo
, env
, e
->Iex
.ITE
.iftrue
, IEndianess
);
3544 iselInt64Expr(&e0Hi
, &e0Lo
, env
, e
->Iex
.ITE
.iffalse
, IEndianess
);
3545 HReg tLo
= newVRegI(env
);
3546 HReg tHi
= newVRegI(env
);
3547 addInstr(env
, mk_iMOVds_RR(tHi
,e0Hi
));
3548 addInstr(env
, mk_iMOVds_RR(tLo
,e0Lo
));
3549 PPCCondCode cc
= iselCondCode(env
, e
->Iex
.ITE
.cond
, IEndianess
);
3550 addInstr(env
, PPCInstr_CMov(cc
,tHi
,PPCRI_Reg(eXHi
)));
3551 addInstr(env
, PPCInstr_CMov(cc
,tLo
,PPCRI_Reg(eXLo
)));
3557 /* --------- BINARY ops --------- */
3558 if (e
->tag
== Iex_Binop
) {
3559 IROp op_binop
= e
->Iex
.Binop
.op
;
3561 /* 32 x 32 -> 64 multiply */
3564 HReg tLo
= newVRegI(env
);
3565 HReg tHi
= newVRegI(env
);
3566 Bool syned
= toBool(op_binop
== Iop_MullS32
);
3567 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
,
3569 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
,
3571 addInstr(env
, PPCInstr_MulL(False
/*signedness irrelevant*/,
3572 False
/*lo32*/, True
/*32bit mul*/,
3573 tLo
, r_srcL
, r_srcR
));
3574 addInstr(env
, PPCInstr_MulL(syned
,
3575 True
/*hi32*/, True
/*32bit mul*/,
3576 tHi
, r_srcL
, r_srcR
));
3582 /* Or64/And64/Xor64 */
3586 HReg xLo
, xHi
, yLo
, yHi
;
3587 HReg tLo
= newVRegI(env
);
3588 HReg tHi
= newVRegI(env
);
3589 PPCAluOp op
= (op_binop
== Iop_Or64
) ? Palu_OR
:
3590 (op_binop
== Iop_And64
) ? Palu_AND
: Palu_XOR
;
3591 iselInt64Expr(&xHi
, &xLo
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3592 iselInt64Expr(&yHi
, &yLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3593 addInstr(env
, PPCInstr_Alu(op
, tHi
, xHi
, PPCRH_Reg(yHi
)));
3594 addInstr(env
, PPCInstr_Alu(op
, tLo
, xLo
, PPCRH_Reg(yLo
)));
3602 HReg xLo
, xHi
, yLo
, yHi
;
3603 HReg tLo
= newVRegI(env
);
3604 HReg tHi
= newVRegI(env
);
3605 iselInt64Expr(&xHi
, &xLo
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3606 iselInt64Expr(&yHi
, &yLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3607 addInstr(env
, PPCInstr_AddSubC( True
/*add*/, True
/*set carry*/,
3609 addInstr(env
, PPCInstr_AddSubC( True
/*add*/, False
/*read carry*/,
3616 /* 32HLto64(e1,e2) */
3618 *rHi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3619 *rLo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3623 case Iop_F64toI64S
: case Iop_F64toI64U
: {
3624 HReg tLo
= newVRegI(env
);
3625 HReg tHi
= newVRegI(env
);
3626 HReg r1
= StackFramePtr(env
->mode64
);
3627 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
3628 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
3629 HReg fsrc
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
,
3631 HReg ftmp
= newVRegF(env
);
3633 vassert(!env
->mode64
);
3634 /* Set host rounding mode */
3635 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3637 sub_from_sp( env
, 16 );
3638 addInstr(env
, PPCInstr_FpCftI(False
/*F->I*/, False
/*int64*/,
3639 (op_binop
== Iop_F64toI64S
) ? True
: False
,
3641 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
3642 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3643 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3644 add_to_sp( env
, 16 );
3646 ///* Restore default FPU rounding. */
3647 //set_FPU_rounding_default( env );
3652 case Iop_D64toI64S
: {
3653 HReg tLo
= newVRegI(env
);
3654 HReg tHi
= newVRegI(env
);
3655 HReg r1
= StackFramePtr(env
->mode64
);
3656 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
3657 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
3658 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3659 HReg tmp
= newVRegF(env
);
3661 vassert(!env
->mode64
);
3662 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3663 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DCTFIX
, tmp
, fr_src
));
3665 sub_from_sp( env
, 16 );
3666 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
3667 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3668 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3669 add_to_sp( env
, 16 );
3674 case Iop_D128toI64S
: {
3675 PPCFpOp fpop
= Pfp_DCTFIXQ
;
3676 HReg r_srcHi
= newVRegF(env
);
3677 HReg r_srcLo
= newVRegF(env
);
3678 HReg tLo
= newVRegI(env
);
3679 HReg tHi
= newVRegI(env
);
3680 HReg ftmp
= newVRegF(env
);
3681 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
3682 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
3684 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3685 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
3687 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, ftmp
, r_srcHi
, r_srcLo
));
3689 // put the D64 result into an integer register pair
3690 sub_from_sp( env
, 16 );
3691 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
3692 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3693 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3694 add_to_sp( env
, 16 );
3702 } /* if (e->tag == Iex_Binop) */
3705 /* --------- UNARY ops --------- */
3706 if (e
->tag
== Iex_Unop
) {
3707 switch (e
->Iex
.Unop
.op
) {
3710 case Iop_CmpwNEZ64
: {
3712 HReg tmp1
= newVRegI(env
);
3713 HReg tmp2
= newVRegI(env
);
3714 iselInt64Expr(&argHi
, &argLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3715 /* tmp1 = argHi | argLo */
3716 addInstr(env
, PPCInstr_Alu(Palu_OR
, tmp1
, argHi
, PPCRH_Reg(argLo
)));
3717 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3718 addInstr(env
, PPCInstr_Unary(Pun_NEG
,tmp2
,tmp1
));
3719 addInstr(env
, PPCInstr_Alu(Palu_OR
, tmp2
, tmp2
, PPCRH_Reg(tmp1
)));
3720 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
3721 tmp2
, tmp2
, PPCRH_Imm(False
, 31)));
3723 *rLo
= tmp2
; /* yes, really tmp2 */
3730 HReg zero32
= newVRegI(env
);
3731 HReg resHi
= newVRegI(env
);
3732 HReg resLo
= newVRegI(env
);
3733 iselInt64Expr(&argHi
, &argLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3734 vassert(env
->mode64
== False
);
3735 addInstr(env
, PPCInstr_LI(zero32
, 0, env
->mode64
));
3736 /* resHi:resLo = - argHi:argLo */
3737 addInstr(env
, PPCInstr_AddSubC( False
/*sub*/, True
/*set carry*/,
3738 resLo
, zero32
, argLo
));
3739 addInstr(env
, PPCInstr_AddSubC( False
/*sub*/, False
/*read carry*/,
3740 resHi
, zero32
, argHi
));
3741 /* resHi:resLo |= srcHi:srcLo */
3742 addInstr(env
, PPCInstr_Alu(Palu_OR
, resLo
, resLo
, PPCRH_Reg(argLo
)));
3743 addInstr(env
, PPCInstr_Alu(Palu_OR
, resHi
, resHi
, PPCRH_Reg(argHi
)));
3751 HReg tHi
= newVRegI(env
);
3752 HReg src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3753 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
3754 tHi
, src
, PPCRH_Imm(False
,31)));
3759 case Iop_ExtractExpD64
: {
3760 HReg tmp
= newVRegF(env
);
3761 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3762 HReg tLo
= newVRegI(env
);
3763 HReg tHi
= newVRegI(env
);
3764 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
3765 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
3767 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DXEX
, tmp
, fr_src
));
3769 // put the D64 result into a integer register pair
3770 sub_from_sp( env
, 16 );
3771 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
3772 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3773 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3774 add_to_sp( env
, 16 );
3779 case Iop_ExtractExpD128
: {
3782 HReg tmp
= newVRegF(env
);
3783 HReg tLo
= newVRegI(env
);
3784 HReg tHi
= newVRegI(env
);
3785 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
3786 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
3788 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3789 addInstr(env
, PPCInstr_ExtractExpD128(Pfp_DXEXQ
, tmp
,
3792 // put the D64 result into a integer register pair
3793 sub_from_sp( env
, 16 );
3794 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
3795 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3796 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3797 add_to_sp( env
, 16 );
3805 HReg tHi
= newVRegI(env
);
3806 HReg tLo
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3807 addInstr(env
, PPCInstr_LI(tHi
, 0, False
/*mode32*/));
3814 /* Narrow, return the low 64-bit half as a 32-bit
3816 HReg r_Hi
= INVALID_HREG
;
3817 HReg r_MedHi
= INVALID_HREG
;
3818 HReg r_MedLo
= INVALID_HREG
;
3819 HReg r_Lo
= INVALID_HREG
;
3821 iselInt128Expr_to_32x4(&r_Hi
, &r_MedHi
, &r_MedLo
, &r_Lo
,
3822 env
, e
->Iex
.Unop
.arg
, IEndianess
);
3828 case Iop_128HIto64
: {
3829 /* Narrow, return the high 64-bit half as a 32-bit
3831 HReg r_Hi
= INVALID_HREG
;
3832 HReg r_MedHi
= INVALID_HREG
;
3833 HReg r_MedLo
= INVALID_HREG
;
3834 HReg r_Lo
= INVALID_HREG
;
3836 iselInt128Expr_to_32x4(&r_Hi
, &r_MedHi
, &r_MedLo
, &r_Lo
,
3837 env
, e
->Iex
.Unop
.arg
, IEndianess
);
3844 case Iop_V128HIto64
:
3845 case Iop_V128to64
: {
3847 Int off
= e
->Iex
.Unop
.op
==Iop_V128HIto64
? 0 : 8;
3848 HReg tLo
= newVRegI(env
);
3849 HReg tHi
= newVRegI(env
);
3850 HReg vec
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3851 PPCAMode
*am_off0
, *am_offLO
, *am_offHI
;
3852 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
3854 // get a quadword aligned address within our stack space
3855 r_aligned16
= get_sp_aligned16( env
);
3856 am_off0
= PPCAMode_IR( 0, r_aligned16
);
3857 am_offHI
= PPCAMode_IR( off
, r_aligned16
);
3858 am_offLO
= PPCAMode_IR( off
+4, r_aligned16
);
3862 PPCInstr_AvLdSt( False
/*store*/, 16, vec
, am_off0
));
3864 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3866 PPCInstr_Load( 4, tHi
, am_offHI
, False
/*mode32*/ ));
3868 PPCInstr_Load( 4, tLo
, am_offLO
, False
/*mode32*/ ));
3870 add_to_sp( env
, 32 ); // Reset SP
3876 /* could do better than this, but for now ... */
3878 HReg tLo
= newVRegI(env
);
3879 HReg tHi
= newVRegI(env
);
3880 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3881 addInstr(env
, PPCInstr_Set(cond
,tLo
));
3882 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
3883 tLo
, tLo
, PPCRH_Imm(False
,31)));
3884 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
3885 tLo
, tLo
, PPCRH_Imm(False
,31)));
3886 addInstr(env
, mk_iMOVds_RR(tHi
, tLo
));
3894 HReg tmpLo
= newVRegI(env
);
3895 HReg tmpHi
= newVRegI(env
);
3896 iselInt64Expr(&xHi
, &xLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3897 addInstr(env
, PPCInstr_Unary(Pun_NOT
,tmpLo
,xLo
));
3898 addInstr(env
, PPCInstr_Unary(Pun_NOT
,tmpHi
,xHi
));
3904 /* ReinterpF64asI64(e) */
3905 /* Given an IEEE754 double, produce an I64 with the same bit
3907 case Iop_ReinterpF64asI64
: {
3908 PPCAMode
*am_addr0
, *am_addr1
;
3909 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3910 HReg r_dstLo
= newVRegI(env
);
3911 HReg r_dstHi
= newVRegI(env
);
3913 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
3914 am_addr0
= PPCAMode_IR( 0, StackFramePtr(False
/*mode32*/) );
3915 am_addr1
= PPCAMode_IR( 4, StackFramePtr(False
/*mode32*/) );
3918 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
3919 fr_src
, am_addr0
));
3921 // load hi,lo as Ity_I32's
3922 addInstr(env
, PPCInstr_Load( 4, r_dstHi
,
3923 am_addr0
, False
/*mode32*/ ));
3924 addInstr(env
, PPCInstr_Load( 4, r_dstLo
,
3925 am_addr1
, False
/*mode32*/ ));
3929 add_to_sp( env
, 16 ); // Reset SP
3933 case Iop_ReinterpD64asI64
: {
3934 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3935 PPCAMode
*am_addr0
, *am_addr1
;
3936 HReg r_dstLo
= newVRegI(env
);
3937 HReg r_dstHi
= newVRegI(env
);
3940 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
3941 am_addr0
= PPCAMode_IR( 0, StackFramePtr(False
/*mode32*/) );
3942 am_addr1
= PPCAMode_IR( 4, StackFramePtr(False
/*mode32*/) );
3945 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
3946 fr_src
, am_addr0
));
3948 // load hi,lo as Ity_I32's
3949 addInstr(env
, PPCInstr_Load( 4, r_dstHi
,
3950 am_addr0
, False
/*mode32*/ ));
3951 addInstr(env
, PPCInstr_Load( 4, r_dstLo
,
3952 am_addr1
, False
/*mode32*/ ));
3956 add_to_sp( env
, 16 ); // Reset SP
3961 case Iop_BCDtoDPB
: {
3966 HReg tLo
= newVRegI(env
);
3967 HReg tHi
= newVRegI(env
);
3970 Bool mode64
= env
->mode64
;
3972 argregs
[0] = hregPPC_GPR3(mode64
);
3973 argregs
[1] = hregPPC_GPR4(mode64
);
3978 iselInt64Expr( &tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3980 argiregs
|= ( 1 << (argreg
+3 ) );
3981 addInstr( env
, mk_iMOVds_RR( argregs
[argreg
++], tmpHi
) );
3983 argiregs
|= ( 1 << (argreg
+3 ) );
3984 addInstr( env
, mk_iMOVds_RR( argregs
[argreg
], tmpLo
) );
3986 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
3988 if (IEndianess
== Iend_LE
) {
3989 addInstr( env
, PPCInstr_Call( cc
, (Addr
)h_calc_BCDtoDPB
,
3991 mk_RetLoc_simple(RLPri_2Int
) ) );
3994 target
= mode64
? (Addr
)h_calc_BCDtoDPB
:
3995 toUInt( (Addr
)h_calc_BCDtoDPB
);
3996 addInstr( env
, PPCInstr_Call( cc
, target
,
3998 mk_RetLoc_simple(RLPri_2Int
) ) );
4001 addInstr( env
, mk_iMOVds_RR( tHi
, argregs
[argreg
-1] ) );
4002 addInstr( env
, mk_iMOVds_RR( tLo
, argregs
[argreg
] ) );
4009 case Iop_DPBtoBCD
: {
4014 HReg tLo
= newVRegI(env
);
4015 HReg tHi
= newVRegI(env
);
4018 Bool mode64
= env
->mode64
;
4020 argregs
[0] = hregPPC_GPR3(mode64
);
4021 argregs
[1] = hregPPC_GPR4(mode64
);
4026 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
4028 argiregs
|= (1 << (argreg
+3));
4029 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++], tmpHi
));
4031 argiregs
|= (1 << (argreg
+3));
4032 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
], tmpLo
));
4034 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
4036 if (IEndianess
== Iend_LE
) {
4037 addInstr(env
, PPCInstr_Call( cc
, (Addr
)h_calc_DPBtoBCD
,
4039 mk_RetLoc_simple(RLPri_2Int
) ) );
4042 target
= mode64
? (Addr
)h_calc_DPBtoBCD
:
4043 toUInt( (Addr
)h_calc_DPBtoBCD
);
4044 addInstr(env
, PPCInstr_Call( cc
, target
, argiregs
,
4045 mk_RetLoc_simple(RLPri_2Int
) ) );
4048 addInstr(env
, mk_iMOVds_RR(tHi
, argregs
[argreg
-1]));
4049 addInstr(env
, mk_iMOVds_RR(tLo
, argregs
[argreg
]));
4059 } /* if (e->tag == Iex_Unop) */
4061 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e
->tag
);
4063 vpanic("iselInt64Expr(ppc)");
4067 /*---------------------------------------------------------*/
4068 /*--- ISEL: Floating point expressions (32 bit) ---*/
4069 /*---------------------------------------------------------*/
4071 /* Nothing interesting here; really just wrappers for
4074 static HReg
iselFltExpr ( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4076 HReg r
= iselFltExpr_wrk( env
, e
, IEndianess
);
4078 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
4080 vassert(hregClass(r
) == HRcFlt64
); /* yes, really Flt64 */
4081 vassert(hregIsVirtual(r
));
4085 /* DO NOT CALL THIS DIRECTLY */
4086 static HReg
iselFltExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
4087 IREndness IEndianess
)
4089 Bool mode64
= env
->mode64
;
4091 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
4092 vassert(ty
== Ity_F32
);
4094 if (e
->tag
== Iex_RdTmp
) {
4095 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
4098 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4100 HReg r_dst
= newVRegF(env
);
4101 vassert(e
->Iex
.Load
.ty
== Ity_F32
);
4102 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_F32
/*xfer*/,
4104 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 4, r_dst
, am_addr
));
4108 if (e
->tag
== Iex_Get
) {
4109 HReg r_dst
= newVRegF(env
);
4110 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4111 GuestStatePtr(env
->mode64
) );
4112 addInstr(env
, PPCInstr_FpLdSt( True
/*load*/, 4, r_dst
, am_addr
));
4116 if (e
->tag
== Iex_Unop
&& e
->Iex
.Unop
.op
== Iop_TruncF64asF32
) {
4117 /* This is quite subtle. The only way to do the relevant
4118 truncation is to do a single-precision store and then a
4119 double precision load to get it back into a register. The
4120 problem is, if the data is then written to memory a second
4123 STbe(...) = TruncF64asF32(...)
4125 then will the second truncation further alter the value? The
4126 answer is no: flds (as generated here) followed by fsts
4127 (generated for the STbe) is the identity function on 32-bit
4128 floats, so we are safe.
4130 Another upshot of this is that if iselStmt can see the
4133 STbe(...) = TruncF64asF32(arg)
4135 then it can short circuit having to deal with TruncF64asF32
4136 individually; instead just compute arg into a 64-bit FP
4137 register and do 'fsts' (since that itself does the
4140 We generate pretty poor code here (should be ok both for
4141 32-bit and 64-bit mode); but it is expected that for the most
4142 part the latter optimisation will apply and hence this code
4143 will not often be used.
4145 HReg fsrc
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4146 HReg fdst
= newVRegF(env
);
4147 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4149 sub_from_sp( env
, 16 );
4150 // store as F32, hence truncating
4151 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 4,
4153 // and reload. Good huh?! (sigh)
4154 addInstr(env
, PPCInstr_FpLdSt( True
/*load*/, 4,
4156 add_to_sp( env
, 16 );
4160 if (e
->tag
== Iex_Binop
&& e
->Iex
.Binop
.op
== Iop_I64UtoF32
) {
4162 HReg fdst
= newVRegF(env
);
4163 HReg isrc
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4164 HReg r1
= StackFramePtr(env
->mode64
);
4165 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4167 /* Set host rounding mode */
4168 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4170 sub_from_sp( env
, 16 );
4172 addInstr(env
, PPCInstr_Store(8, zero_r1
, isrc
, True
/*mode64*/));
4173 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4174 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4178 add_to_sp( env
, 16 );
4180 ///* Restore default FPU rounding. */
4181 //set_FPU_rounding_default( env );
4185 HReg fdst
= newVRegF(env
);
4186 HReg isrcHi
, isrcLo
;
4187 HReg r1
= StackFramePtr(env
->mode64
);
4188 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4189 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
4191 iselInt64Expr(&isrcHi
, &isrcLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4193 /* Set host rounding mode */
4194 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4196 sub_from_sp( env
, 16 );
4198 addInstr(env
, PPCInstr_Store(4, zero_r1
, isrcHi
, False
/*mode32*/));
4199 addInstr(env
, PPCInstr_Store(4, four_r1
, isrcLo
, False
/*mode32*/));
4200 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4201 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4205 add_to_sp( env
, 16 );
4207 ///* Restore default FPU rounding. */
4208 //set_FPU_rounding_default( env );
4214 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e
->tag
);
4216 vpanic("iselFltExpr_wrk(ppc)");
4220 /*---------------------------------------------------------*/
4221 /*--- ISEL: Floating point expressions (64 bit) ---*/
4222 /*---------------------------------------------------------*/
4224 /* Compute a 64-bit floating point value into a register, the identity
4225 of which is returned. As with iselIntExpr_R, the reg may be either
4226 real or virtual; in any case it must not be changed by subsequent
4227 code emitted by the caller. */
4229 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
4231 Type S (1 bit) E (11 bits) F (52 bits)
4232 ---- --------- ----------- -----------
4233 signalling NaN u 2047 (max) .0uuuuu---u
4236 quiet NaN u 2047 (max) .1uuuuu---u
4238 negative infinity 1 2047 (max) .000000---0
4240 positive infinity 0 2047 (max) .000000---0
4242 negative zero 1 0 .000000---0
4244 positive zero 0 0 .000000---0
4247 static HReg
iselDblExpr ( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4249 HReg r
= iselDblExpr_wrk( env
, e
, IEndianess
);
4251 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
4253 vassert(hregClass(r
) == HRcFlt64
);
4254 vassert(hregIsVirtual(r
));
4258 /* DO NOT CALL THIS DIRECTLY */
4259 static HReg
iselDblExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
4260 IREndness IEndianess
)
4262 Bool mode64
= env
->mode64
;
4263 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
4265 vassert(ty
== Ity_F64
);
4267 if (e
->tag
== Iex_RdTmp
) {
4268 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
4271 /* --------- LITERAL --------- */
4272 if (e
->tag
== Iex_Const
) {
4273 union { UInt u32x2
[2]; ULong u64
; Double f64
; } u
;
4274 vassert(sizeof(u
) == 8);
4275 vassert(sizeof(u
.u64
) == 8);
4276 vassert(sizeof(u
.f64
) == 8);
4277 vassert(sizeof(u
.u32x2
) == 8);
4279 if (e
->Iex
.Const
.con
->tag
== Ico_F64
) {
4280 u
.f64
= e
->Iex
.Const
.con
->Ico
.F64
;
4282 else if (e
->Iex
.Const
.con
->tag
== Ico_F64i
) {
4283 u
.u64
= e
->Iex
.Const
.con
->Ico
.F64i
;
4286 vpanic("iselDblExpr(ppc): const");
4289 HReg r_srcHi
= newVRegI(env
);
4290 HReg r_srcLo
= newVRegI(env
);
4291 addInstr(env
, PPCInstr_LI(r_srcHi
, u
.u32x2
[0], mode64
));
4292 addInstr(env
, PPCInstr_LI(r_srcLo
, u
.u32x2
[1], mode64
));
4293 return mk_LoadRR32toFPR( env
, r_srcHi
, r_srcLo
);
4295 HReg r_src
= newVRegI(env
);
4296 addInstr(env
, PPCInstr_LI(r_src
, u
.u64
, mode64
));
4297 return mk_LoadR64toFPR( env
, r_src
); // 1*I64 -> F64
4301 /* --------- LOAD --------- */
4302 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4303 HReg r_dst
= newVRegF(env
);
4305 vassert(e
->Iex
.Load
.ty
== Ity_F64
);
4306 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_F64
/*xfer*/,
4308 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dst
, am_addr
));
4312 /* --------- GET --------- */
4313 if (e
->tag
== Iex_Get
) {
4314 HReg r_dst
= newVRegF(env
);
4315 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4316 GuestStatePtr(mode64
) );
4317 addInstr(env
, PPCInstr_FpLdSt( True
/*load*/, 8, r_dst
, am_addr
));
4321 /* --------- OPS --------- */
4322 if (e
->tag
== Iex_Qop
) {
4323 PPCFpOp fpop
= Pfp_INVALID
;
4324 switch (e
->Iex
.Qop
.details
->op
) {
4325 case Iop_MAddF64
: fpop
= Pfp_MADDD
; break;
4326 case Iop_MAddF64r32
: fpop
= Pfp_MADDS
; break;
4327 case Iop_MSubF64
: fpop
= Pfp_MSUBD
; break;
4328 case Iop_MSubF64r32
: fpop
= Pfp_MSUBS
; break;
4331 if (fpop
!= Pfp_INVALID
) {
4332 HReg r_dst
= newVRegF(env
);
4333 HReg r_srcML
= iselDblExpr(env
, e
->Iex
.Qop
.details
->arg2
,
4335 HReg r_srcMR
= iselDblExpr(env
, e
->Iex
.Qop
.details
->arg3
,
4337 HReg r_srcAcc
= iselDblExpr(env
, e
->Iex
.Qop
.details
->arg4
,
4339 set_FPU_rounding_mode( env
, e
->Iex
.Qop
.details
->arg1
, IEndianess
);
4340 addInstr(env
, PPCInstr_FpMulAcc(fpop
, r_dst
,
4341 r_srcML
, r_srcMR
, r_srcAcc
));
4346 if (e
->tag
== Iex_Triop
) {
4347 IRTriop
*triop
= e
->Iex
.Triop
.details
;
4348 PPCFpOp fpop
= Pfp_INVALID
;
4349 switch (triop
->op
) {
4350 case Iop_AddF64
: fpop
= Pfp_ADDD
; break;
4351 case Iop_SubF64
: fpop
= Pfp_SUBD
; break;
4352 case Iop_MulF64
: fpop
= Pfp_MULD
; break;
4353 case Iop_DivF64
: fpop
= Pfp_DIVD
; break;
4354 case Iop_AddF64r32
: fpop
= Pfp_ADDS
; break;
4355 case Iop_SubF64r32
: fpop
= Pfp_SUBS
; break;
4356 case Iop_MulF64r32
: fpop
= Pfp_MULS
; break;
4357 case Iop_DivF64r32
: fpop
= Pfp_DIVS
; break;
4360 if (fpop
!= Pfp_INVALID
) {
4361 HReg r_dst
= newVRegF(env
);
4362 HReg r_srcL
= iselDblExpr(env
, triop
->arg2
, IEndianess
);
4363 HReg r_srcR
= iselDblExpr(env
, triop
->arg3
, IEndianess
);
4364 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4365 addInstr(env
, PPCInstr_FpBinary(fpop
, r_dst
, r_srcL
, r_srcR
));
4370 if (e
->tag
== Iex_Binop
) {
4371 PPCFpOp fpop
= Pfp_INVALID
;
4372 switch (e
->Iex
.Binop
.op
) {
4373 case Iop_SqrtF64
: fpop
= Pfp_SQRT
; break;
4376 if (fpop
== Pfp_SQRT
) {
4377 HReg fr_dst
= newVRegF(env
);
4378 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4379 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4380 addInstr(env
, PPCInstr_FpUnary(fpop
, fr_dst
, fr_src
));
4385 if (e
->tag
== Iex_Binop
) {
4387 if (e
->Iex
.Binop
.op
== Iop_F128toF64
) {
4388 HReg fr_dst
= newVRegF(env
);
4389 HReg fr_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4390 HReg tmp
= newVRegV(env
);
4391 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4392 PPCAMode
* eight_r1
= PPCAMode_IR( 8, StackFramePtr(env
->mode64
) );
4393 PPCFpOp fpop
= Pfp_INVALID
;
4395 if (FPU_rounding_mode_isOdd(e
->Iex
.Binop
.arg1
)) {
4396 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4397 fpop
= Pfp_FPQTODRNDODD
;
4399 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4403 addInstr(env
, PPCInstr_Fp128Unary(fpop
, tmp
, fr_src
));
4405 /* result is in a 128-bit vector register, move to 64-bit reg to
4406 * match the Iop specification. The result will get moved back
4407 * to a 128-bit register and stored once the value is returned.
4409 sub_from_sp( env
, 16 );
4410 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, tmp
, zero_r1
));
4411 if (IEndianess
== Iend_LE
)
4412 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_dst
, eight_r1
));
4414 /* High 64-bits stored at lower address */
4415 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_dst
, zero_r1
));
4417 add_to_sp( env
, 16 );
4422 if (e
->Iex
.Binop
.op
== Iop_RoundF64toF32
) {
4423 HReg r_dst
= newVRegF(env
);
4424 HReg r_src
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4425 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4426 addInstr(env
, PPCInstr_FpRSP(r_dst
, r_src
));
4427 //set_FPU_rounding_default( env );
4431 if (e
->Iex
.Binop
.op
== Iop_I64StoF64
|| e
->Iex
.Binop
.op
== Iop_I64UtoF64
) {
4433 HReg fdst
= newVRegF(env
);
4434 HReg isrc
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4435 HReg r1
= StackFramePtr(env
->mode64
);
4436 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4438 /* Set host rounding mode */
4439 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4441 sub_from_sp( env
, 16 );
4443 addInstr(env
, PPCInstr_Store(8, zero_r1
, isrc
, True
/*mode64*/));
4444 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4445 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4446 e
->Iex
.Binop
.op
== Iop_I64StoF64
,
4447 True
/*fdst is 64 bit*/,
4450 add_to_sp( env
, 16 );
4452 ///* Restore default FPU rounding. */
4453 //set_FPU_rounding_default( env );
4457 HReg fdst
= newVRegF(env
);
4458 HReg isrcHi
, isrcLo
;
4459 HReg r1
= StackFramePtr(env
->mode64
);
4460 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4461 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
4463 iselInt64Expr(&isrcHi
, &isrcLo
, env
, e
->Iex
.Binop
.arg2
,
4466 /* Set host rounding mode */
4467 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4469 sub_from_sp( env
, 16 );
4471 addInstr(env
, PPCInstr_Store(4, zero_r1
, isrcHi
, False
/*mode32*/));
4472 addInstr(env
, PPCInstr_Store(4, four_r1
, isrcLo
, False
/*mode32*/));
4473 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4474 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4475 e
->Iex
.Binop
.op
== Iop_I64StoF64
,
4476 True
/*fdst is 64 bit*/,
4479 add_to_sp( env
, 16 );
4481 ///* Restore default FPU rounding. */
4482 //set_FPU_rounding_default( env );
4489 if (e
->tag
== Iex_Unop
) {
4490 PPCFpOp fpop
= Pfp_INVALID
;
4491 switch (e
->Iex
.Unop
.op
) {
4492 case Iop_NegF64
: fpop
= Pfp_NEG
; break;
4493 case Iop_AbsF64
: fpop
= Pfp_ABS
; break;
4494 case Iop_RSqrtEst5GoodF64
: fpop
= Pfp_RSQRTE
; break;
4495 case Iop_RoundF64toF64_NegINF
: fpop
= Pfp_FRIM
; break;
4496 case Iop_RoundF64toF64_PosINF
: fpop
= Pfp_FRIP
; break;
4497 case Iop_RoundF64toF64_NEAREST
: fpop
= Pfp_FRIN
; break;
4498 case Iop_RoundF64toF64_ZERO
: fpop
= Pfp_FRIZ
; break;
4501 if (fpop
!= Pfp_INVALID
) {
4502 HReg fr_dst
= newVRegF(env
);
4503 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4504 addInstr(env
, PPCInstr_FpUnary(fpop
, fr_dst
, fr_src
));
4509 if (e
->tag
== Iex_Unop
) {
4510 switch (e
->Iex
.Unop
.op
) {
4511 case Iop_F128HItoF64
:
4512 case Iop_F128LOtoF64
:
4514 /* put upper/lower 64-bits of F128 into an F64. */
4516 HReg fdst
= newVRegF(env
);
4517 HReg fsrc
= iselFp128Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4518 PPCAMode
*am_off0
, *am_off8
, *am_off_arg
;
4519 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
4521 // get a quadword aligned address within our stack space
4522 r_aligned16
= get_sp_aligned16( env
);
4523 am_off0
= PPCAMode_IR( 0, r_aligned16
);
4524 am_off8
= PPCAMode_IR( 8 ,r_aligned16
);
4526 /* store 128-bit floating point value to memory, load low word
4527 * or high to 64-bit destination floating point register
4529 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, fsrc
, am_off0
));
4530 if (IEndianess
== Iend_LE
) {
4531 if (e
->Iex
.Binop
.op
== Iop_F128HItoF64
)
4532 am_off_arg
= am_off8
;
4534 am_off_arg
= am_off0
;
4536 if (e
->Iex
.Binop
.op
== Iop_F128HItoF64
)
4537 am_off_arg
= am_off0
;
4539 am_off_arg
= am_off8
;
4542 PPCInstr_FpLdSt( True
/*load*/,
4545 add_to_sp( env
, 32 ); // Reset SP
4548 case Iop_ReinterpI64asF64
: {
4549 /* Given an I64, produce an IEEE754 double with the same
4552 HReg r_srcHi
, r_srcLo
;
4553 iselInt64Expr( &r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
,
4555 return mk_LoadRR32toFPR( env
, r_srcHi
, r_srcLo
);
4557 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4558 return mk_LoadR64toFPR( env
, r_src
);
4562 case Iop_F32toF64
: {
4563 if (e
->Iex
.Unop
.arg
->tag
== Iex_Unop
&&
4564 e
->Iex
.Unop
.arg
->Iex
.Unop
.op
== Iop_ReinterpI32asF32
) {
4565 e
= e
->Iex
.Unop
.arg
;
4567 HReg src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4568 HReg fr_dst
= newVRegF(env
);
4571 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
4572 am_addr
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4574 // store src as Ity_I32's
4575 addInstr(env
, PPCInstr_Store( 4, am_addr
, src
, env
->mode64
));
4577 // load single precision float, but the end results loads into a
4578 // 64-bit FP register -- i.e., F64.
4579 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 4, fr_dst
, am_addr
));
4581 add_to_sp( env
, 16 ); // Reset SP
4586 /* this is a no-op */
4587 HReg res
= iselFltExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4595 /* --------- MULTIPLEX --------- */
4596 if (e
->tag
== Iex_ITE
) { // VFD
4598 && typeOfIRExpr(env
->type_env
,e
->Iex
.ITE
.cond
) == Ity_I1
) {
4599 HReg fr1
= iselDblExpr(env
, e
->Iex
.ITE
.iftrue
, IEndianess
);
4600 HReg fr0
= iselDblExpr(env
, e
->Iex
.ITE
.iffalse
, IEndianess
);
4601 HReg fr_dst
= newVRegF(env
);
4602 addInstr(env
, PPCInstr_FpUnary( Pfp_MOV
, fr_dst
, fr0
));
4603 PPCCondCode cc
= iselCondCode(env
, e
->Iex
.ITE
.cond
, IEndianess
);
4604 addInstr(env
, PPCInstr_FpCMov( cc
, fr_dst
, fr1
));
4609 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e
->tag
);
4611 vpanic("iselDblExpr_wrk(ppc)");
4614 static HReg
iselDfp32Expr(ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4616 HReg r
= iselDfp32Expr_wrk( env
, e
, IEndianess
);
4617 vassert(hregClass(r
) == HRcFlt64
);
4618 vassert( hregIsVirtual(r
) );
4622 /* DO NOT CALL THIS DIRECTLY */
4623 static HReg
iselDfp32Expr_wrk(ISelEnv
* env
, const IRExpr
* e
,
4624 IREndness IEndianess
)
4626 Bool mode64
= env
->mode64
;
4627 IRType ty
= typeOfIRExpr( env
->type_env
, e
);
4630 vassert( ty
== Ity_D32
);
4632 /* --------- GET --------- */
4633 if (e
->tag
== Iex_Get
) {
4634 HReg r_dst
= newVRegF( env
);
4635 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4636 GuestStatePtr(mode64
) );
4637 addInstr( env
, PPCInstr_FpLdSt( True
/*load*/, 8, r_dst
, am_addr
) );
4641 /* --------- LOAD --------- */
4642 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4644 HReg r_dst
= newVRegF(env
);
4645 vassert(e
->Iex
.Load
.ty
== Ity_D32
);
4646 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_D32
/*xfer*/,
4648 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 4, r_dst
, am_addr
));
4652 /* --------- OPS --------- */
4653 if (e
->tag
== Iex_Binop
) {
4654 if (e
->Iex
.Binop
.op
== Iop_D64toD32
) {
4655 HReg fr_dst
= newVRegF(env
);
4656 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4657 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4658 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DRSP
, fr_dst
, fr_src
));
4664 vpanic( "iselDfp32Expr_wrk(ppc)" );
4667 static HReg
iselFp128Expr( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4669 HReg r
= iselFp128Expr_wrk( env
, e
, IEndianess
);
4670 vassert(hregClass(r
) == HRcVec128
);
4671 vassert(hregIsVirtual(r
));
4675 /* DO NOT CALL THIS DIRECTLY */
4676 static HReg
iselFp128Expr_wrk( ISelEnv
* env
, const IRExpr
* e
,
4677 IREndness IEndianess
)
4679 Bool mode64
= env
->mode64
;
4680 PPCFpOp fpop
= Pfp_INVALID
;
4681 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
4684 vassert( ty
== Ity_F128
);
4686 /* read 128-bit IRTemp */
4687 if (e
->tag
== Iex_RdTmp
) {
4688 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
4691 if (e
->tag
== Iex_Get
) {
4692 /* Guest state vectors are 16byte aligned,
4693 so don't need to worry here */
4694 HReg dst
= newVRegV(env
);
4697 PPCInstr_AvLdSt( True
/*load*/, 16, dst
,
4698 PPCAMode_IR( e
->Iex
.Get
.offset
,
4699 GuestStatePtr(mode64
) )));
4703 if (e
->tag
== Iex_Unop
) {
4704 switch (e
->Iex
.Unop
.op
) {
4705 case Iop_TruncF128toI64S
:
4706 fpop
= Pfp_TRUNCFPQTOISD
; goto do_Un_F128
;
4707 case Iop_TruncF128toI32S
:
4708 fpop
= Pfp_TRUNCFPQTOISW
; goto do_Un_F128
;
4709 case Iop_TruncF128toI64U
:
4710 fpop
= Pfp_TRUNCFPQTOIUD
; goto do_Un_F128
;
4711 case Iop_TruncF128toI32U
:
4712 fpop
= Pfp_TRUNCFPQTOIUW
; goto do_Un_F128
;
4715 HReg r_dst
= newVRegV(env
);
4716 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4717 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, r_src
));
4721 case Iop_F64toF128
: {
4723 HReg r_dst
= newVRegV(env
);
4724 HReg r_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4725 HReg v128tmp
= newVRegV(env
);
4726 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4728 /* value is in 64-bit float reg, need to move to 128-bit vector reg */
4729 sub_from_sp( env
, 16 );
4730 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, r_src
, zero_r1
));
4731 addInstr(env
, PPCInstr_AvLdSt(True
/*load*/, 16, v128tmp
, zero_r1
));
4732 add_to_sp( env
, 16 );
4734 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, v128tmp
));
4738 case Iop_I64StoF128
:
4739 fpop
= Pfp_IDSTOQ
; goto do_Un_int_F128
;
4740 case Iop_I64UtoF128
:
4741 fpop
= Pfp_IDUTOQ
; goto do_Un_int_F128
;
4744 HReg r_dst
= newVRegV(env
);
4745 HReg tmp
= newVRegV(env
);
4746 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4747 PPCAMode
*am_offhi
, *am_offlo
;
4750 /* source is in a 64-bit integer reg, move to 128-bit float reg
4751 * do this via the stack (easy, convenient, etc).
4753 sub_from_sp( env
, 32 ); // Move SP down
4755 /* Get a quadword aligned address within our stack space */
4756 r_aligned16
= get_sp_aligned16( env
);
4758 am_offlo
= PPCAMode_IR( 0, r_aligned16
);
4759 am_offhi
= PPCAMode_IR( 8, r_aligned16
);
4761 /* Inst only uses the upper 64-bit of the source */
4762 addInstr(env
, PPCInstr_Load(8, r_src
, am_offhi
, mode64
));
4764 /* Fetch result back from stack. */
4765 addInstr(env
, PPCInstr_AvLdSt(True
/*load*/, 16, tmp
, am_offlo
));
4767 add_to_sp( env
, 32 ); // Reset SP
4769 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, tmp
));
4775 } /* switch (e->Iex.Unop.op) */
4776 } /* if (e->tag == Iex_Unop) */
4778 if (e
->tag
== Iex_Binop
) {
4779 switch (e
->Iex
.Binop
.op
) {
4781 case Iop_F64HLtoF128
:
4783 HReg dst
= newVRegV(env
);
4784 HReg r_src_hi
= iselDblExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4785 HReg r_src_lo
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4786 PPCAMode
*am_offhi
, *am_offlo
;
4789 /* do this via the stack (easy, convenient, etc) */
4790 sub_from_sp( env
, 16 ); // Move SP down
4792 /* Get a quadword aligned address within our stack space */
4793 r_aligned16
= get_sp_aligned16( env
);
4795 am_offlo
= PPCAMode_IR( 0, r_aligned16
);
4796 am_offhi
= PPCAMode_IR( 8, r_aligned16
);
4798 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8,
4799 r_src_lo
, am_offlo
));
4800 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8,
4801 r_src_hi
, am_offhi
));
4803 /* Fetch result back from stack. */
4804 addInstr(env
, PPCInstr_AvLdSt(True
/*load*/, 16,
4807 add_to_sp( env
, 16 ); // Reset SP
4810 case Iop_F128toI128S
:
4812 HReg dst
= newVRegV(env
);
4813 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4814 PPCRI
* rm
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4815 /* Note: rm is a set of three bit fields that specify the
4816 * rounding mode and which of the two instructions to issue.
4818 addInstr(env
, PPCInstr_AvBinaryInt(Pav_F128toI128S
, dst
,
4824 HReg dst
= newVRegV(env
);
4825 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4826 PPCRI
* rm
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4827 /* Note: rm is a set of three bit fields that specify the
4828 * rounding mode and which of the two instructions to issue.
4830 addInstr(env
, PPCInstr_AvBinaryInt(Pav_ROUNDFPQ
, dst
,
4835 if (FPU_rounding_mode_isOdd(e
->Iex
.Binop
.arg1
)) {
4836 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4837 fpop
= Pfp_FPSQRTQRNDODD
;
4840 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4845 if (FPU_rounding_mode_isOdd(e
->Iex
.Binop
.arg1
)) {
4846 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4847 fpop
= Pfp_FPQTOWRNDODD
;
4850 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4855 HReg r_dst
= newVRegV(env
);
4856 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4857 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, r_src
));
4863 } /* switch (e->Iex.Binop.op) */
4864 } /* if (e->tag == Iex_Binop) */
4866 if (e
->tag
== Iex_Triop
) {
4867 IRTriop
*triop
= e
->Iex
.Triop
.details
;
4869 switch (triop
->op
) {
4871 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4872 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4873 fpop
= Pfp_FPADDQRNDODD
; goto do_Tri_F128
;
4875 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4876 fpop
= Pfp_FPADDQ
; goto do_Tri_F128
;
4879 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4880 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4881 fpop
= Pfp_FPSUBQRNDODD
; goto do_Tri_F128
;
4883 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4884 fpop
= Pfp_FPSUBQ
; goto do_Tri_F128
;
4887 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4888 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4889 fpop
= Pfp_FPMULQRNDODD
; goto do_Tri_F128
;
4891 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4892 fpop
= Pfp_FPMULQ
; goto do_Tri_F128
;
4895 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4896 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4897 fpop
= Pfp_FPDIVQRNDODD
; goto do_Tri_F128
;
4899 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4900 fpop
= Pfp_FPDIVQ
; goto do_Tri_F128
;
4903 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4904 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4905 fpop
= Pfp_FPMULADDQRNDODD
; goto do_Tri_F128
;
4907 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4908 fpop
= Pfp_FPMULADDQ
; goto do_Tri_F128
;
4912 HReg r_dst
= newVRegV(env
);
4913 HReg r_srcL
= iselFp128Expr(env
, triop
->arg2
, IEndianess
);
4914 HReg r_srcR
= iselFp128Expr(env
, triop
->arg3
, IEndianess
);
4916 addInstr(env
, PPCInstr_Fp128Binary(fpop
, r_dst
, r_srcL
, r_srcR
));
4922 } /* switch (e->Iex.Triop.op) */
4924 } /* if (e->tag == Iex_Trinop) */
4926 if (e
->tag
== Iex_Qop
) {
4927 IRQop
*qop
= e
->Iex
.Qop
.details
;
4931 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4932 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4933 fpop
= Pfp_FPMULADDQRNDODD
; goto do_Quad_F128
;
4935 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4936 fpop
= Pfp_FPMULADDQ
; goto do_Quad_F128
;
4939 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4940 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4941 fpop
= Pfp_FPMULSUBQRNDODD
; goto do_Quad_F128
;
4943 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4944 fpop
= Pfp_FPMULSUBQ
; goto do_Quad_F128
;
4946 case Iop_NegMAddF128
:
4947 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4948 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4949 fpop
= Pfp_FPNEGMULADDQRNDODD
; goto do_Quad_F128
;
4951 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4952 fpop
= Pfp_FPNEGMULADDQ
; goto do_Quad_F128
;
4954 case Iop_NegMSubF128
:
4955 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4956 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4957 fpop
= Pfp_FPNEGMULSUBQRNDODD
; goto do_Quad_F128
;
4959 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4960 fpop
= Pfp_FPNEGMULSUBQ
; goto do_Quad_F128
;
4964 HReg r_dst
= iselFp128Expr(env
, qop
->arg3
,
4966 HReg r_srcL
= iselFp128Expr(env
, qop
->arg2
,
4968 HReg r_srcR
= iselFp128Expr(env
, qop
->arg4
,
4971 addInstr(env
, PPCInstr_Fp128Trinary(fpop
, r_dst
, r_srcL
, r_srcR
));
4978 } /* if (e->tag == Iex_Qop) */
4981 vpanic( "iselFp128Expr(ppc64)" );
4984 static HReg
iselDfp64Expr(ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4986 HReg r
= iselDfp64Expr_wrk( env
, e
, IEndianess
);
4987 vassert(hregClass(r
) == HRcFlt64
);
4988 vassert( hregIsVirtual(r
) );
4992 /* DO NOT CALL THIS DIRECTLY */
4993 static HReg
iselDfp64Expr_wrk(ISelEnv
* env
, const IRExpr
* e
,
4994 IREndness IEndianess
)
4996 Bool mode64
= env
->mode64
;
4997 IRType ty
= typeOfIRExpr( env
->type_env
, e
);
4998 HReg r_dstHi
, r_dstLo
;
5001 vassert( ty
== Ity_D64
);
5003 if (e
->tag
== Iex_RdTmp
) {
5004 return lookupIRTemp( env
, e
->Iex
.RdTmp
.tmp
);
5007 /* --------- GET --------- */
5008 if (e
->tag
== Iex_Get
) {
5009 HReg r_dst
= newVRegF( env
);
5010 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
5011 GuestStatePtr(mode64
) );
5012 addInstr( env
, PPCInstr_FpLdSt( True
/*load*/, 8, r_dst
, am_addr
) );
5016 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
5018 HReg r_dst
= newVRegF(env
);
5019 vassert(e
->Iex
.Load
.ty
== Ity_D64
);
5020 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_D64
/*xfer*/,
5022 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dst
, am_addr
));
5026 /* --------- OPS --------- */
5027 if (e
->tag
== Iex_Qop
) {
5028 HReg r_dst
= newVRegF( env
);
5032 if (e
->tag
== Iex_Unop
) {
5033 HReg fr_dst
= newVRegF(env
);
5034 switch (e
->Iex
.Unop
.op
) {
5035 case Iop_ReinterpI64asD64
: {
5036 /* Given an I64, produce an IEEE754 DFP with the same
5039 HReg r_srcHi
, r_srcLo
;
5040 iselInt64Expr( &r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
,
5042 return mk_LoadRR32toFPR( env
, r_srcHi
, r_srcLo
);
5044 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5045 return mk_LoadR64toFPR( env
, r_src
);
5048 case Iop_D32toD64
: {
5049 HReg fr_src
= iselDfp32Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5050 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DCTDP
, fr_dst
, fr_src
));
5053 case Iop_D128HItoD64
:
5054 iselDfp128Expr( &r_dstHi
, &r_dstLo
, env
, e
->Iex
.Unop
.arg
,
5057 case Iop_D128LOtoD64
:
5058 iselDfp128Expr( &r_dstHi
, &r_dstLo
, env
, e
->Iex
.Unop
.arg
,
5061 case Iop_InsertExpD64
: {
5062 HReg fr_srcL
= iselDblExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5063 HReg fr_srcR
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5065 addInstr(env
, PPCInstr_Dfp64Binary(Pfp_DIEX
, fr_dst
, fr_srcL
,
5070 vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
5071 (Int
)e
->Iex
.Unop
.op
);
5075 if (e
->tag
== Iex_Binop
) {
5076 PPCFpOp fpop
= Pfp_INVALID
;
5077 HReg fr_dst
= newVRegF(env
);
5079 switch (e
->Iex
.Binop
.op
) {
5080 case Iop_D128toD64
: fpop
= Pfp_DRDPQ
; break;
5081 case Iop_D64toD32
: fpop
= Pfp_DRSP
; break;
5082 case Iop_I64StoD64
: fpop
= Pfp_DCFFIX
; break;
5083 case Iop_RoundD64toInt
: fpop
= Pfp_DRINTN
; break;
5086 if (fpop
== Pfp_DRDPQ
) {
5087 HReg r_srcHi
= newVRegF(env
);
5088 HReg r_srcLo
= newVRegF(env
);
5090 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5091 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5093 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, fr_dst
, r_srcHi
, r_srcLo
));
5096 } else if (fpop
== Pfp_DRINTN
) {
5097 HReg fr_src
= newVRegF(env
);
5098 PPCRI
* r_rmc
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5100 /* NOTE, this IOP takes a DFP value and rounds to the
5101 * neares floating point integer value, i.e. fractional part
5102 * is zero. The result is a decimal floating point number.
5103 * the INT in the name is a bit misleading.
5105 fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5106 addInstr(env
, PPCInstr_DfpRound(fr_dst
, fr_src
, r_rmc
));
5109 } else if (fpop
== Pfp_DRSP
) {
5110 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5111 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5112 addInstr(env
, PPCInstr_Dfp64Unary(fpop
, fr_dst
, fr_src
));
5115 } else if (fpop
== Pfp_DCFFIX
) {
5116 HReg fr_src
= newVRegF(env
);
5117 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5119 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5120 sub_from_sp( env
, 16 );
5122 // put the I64 value into a floating point register
5124 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5126 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5129 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5131 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Binop
.arg2
,
5133 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*mode32*/));
5134 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*mode32*/));
5137 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_src
, zero_r1
));
5138 addInstr(env
, PPCInstr_Dfp64Unary(fpop
, fr_dst
, fr_src
));
5139 add_to_sp( env
, 16 );
5143 switch (e
->Iex
.Binop
.op
) {
5144 /* shift instructions D64, I32 -> D64 */
5145 case Iop_ShlD64
: fpop
= Pfp_DSCLI
; break;
5146 case Iop_ShrD64
: fpop
= Pfp_DSCRI
; break;
5149 if (fpop
!= Pfp_INVALID
) {
5150 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5151 PPCRI
* shift
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5153 /* shift value must be an immediate value */
5154 vassert(shift
->tag
== Pri_Imm
);
5156 addInstr(env
, PPCInstr_DfpShift(fpop
, fr_dst
, fr_src
, shift
));
5160 switch (e
->Iex
.Binop
.op
) {
5161 case Iop_InsertExpD64
:
5166 if (fpop
!= Pfp_INVALID
) {
5167 HReg fr_srcL
= newVRegF(env
);
5168 HReg fr_srcR
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5169 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5170 sub_from_sp( env
, 16 );
5173 // put the I64 value into a floating point reg
5174 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5176 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5178 // put the I64 register pair into a floating point reg
5181 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5183 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Binop
.arg1
,
5185 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*!mode64*/));
5186 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*!mode64*/));
5188 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_srcL
, zero_r1
));
5189 addInstr(env
, PPCInstr_Dfp64Binary(fpop
, fr_dst
, fr_srcL
,
5191 add_to_sp( env
, 16 );
5196 if (e
->tag
== Iex_Triop
) {
5197 IRTriop
*triop
= e
->Iex
.Triop
.details
;
5198 PPCFpOp fpop
= Pfp_INVALID
;
5200 switch (triop
->op
) {
5216 if (fpop
!= Pfp_INVALID
) {
5217 HReg r_dst
= newVRegF( env
);
5218 HReg r_srcL
= iselDfp64Expr( env
, triop
->arg2
, IEndianess
);
5219 HReg r_srcR
= iselDfp64Expr( env
, triop
->arg3
, IEndianess
);
5221 set_FPU_DFP_rounding_mode( env
, triop
->arg1
, IEndianess
);
5222 addInstr( env
, PPCInstr_Dfp64Binary( fpop
, r_dst
, r_srcL
, r_srcR
) );
5226 switch (triop
->op
) {
5227 case Iop_QuantizeD64
: fpop
= Pfp_DQUA
; break;
5228 case Iop_SignificanceRoundD64
: fpop
= Pfp_RRDTR
; break;
5231 if (fpop
== Pfp_DQUA
) {
5232 HReg r_dst
= newVRegF(env
);
5233 HReg r_srcL
= iselDfp64Expr(env
, triop
->arg2
, IEndianess
);
5234 HReg r_srcR
= iselDfp64Expr(env
, triop
->arg3
, IEndianess
);
5235 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5236 addInstr(env
, PPCInstr_DfpQuantize(fpop
, r_dst
, r_srcL
, r_srcR
,
5240 } else if (fpop
== Pfp_RRDTR
) {
5241 HReg r_dst
= newVRegF(env
);
5242 HReg r_srcL
= newVRegF(env
);
5243 HReg r_srcR
= iselDfp64Expr(env
, triop
->arg3
, IEndianess
);
5244 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5245 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5246 HReg i8_val
= iselWordExpr_R(env
, triop
->arg2
, IEndianess
);
5248 /* Move I8 to float register to issue instruction */
5249 sub_from_sp( env
, 16 );
5251 addInstr(env
, PPCInstr_Store(8, zero_r1
, i8_val
, True
/*mode64*/));
5253 addInstr(env
, PPCInstr_Store(4, zero_r1
, i8_val
, False
/*mode32*/));
5255 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_srcL
, zero_r1
));
5256 add_to_sp( env
, 16 );
5258 // will set TE and RMC when issuing instruction
5259 addInstr(env
, PPCInstr_DfpQuantize(fpop
, r_dst
, r_srcL
, r_srcR
, rmc
));
5265 vpanic( "iselDfp64Expr_wrk(ppc)" );
5268 static void iselDfp128Expr(HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
, const IRExpr
* e
,
5269 IREndness IEndianess
)
5271 iselDfp128Expr_wrk( rHi
, rLo
, env
, e
, IEndianess
);
5272 vassert( hregIsVirtual(*rHi
) );
5273 vassert( hregIsVirtual(*rLo
) );
5276 /* DO NOT CALL THIS DIRECTLY */
5277 static void iselDfp128Expr_wrk(HReg
* rHi
, HReg
*rLo
, ISelEnv
* env
,
5278 const IRExpr
* e
, IREndness IEndianess
)
5281 vassert( typeOfIRExpr(env
->type_env
,e
) == Ity_D128
);
5283 /* read 128-bit IRTemp */
5284 if (e
->tag
== Iex_RdTmp
) {
5285 lookupIRTempPair( rHi
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
5289 if (e
->tag
== Iex_Unop
) {
5290 HReg r_dstHi
= newVRegF(env
);
5291 HReg r_dstLo
= newVRegF(env
);
5293 if (e
->Iex
.Unop
.op
== Iop_I64StoD128
) {
5294 HReg fr_src
= newVRegF(env
);
5295 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5297 // put the I64 value into a floating point reg
5299 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5300 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5303 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5305 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
,
5307 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*mode32*/));
5308 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*mode32*/));
5311 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_src
, zero_r1
));
5312 addInstr(env
, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ
, r_dstHi
, r_dstLo
,
5316 if (e
->Iex
.Unop
.op
== Iop_D64toD128
) {
5317 HReg r_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5319 /* Source is 64bit, result is 128 bit. High 64bit source arg,
5320 * is ignored by the instruction. Set high arg to r_src just
5321 * to meet the vassert tests.
5323 addInstr(env
, PPCInstr_Dfp128Unary(Pfp_DCTQPQ
, r_dstHi
, r_dstLo
,
5331 /* --------- OPS --------- */
5332 if (e
->tag
== Iex_Binop
) {
5336 switch (e
->Iex
.Binop
.op
) {
5337 case Iop_D64HLtoD128
:
5338 r_srcHi
= iselDfp64Expr( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5339 r_srcLo
= iselDfp64Expr( env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5344 case Iop_D128toD64
: {
5345 PPCFpOp fpop
= Pfp_DRDPQ
;
5346 HReg fr_dst
= newVRegF(env
);
5348 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5349 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5351 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, fr_dst
, r_srcHi
, r_srcLo
));
5353 /* Need to meet the interface spec but the result is
5354 * just 64-bits so send the result back in both halfs.
5362 HReg fr_dst_hi
= newVRegF(env
);
5363 HReg fr_dst_lo
= newVRegF(env
);
5364 PPCRI
* shift
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5365 PPCFpOp fpop
= Pfp_DSCLIQ
; /* fix later if necessary */
5367 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg1
,
5370 if (e
->Iex
.Binop
.op
== Iop_ShrD128
)
5373 addInstr(env
, PPCInstr_DfpShift128(fpop
, fr_dst_hi
, fr_dst_lo
,
5374 r_srcHi
, r_srcLo
, shift
));
5380 case Iop_RoundD128toInt
: {
5381 HReg r_dstHi
= newVRegF(env
);
5382 HReg r_dstLo
= newVRegF(env
);
5383 PPCRI
* r_rmc
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5385 // will set R and RMC when issuing instruction
5386 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5389 addInstr(env
, PPCInstr_DfpRound128(r_dstHi
, r_dstLo
,
5390 r_srcHi
, r_srcLo
, r_rmc
));
5395 case Iop_InsertExpD128
: {
5396 HReg r_dstHi
= newVRegF(env
);
5397 HReg r_dstLo
= newVRegF(env
);
5398 HReg r_srcL
= newVRegF(env
);
5399 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5400 r_srcHi
= newVRegF(env
);
5401 r_srcLo
= newVRegF(env
);
5403 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5406 /* Move I64 to float register to issue instruction */
5408 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5409 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5412 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5414 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
,
5416 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*mode32*/));
5417 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*mode32*/));
5420 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_srcL
, zero_r1
));
5421 addInstr(env
, PPCInstr_InsertExpD128(Pfp_DIEXQ
,
5423 r_srcL
, r_srcHi
, r_srcLo
));
5429 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
5430 (Int
)e
->Iex
.Binop
.op
);
5435 if (e
->tag
== Iex_Triop
) {
5436 IRTriop
*triop
= e
->Iex
.Triop
.details
;
5437 PPCFpOp fpop
= Pfp_INVALID
;
5438 HReg r_dstHi
= newVRegF(env
);
5439 HReg r_dstLo
= newVRegF(env
);
5441 switch (triop
->op
) {
5458 if (fpop
!= Pfp_INVALID
) {
5459 HReg r_srcRHi
= newVRegV( env
);
5460 HReg r_srcRLo
= newVRegV( env
);
5462 /* dst will be used to pass in the left operand and get the result. */
5463 iselDfp128Expr( &r_dstHi
, &r_dstLo
, env
, triop
->arg2
, IEndianess
);
5464 iselDfp128Expr( &r_srcRHi
, &r_srcRLo
, env
, triop
->arg3
, IEndianess
);
5465 set_FPU_DFP_rounding_mode( env
, triop
->arg1
, IEndianess
);
5467 PPCInstr_Dfp128Binary( fpop
, r_dstHi
, r_dstLo
,
5468 r_srcRHi
, r_srcRLo
) );
5473 switch (triop
->op
) {
5474 case Iop_QuantizeD128
: fpop
= Pfp_DQUAQ
; break;
5475 case Iop_SignificanceRoundD128
: fpop
= Pfp_DRRNDQ
; break;
5478 if (fpop
== Pfp_DQUAQ
) {
5479 HReg r_srcHi
= newVRegF(env
);
5480 HReg r_srcLo
= newVRegF(env
);
5481 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5483 /* dst will be used to pass in the left operand and get the result */
5484 iselDfp128Expr(&r_dstHi
, &r_dstLo
, env
, triop
->arg2
, IEndianess
);
5485 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, triop
->arg3
, IEndianess
);
5487 // will set RMC when issuing instruction
5488 addInstr(env
, PPCInstr_DfpQuantize128(fpop
, r_dstHi
, r_dstLo
,
5489 r_srcHi
, r_srcLo
, rmc
));
5494 } else if (fpop
== Pfp_DRRNDQ
) {
5495 HReg r_srcHi
= newVRegF(env
);
5496 HReg r_srcLo
= newVRegF(env
);
5497 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5498 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5499 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5500 HReg i8_val
= iselWordExpr_R(env
, triop
->arg2
, IEndianess
);
5501 HReg r_zero
= newVRegI( env
);
5503 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, triop
->arg3
, IEndianess
);
5505 /* dst will be used to pass in the left operand and get the result */
5506 /* Move I8 to float register to issue instruction. Note, the
5507 * instruction only looks at the bottom 6 bits so we really don't
5508 * have to clear the upper bits since the iselWordExpr_R sets the
5511 sub_from_sp( env
, 16 );
5514 addInstr(env
, PPCInstr_Store(4, four_r1
, i8_val
, True
/*mode64*/));
5516 addInstr(env
, PPCInstr_Store(4, four_r1
, i8_val
, False
/*mode32*/));
5518 /* Have to write to the upper bits to ensure they have been
5519 * initialized. The instruction ignores all but the lower 6-bits.
5521 addInstr( env
, PPCInstr_LI( r_zero
, 0, env
->mode64
) );
5522 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dstHi
, zero_r1
));
5523 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dstLo
, zero_r1
));
5525 add_to_sp( env
, 16 );
5527 // will set RMC when issuing instruction
5528 addInstr(env
, PPCInstr_DfpQuantize128(fpop
, r_dstHi
, r_dstLo
,
5529 r_srcHi
, r_srcLo
, rmc
));
5537 vpanic( "iselDfp128Expr(ppc64)" );
5541 /*---------------------------------------------------------*/
5542 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
5543 /*---------------------------------------------------------*/
5545 static HReg
iselVecExpr ( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
5547 HReg r
= iselVecExpr_wrk( env
, e
, IEndianess
);
5549 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
5551 vassert(hregClass(r
) == HRcVec128
);
5552 vassert(hregIsVirtual(r
));
5556 /* DO NOT CALL THIS DIRECTLY */
5557 static HReg
iselVecExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
5558 IREndness IEndianess
)
5560 Bool mode64
= env
->mode64
;
5561 PPCAvOp op
= Pav_INVALID
;
5562 PPCAvFpOp fpop
= Pavfp_INVALID
;
5563 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
5565 vassert(ty
== Ity_V128
);
5567 if (e
->tag
== Iex_RdTmp
) {
5568 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
5571 if (e
->tag
== Iex_Get
) {
5572 /* Guest state vectors are 16byte aligned,
5573 so don't need to worry here */
5574 HReg dst
= newVRegV(env
);
5576 PPCInstr_AvLdSt( True
/*load*/, 16, dst
,
5577 PPCAMode_IR( e
->Iex
.Get
.offset
,
5578 GuestStatePtr(mode64
) )));
5582 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
5583 /* Need to be able to do V128 unaligned loads. The BE unaligned load
5584 * can be accomplised using the following code sequece from the ISA.
5585 * It uses the lvx instruction that does two aligned loads and then
5586 * permute the data to store the required data as if it had been an
5589 * lvx Vhi,0,Rb # load MSQ, using the unaligned address in Rb
5590 * lvsl Vp, 0,Rb # Set permute control vector
5591 * addi Rb,Rb,15 # Address of LSQ
5592 * lvx Vlo,0,Rb # load LSQ
5593 * vperm Vt,Vhi,Vlo,Vp # align the data as requested
5596 HReg Vhi
= newVRegV(env
);
5597 HReg Vlo
= newVRegV(env
);
5598 HReg Vp
= newVRegV(env
);
5599 HReg v_dst
= newVRegV(env
);
5601 HReg rB_plus_15
= newVRegI(env
);
5603 vassert(e
->Iex
.Load
.ty
== Ity_V128
);
5604 rB
= iselWordExpr_R( env
, e
->Iex
.Load
.addr
, IEndianess
);
5607 addInstr(env
, PPCInstr_AvLdSt( True
/*load*/, 16, Vhi
,
5608 PPCAMode_IR(0, rB
)) );
5610 if (IEndianess
== Iend_LE
)
5612 addInstr(env
, PPCInstr_AvSh( False
/*right shift*/, Vp
,
5613 PPCAMode_IR(0, rB
)) );
5616 addInstr(env
, PPCInstr_AvSh( True
/*left shift*/, Vp
,
5617 PPCAMode_IR(0, rB
)) );
5619 // addi Rb_plus_15, Rb, 15
5620 addInstr(env
, PPCInstr_Alu( Palu_ADD
, rB_plus_15
,
5621 rB
, PPCRH_Imm(True
, toUShort(15))) );
5623 // lvx Vlo, 0, Rb_plus_15
5624 addInstr(env
, PPCInstr_AvLdSt( True
/*load*/, 16, Vlo
,
5625 PPCAMode_IR(0, rB_plus_15
)) );
5627 if (IEndianess
== Iend_LE
)
5628 // vperm Vt, Vhi, Vlo, Vp
5629 addInstr(env
, PPCInstr_AvPerm( v_dst
, Vlo
, Vhi
, Vp
));
5631 // vperm Vt, Vhi, Vlo, Vp
5632 addInstr(env
, PPCInstr_AvPerm( v_dst
, Vhi
, Vlo
, Vp
));
5637 if (e
->tag
== Iex_Unop
) {
5638 switch (e
->Iex
.Unop
.op
) {
5640 case Iop_F16toF64x2
:
5642 HReg dst
= newVRegV(env
);
5643 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5644 /* Note: PPC only coverts the 16-bt value in the upper word
5645 * to a 64-bit value stored in the upper word. The
5646 * contents of the lower word is undefined.
5648 addInstr(env
, PPCInstr_AvUnary(Pav_F16toF64x2
, dst
, arg
));
5652 case Iop_F64toF16x2_DEP
:
5654 HReg dst
= newVRegV(env
);
5655 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5656 /* Note: PPC only coverts the 64-bt value in the upper 64-bit of V128
5657 * to a 16-bit value stored in the upper 64-bits of the result
5658 * V128. The contents of the lower 64-bits is undefined.
5660 addInstr(env
, PPCInstr_AvUnary(Pav_F64toF16x2
, dst
, arg
));
5664 case Iop_F16toF32x4
:
5666 HReg src
= newVRegV(env
);
5667 HReg dst
= newVRegV(env
);
5668 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5669 PPCAMode
*am_off0
, *am_off8
;
5673 /* need to put I64 src into upper 64-bits of vector register,
5675 sub_from_sp( env
, 32 ); // Move SP down
5677 /* Get a quadword aligned address within our stack space */
5678 r_aligned16
= get_sp_aligned16( env
);
5679 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5680 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5682 /* Store I64 to stack */
5684 if (IEndianess
== Iend_LE
) {
5685 addInstr(env
, PPCInstr_Store( 8, am_off8
, arg
, mode64
));
5687 addInstr(env
, PPCInstr_Store( 8, am_off0
, arg
, mode64
));
5690 /* Fetch new v128 src back from stack. */
5691 addInstr(env
, PPCInstr_AvLdSt(True
/*ld*/, 16, src
, am_off0
));
5693 /* issue instruction */
5694 addInstr(env
, PPCInstr_AvUnary(Pav_F16toF32x4
, dst
, src
));
5695 add_to_sp( env
, 32 ); // Reset SP
5700 case Iop_F32toF16x4_DEP
:
5702 HReg dst
= newVRegI(env
);
5703 HReg tmp
= newVRegV(env
);
5704 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5705 PPCAMode
*am_off0
, *am_off8
;
5708 /* Instruction returns a V128, the Iop_F32toF16x4 needs to return
5709 * I64. Move the upper 64-bits from the instruction to an I64 via
5710 * the stack and return it.
5712 sub_from_sp( env
, 32 ); // Move SP down
5714 addInstr(env
, PPCInstr_AvUnary(Pav_F32toF16x4
, tmp
, arg
));
5716 /* Get a quadword aligned address within our stack space */
5717 r_aligned16
= get_sp_aligned16( env
);
5718 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5719 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5721 /* Store v128 tmp to stack. */
5722 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, tmp
, am_off0
));
5724 /* Fetch I64 from stack */
5725 if (IEndianess
== Iend_LE
) {
5726 addInstr(env
, PPCInstr_Load( 8, dst
, am_off8
, mode64
));
5728 addInstr(env
, PPCInstr_Load( 8, dst
, am_off0
, mode64
));
5731 add_to_sp( env
, 32 ); // Reset SP
5736 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5737 HReg dst
= newVRegV(env
);
5738 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, arg
));
5742 case Iop_CmpNEZ8x16
: {
5743 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5744 HReg zero
= newVRegV(env
);
5745 HReg dst
= newVRegV(env
);
5746 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5747 addInstr(env
, PPCInstr_AvBin8x16(Pav_CMPEQU
, dst
, arg
, zero
));
5748 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5752 case Iop_CmpNEZ16x8
: {
5753 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5754 HReg zero
= newVRegV(env
);
5755 HReg dst
= newVRegV(env
);
5756 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5757 addInstr(env
, PPCInstr_AvBin16x8(Pav_CMPEQU
, dst
, arg
, zero
));
5758 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5762 case Iop_CmpNEZ32x4
: {
5763 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5764 HReg zero
= newVRegV(env
);
5765 HReg dst
= newVRegV(env
);
5766 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5767 addInstr(env
, PPCInstr_AvBin32x4(Pav_CMPEQU
, dst
, arg
, zero
));
5768 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5772 case Iop_CmpNEZ64x2
: {
5773 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5774 HReg zero
= newVRegV(env
);
5775 HReg dst
= newVRegV(env
);
5776 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5777 addInstr(env
, PPCInstr_AvBin64x2(Pav_CMPEQU
, dst
, arg
, zero
));
5778 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5782 case Iop_RecipEst32Fx4
: fpop
= Pavfp_RCPF
; goto do_32Fx4_unary
;
5783 case Iop_RSqrtEst32Fx4
: fpop
= Pavfp_RSQRTF
; goto do_32Fx4_unary
;
5784 case Iop_I32UtoF32x4_DEP
: fpop
= Pavfp_CVTU2F
; goto do_32Fx4_unary
;
5785 case Iop_I32StoF32x4_DEP
: fpop
= Pavfp_CVTS2F
; goto do_32Fx4_unary
;
5786 case Iop_QF32toI32Ux4_RZ
: fpop
= Pavfp_QCVTF2U
; goto do_32Fx4_unary
;
5787 case Iop_QF32toI32Sx4_RZ
: fpop
= Pavfp_QCVTF2S
; goto do_32Fx4_unary
;
5788 case Iop_RoundF32x4_RM
: fpop
= Pavfp_ROUNDM
; goto do_32Fx4_unary
;
5789 case Iop_RoundF32x4_RP
: fpop
= Pavfp_ROUNDP
; goto do_32Fx4_unary
;
5790 case Iop_RoundF32x4_RN
: fpop
= Pavfp_ROUNDN
; goto do_32Fx4_unary
;
5791 case Iop_RoundF32x4_RZ
: fpop
= Pavfp_ROUNDZ
; goto do_32Fx4_unary
;
5794 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5795 HReg dst
= newVRegV(env
);
5796 addInstr(env
, PPCInstr_AvUn32Fx4(fpop
, dst
, arg
));
5800 case Iop_32UtoV128
: {
5801 HReg r_aligned16
, r_zeros
;
5802 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5803 HReg dst
= newVRegV(env
);
5804 PPCAMode
*am_off0
, *am_off4
, *am_off8
, *am_off12
;
5805 sub_from_sp( env
, 32 ); // Move SP down
5807 /* Get a quadword aligned address within our stack space */
5808 r_aligned16
= get_sp_aligned16( env
);
5809 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5810 am_off4
= PPCAMode_IR( 4, r_aligned16
);
5811 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5812 am_off12
= PPCAMode_IR( 12, r_aligned16
);
5815 r_zeros
= newVRegI(env
);
5816 addInstr(env
, PPCInstr_LI(r_zeros
, 0x0, mode64
));
5817 if (IEndianess
== Iend_LE
)
5818 addInstr(env
, PPCInstr_Store( 4, am_off0
, r_src
, mode64
));
5820 addInstr(env
, PPCInstr_Store( 4, am_off0
, r_zeros
, mode64
));
5821 addInstr(env
, PPCInstr_Store( 4, am_off4
, r_zeros
, mode64
));
5822 addInstr(env
, PPCInstr_Store( 4, am_off8
, r_zeros
, mode64
));
5824 /* Store r_src in low word of quadword-aligned mem */
5825 if (IEndianess
== Iend_LE
)
5826 addInstr(env
, PPCInstr_Store( 4, am_off12
, r_zeros
, mode64
));
5828 addInstr(env
, PPCInstr_Store( 4, am_off12
, r_src
, mode64
));
5830 /* Load word into low word of quadword vector reg */
5831 if (IEndianess
== Iend_LE
)
5832 addInstr(env
, PPCInstr_AvLdSt( True
/*ld*/, 4, dst
, am_off0
));
5834 addInstr(env
, PPCInstr_AvLdSt( True
/*ld*/, 4, dst
, am_off12
));
5836 add_to_sp( env
, 32 ); // Reset SP
5843 return mk_AvDuplicateRI(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5845 case Iop_CipherSV128
: op
= Pav_CIPHERSUBV128
; goto do_AvCipherV128Un
;
5846 do_AvCipherV128Un
: {
5847 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5848 HReg dst
= newVRegV(env
);
5849 addInstr(env
, PPCInstr_AvCipherV128Unary(op
, dst
, arg
));
5853 case Iop_Clz8x16
: op
= Pav_ZEROCNTBYTE
; goto do_zerocnt
;
5854 case Iop_Clz16x8
: op
= Pav_ZEROCNTHALF
; goto do_zerocnt
;
5855 case Iop_Clz32x4
: op
= Pav_ZEROCNTWORD
; goto do_zerocnt
;
5856 case Iop_Clz64x2
: op
= Pav_ZEROCNTDBL
; goto do_zerocnt
;
5857 case Iop_Ctz8x16
: op
= Pav_TRAILINGZEROCNTBYTE
; goto do_zerocnt
;
5858 case Iop_Ctz16x8
: op
= Pav_TRAILINGZEROCNTHALF
; goto do_zerocnt
;
5859 case Iop_Ctz32x4
: op
= Pav_TRAILINGZEROCNTWORD
; goto do_zerocnt
;
5860 case Iop_Ctz64x2
: op
= Pav_TRAILINGZEROCNTDBL
; goto do_zerocnt
;
5861 case Iop_PwBitMtxXpose64x2
: op
= Pav_BITMTXXPOSE
; goto do_zerocnt
;
5864 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5865 HReg dst
= newVRegV(env
);
5866 addInstr(env
, PPCInstr_AvUnary(op
, dst
, arg
));
5871 case Iop_BCD128toI128S
:
5873 HReg dst
= newVRegV(env
);
5874 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5875 addInstr(env
, PPCInstr_AvUnary( Pav_BCD128toI128S
, dst
, arg
) );
5879 case Iop_MulI128by10
: op
= Pav_MulI128by10
; goto do_MulI128
;
5880 case Iop_MulI128by10Carry
: op
= Pav_MulI128by10Carry
; goto do_MulI128
;
5882 HReg dst
= newVRegV(env
);
5883 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5884 addInstr(env
, PPCInstr_AvUnary(op
, dst
, arg
));
5890 } /* switch (e->Iex.Unop.op) */
5891 } /* if (e->tag == Iex_Unop) */
5893 if (e
->tag
== Iex_Binop
) {
5894 switch (e
->Iex
.Binop
.op
) {
5896 case Iop_64HLtoV128
: {
5898 HReg r3
, r2
, r1
, r0
, r_aligned16
;
5899 PPCAMode
*am_off0
, *am_off4
, *am_off8
, *am_off12
;
5900 HReg dst
= newVRegV(env
);
5901 /* do this via the stack (easy, convenient, etc) */
5902 sub_from_sp( env
, 32 ); // Move SP down
5904 // get a quadword aligned address within our stack space
5905 r_aligned16
= get_sp_aligned16( env
);
5906 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5907 am_off4
= PPCAMode_IR( 4, r_aligned16
);
5908 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5909 am_off12
= PPCAMode_IR( 12, r_aligned16
);
5911 /* Do the less significant 64 bits */
5912 iselInt64Expr(&r1
, &r0
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5913 addInstr(env
, PPCInstr_Store( 4, am_off12
, r0
, mode64
));
5914 addInstr(env
, PPCInstr_Store( 4, am_off8
, r1
, mode64
));
5915 /* Do the more significant 64 bits */
5916 iselInt64Expr(&r3
, &r2
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5917 addInstr(env
, PPCInstr_Store( 4, am_off4
, r2
, mode64
));
5918 addInstr(env
, PPCInstr_Store( 4, am_off0
, r3
, mode64
));
5920 /* Fetch result back from stack. */
5921 addInstr(env
, PPCInstr_AvLdSt(True
/*ld*/, 16, dst
, am_off0
));
5923 add_to_sp( env
, 32 ); // Reset SP
5926 HReg rHi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5927 HReg rLo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5928 HReg dst
= newVRegV(env
);
5930 PPCAMode
*am_off0
, *am_off8
;
5931 /* do this via the stack (easy, convenient, etc) */
5932 sub_from_sp( env
, 32 ); // Move SP down
5934 // get a quadword aligned address within our stack space
5935 r_aligned16
= get_sp_aligned16( env
);
5936 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5937 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5939 /* Store 2*I64 to stack */
5940 if (IEndianess
== Iend_LE
) {
5941 addInstr(env
, PPCInstr_Store( 8, am_off0
, rLo
, mode64
));
5942 addInstr(env
, PPCInstr_Store( 8, am_off8
, rHi
, mode64
));
5944 addInstr(env
, PPCInstr_Store( 8, am_off0
, rHi
, mode64
));
5945 addInstr(env
, PPCInstr_Store( 8, am_off8
, rLo
, mode64
));
5947 /* Fetch result back from stack. */
5948 addInstr(env
, PPCInstr_AvLdSt(True
/*ld*/, 16, dst
, am_off0
));
5950 add_to_sp( env
, 32 ); // Reset SP
5955 case Iop_Max32Fx4
: fpop
= Pavfp_MAXF
; goto do_32Fx4
;
5956 case Iop_Min32Fx4
: fpop
= Pavfp_MINF
; goto do_32Fx4
;
5957 case Iop_CmpEQ32Fx4
: fpop
= Pavfp_CMPEQF
; goto do_32Fx4
;
5958 case Iop_CmpGT32Fx4
: fpop
= Pavfp_CMPGTF
; goto do_32Fx4
;
5959 case Iop_CmpGE32Fx4
: fpop
= Pavfp_CMPGEF
; goto do_32Fx4
;
5962 HReg argL
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5963 HReg argR
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5964 HReg dst
= newVRegV(env
);
5965 addInstr(env
, PPCInstr_AvBin32Fx4(fpop
, dst
, argL
, argR
));
5969 case Iop_CmpLE32Fx4
: {
5970 HReg argL
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5971 HReg argR
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5972 HReg dst
= newVRegV(env
);
5974 /* stay consistent with native ppc compares:
5975 if a left/right lane holds a nan, return zeros for that lane
5976 so: le == NOT(gt OR isNan)
5978 HReg isNanLR
= newVRegV(env
);
5979 HReg isNanL
= isNan(env
, argL
, IEndianess
);
5980 HReg isNanR
= isNan(env
, argR
, IEndianess
);
5981 addInstr(env
, PPCInstr_AvBinary(Pav_OR
, isNanLR
,
5984 addInstr(env
, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF
, dst
,
5986 addInstr(env
, PPCInstr_AvBinary(Pav_OR
, dst
, dst
, isNanLR
));
5987 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5991 case Iop_AndV128
: op
= Pav_AND
; goto do_AvBin
;
5992 case Iop_OrV128
: op
= Pav_OR
; goto do_AvBin
;
5993 case Iop_XorV128
: op
= Pav_XOR
; goto do_AvBin
;
5995 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5996 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5997 HReg dst
= newVRegV(env
);
5998 addInstr(env
, PPCInstr_AvBinary(op
, dst
, arg1
, arg2
));
6002 case Iop_Shl8x16
: op
= Pav_SHL
; goto do_AvBin8x16
;
6003 case Iop_Shr8x16
: op
= Pav_SHR
; goto do_AvBin8x16
;
6004 case Iop_Sar8x16
: op
= Pav_SAR
; goto do_AvBin8x16
;
6005 case Iop_Rol8x16
: op
= Pav_ROTL
; goto do_AvBin8x16
;
6006 case Iop_InterleaveHI8x16
: op
= Pav_MRGHI
; goto do_AvBin8x16
;
6007 case Iop_InterleaveLO8x16
: op
= Pav_MRGLO
; goto do_AvBin8x16
;
6008 case Iop_Add8x16
: op
= Pav_ADDU
; goto do_AvBin8x16
;
6009 case Iop_QAdd8Ux16
: op
= Pav_QADDU
; goto do_AvBin8x16
;
6010 case Iop_QAdd8Sx16
: op
= Pav_QADDS
; goto do_AvBin8x16
;
6011 case Iop_Sub8x16
: op
= Pav_SUBU
; goto do_AvBin8x16
;
6012 case Iop_QSub8Ux16
: op
= Pav_QSUBU
; goto do_AvBin8x16
;
6013 case Iop_QSub8Sx16
: op
= Pav_QSUBS
; goto do_AvBin8x16
;
6014 case Iop_Avg8Ux16
: op
= Pav_AVGU
; goto do_AvBin8x16
;
6015 case Iop_Avg8Sx16
: op
= Pav_AVGS
; goto do_AvBin8x16
;
6016 case Iop_Max8Ux16
: op
= Pav_MAXU
; goto do_AvBin8x16
;
6017 case Iop_Max8Sx16
: op
= Pav_MAXS
; goto do_AvBin8x16
;
6018 case Iop_Min8Ux16
: op
= Pav_MINU
; goto do_AvBin8x16
;
6019 case Iop_Min8Sx16
: op
= Pav_MINS
; goto do_AvBin8x16
;
6020 case Iop_MullEven8Ux16
: op
= Pav_OMULU
; goto do_AvBin8x16
;
6021 case Iop_MullEven8Sx16
: op
= Pav_OMULS
; goto do_AvBin8x16
;
6022 case Iop_CmpEQ8x16
: op
= Pav_CMPEQU
; goto do_AvBin8x16
;
6023 case Iop_CmpGT8Ux16
: op
= Pav_CMPGTU
; goto do_AvBin8x16
;
6024 case Iop_CmpGT8Sx16
: op
= Pav_CMPGTS
; goto do_AvBin8x16
;
6025 case Iop_PolynomialMulAdd8x16
: op
= Pav_POLYMULADD
; goto do_AvBin8x16
;
6027 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6028 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6029 HReg dst
= newVRegV(env
);
6030 addInstr(env
, PPCInstr_AvBin8x16(op
, dst
, arg1
, arg2
));
6034 case Iop_Shl16x8
: op
= Pav_SHL
; goto do_AvBin16x8
;
6035 case Iop_Shr16x8
: op
= Pav_SHR
; goto do_AvBin16x8
;
6036 case Iop_Sar16x8
: op
= Pav_SAR
; goto do_AvBin16x8
;
6037 case Iop_Rol16x8
: op
= Pav_ROTL
; goto do_AvBin16x8
;
6038 case Iop_NarrowBin16to8x16
: op
= Pav_PACKUU
; goto do_AvBin16x8
;
6039 case Iop_QNarrowBin16Uto8Ux16
: op
= Pav_QPACKUU
; goto do_AvBin16x8
;
6040 case Iop_QNarrowBin16Sto8Sx16
: op
= Pav_QPACKSS
; goto do_AvBin16x8
;
6041 case Iop_InterleaveHI16x8
: op
= Pav_MRGHI
; goto do_AvBin16x8
;
6042 case Iop_InterleaveLO16x8
: op
= Pav_MRGLO
; goto do_AvBin16x8
;
6043 case Iop_Add16x8
: op
= Pav_ADDU
; goto do_AvBin16x8
;
6044 case Iop_QAdd16Ux8
: op
= Pav_QADDU
; goto do_AvBin16x8
;
6045 case Iop_QAdd16Sx8
: op
= Pav_QADDS
; goto do_AvBin16x8
;
6046 case Iop_Sub16x8
: op
= Pav_SUBU
; goto do_AvBin16x8
;
6047 case Iop_QSub16Ux8
: op
= Pav_QSUBU
; goto do_AvBin16x8
;
6048 case Iop_QSub16Sx8
: op
= Pav_QSUBS
; goto do_AvBin16x8
;
6049 case Iop_Avg16Ux8
: op
= Pav_AVGU
; goto do_AvBin16x8
;
6050 case Iop_Avg16Sx8
: op
= Pav_AVGS
; goto do_AvBin16x8
;
6051 case Iop_Max16Ux8
: op
= Pav_MAXU
; goto do_AvBin16x8
;
6052 case Iop_Max16Sx8
: op
= Pav_MAXS
; goto do_AvBin16x8
;
6053 case Iop_Min16Ux8
: op
= Pav_MINU
; goto do_AvBin16x8
;
6054 case Iop_Min16Sx8
: op
= Pav_MINS
; goto do_AvBin16x8
;
6055 case Iop_MullEven16Ux8
: op
= Pav_OMULU
; goto do_AvBin16x8
;
6056 case Iop_MullEven16Sx8
: op
= Pav_OMULS
; goto do_AvBin16x8
;
6057 case Iop_CmpEQ16x8
: op
= Pav_CMPEQU
; goto do_AvBin16x8
;
6058 case Iop_CmpGT16Ux8
: op
= Pav_CMPGTU
; goto do_AvBin16x8
;
6059 case Iop_CmpGT16Sx8
: op
= Pav_CMPGTS
; goto do_AvBin16x8
;
6060 case Iop_PolynomialMulAdd16x8
: op
= Pav_POLYMULADD
; goto do_AvBin16x8
;
6062 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6063 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6064 HReg dst
= newVRegV(env
);
6065 addInstr(env
, PPCInstr_AvBin16x8(op
, dst
, arg1
, arg2
));
6069 case Iop_Shl32x4
: op
= Pav_SHL
; goto do_AvBin32x4
;
6070 case Iop_Shr32x4
: op
= Pav_SHR
; goto do_AvBin32x4
;
6071 case Iop_Sar32x4
: op
= Pav_SAR
; goto do_AvBin32x4
;
6072 case Iop_Rol32x4
: op
= Pav_ROTL
; goto do_AvBin32x4
;
6073 case Iop_NarrowBin32to16x8
: op
= Pav_PACKUU
; goto do_AvBin32x4
;
6074 case Iop_QNarrowBin32Uto16Ux8
: op
= Pav_QPACKUU
; goto do_AvBin32x4
;
6075 case Iop_QNarrowBin32Sto16Sx8
: op
= Pav_QPACKSS
; goto do_AvBin32x4
;
6076 case Iop_InterleaveHI32x4
: op
= Pav_MRGHI
; goto do_AvBin32x4
;
6077 case Iop_InterleaveLO32x4
: op
= Pav_MRGLO
; goto do_AvBin32x4
;
6078 case Iop_Add32x4
: op
= Pav_ADDU
; goto do_AvBin32x4
;
6079 case Iop_QAdd32Ux4
: op
= Pav_QADDU
; goto do_AvBin32x4
;
6080 case Iop_QAdd32Sx4
: op
= Pav_QADDS
; goto do_AvBin32x4
;
6081 case Iop_Sub32x4
: op
= Pav_SUBU
; goto do_AvBin32x4
;
6082 case Iop_QSub32Ux4
: op
= Pav_QSUBU
; goto do_AvBin32x4
;
6083 case Iop_QSub32Sx4
: op
= Pav_QSUBS
; goto do_AvBin32x4
;
6084 case Iop_Avg32Ux4
: op
= Pav_AVGU
; goto do_AvBin32x4
;
6085 case Iop_Avg32Sx4
: op
= Pav_AVGS
; goto do_AvBin32x4
;
6086 case Iop_Max32Ux4
: op
= Pav_MAXU
; goto do_AvBin32x4
;
6087 case Iop_Max32Sx4
: op
= Pav_MAXS
; goto do_AvBin32x4
;
6088 case Iop_Min32Ux4
: op
= Pav_MINU
; goto do_AvBin32x4
;
6089 case Iop_Min32Sx4
: op
= Pav_MINS
; goto do_AvBin32x4
;
6090 case Iop_Mul32x4
: op
= Pav_MULU
; goto do_AvBin32x4
;
6091 case Iop_MullEven32Ux4
: op
= Pav_OMULU
; goto do_AvBin32x4
;
6092 case Iop_MullEven32Sx4
: op
= Pav_OMULS
; goto do_AvBin32x4
;
6093 case Iop_CmpEQ32x4
: op
= Pav_CMPEQU
; goto do_AvBin32x4
;
6094 case Iop_CmpGT32Ux4
: op
= Pav_CMPGTU
; goto do_AvBin32x4
;
6095 case Iop_CmpGT32Sx4
: op
= Pav_CMPGTS
; goto do_AvBin32x4
;
6096 case Iop_CatOddLanes32x4
: op
= Pav_CATODD
; goto do_AvBin32x4
;
6097 case Iop_CatEvenLanes32x4
: op
= Pav_CATEVEN
; goto do_AvBin32x4
;
6098 case Iop_PolynomialMulAdd32x4
: op
= Pav_POLYMULADD
; goto do_AvBin32x4
;
6100 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6101 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6102 HReg dst
= newVRegV(env
);
6103 addInstr(env
, PPCInstr_AvBin32x4(op
, dst
, arg1
, arg2
));
6107 case Iop_Shl64x2
: op
= Pav_SHL
; goto do_AvBin64x2
;
6108 case Iop_Shr64x2
: op
= Pav_SHR
; goto do_AvBin64x2
;
6109 case Iop_Sar64x2
: op
= Pav_SAR
; goto do_AvBin64x2
;
6110 case Iop_Rol64x2
: op
= Pav_ROTL
; goto do_AvBin64x2
;
6111 case Iop_NarrowBin64to32x4
: op
= Pav_PACKUU
; goto do_AvBin64x2
;
6112 case Iop_QNarrowBin64Sto32Sx4
: op
= Pav_QPACKSS
; goto do_AvBin64x2
;
6113 case Iop_QNarrowBin64Uto32Ux4
: op
= Pav_QPACKUU
; goto do_AvBin64x2
;
6114 case Iop_InterleaveHI64x2
: op
= Pav_MRGHI
; goto do_AvBin64x2
;
6115 case Iop_InterleaveLO64x2
: op
= Pav_MRGLO
; goto do_AvBin64x2
;
6116 case Iop_Add64x2
: op
= Pav_ADDU
; goto do_AvBin64x2
;
6117 case Iop_Sub64x2
: op
= Pav_SUBU
; goto do_AvBin64x2
;
6118 case Iop_Max64Ux2
: op
= Pav_MAXU
; goto do_AvBin64x2
;
6119 case Iop_Max64Sx2
: op
= Pav_MAXS
; goto do_AvBin64x2
;
6120 case Iop_Min64Ux2
: op
= Pav_MINU
; goto do_AvBin64x2
;
6121 case Iop_Min64Sx2
: op
= Pav_MINS
; goto do_AvBin64x2
;
6122 case Iop_CmpEQ64x2
: op
= Pav_CMPEQU
; goto do_AvBin64x2
;
6123 case Iop_CmpGT64Ux2
: op
= Pav_CMPGTU
; goto do_AvBin64x2
;
6124 case Iop_CmpGT64Sx2
: op
= Pav_CMPGTS
; goto do_AvBin64x2
;
6125 case Iop_PolynomialMulAdd64x2
: op
= Pav_POLYMULADD
; goto do_AvBin64x2
;
6127 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6128 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6129 HReg dst
= newVRegV(env
);
6130 addInstr(env
, PPCInstr_AvBin64x2(op
, dst
, arg1
, arg2
));
6134 case Iop_ShlN8x16
: op
= Pav_SHL
; goto do_AvShift8x16
;
6135 case Iop_SarN8x16
: op
= Pav_SAR
; goto do_AvShift8x16
;
6137 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6138 HReg dst
= newVRegV(env
);
6139 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6140 addInstr(env
, PPCInstr_AvBin8x16(op
, dst
, r_src
, v_shft
));
6144 case Iop_ShlN16x8
: op
= Pav_SHL
; goto do_AvShift16x8
;
6145 case Iop_ShrN16x8
: op
= Pav_SHR
; goto do_AvShift16x8
;
6146 case Iop_SarN16x8
: op
= Pav_SAR
; goto do_AvShift16x8
;
6148 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6149 HReg dst
= newVRegV(env
);
6150 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6151 addInstr(env
, PPCInstr_AvBin16x8(op
, dst
, r_src
, v_shft
));
6155 case Iop_ShlN32x4
: op
= Pav_SHL
; goto do_AvShift32x4
;
6156 case Iop_ShrN32x4
: op
= Pav_SHR
; goto do_AvShift32x4
;
6157 case Iop_SarN32x4
: op
= Pav_SAR
; goto do_AvShift32x4
;
6159 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6160 HReg dst
= newVRegV(env
);
6161 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6162 addInstr(env
, PPCInstr_AvBin32x4(op
, dst
, r_src
, v_shft
));
6166 case Iop_ShlN64x2
: op
= Pav_SHL
; goto do_AvShift64x2
;
6167 case Iop_ShrN64x2
: op
= Pav_SHR
; goto do_AvShift64x2
;
6168 case Iop_SarN64x2
: op
= Pav_SAR
; goto do_AvShift64x2
;
6170 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6171 HReg dst
= newVRegV(env
);
6172 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6173 addInstr(env
, PPCInstr_AvBin64x2(op
, dst
, r_src
, v_shft
));
6177 case Iop_ShrV128
: op
= Pav_SHR
; goto do_AvShiftV128
;
6178 case Iop_ShlV128
: op
= Pav_SHL
; goto do_AvShiftV128
;
6180 HReg dst
= newVRegV(env
);
6181 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6182 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6183 /* Note: shift value gets masked by 127 */
6184 addInstr(env
, PPCInstr_AvBinary(op
, dst
, r_src
, v_shft
));
6188 case Iop_Perm8x16
: {
6189 HReg dst
= newVRegV(env
);
6190 HReg v_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6191 HReg v_ctl
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6192 addInstr(env
, PPCInstr_AvPerm(dst
, v_src
, v_src
, v_ctl
));
6196 case Iop_CipherV128
: op
= Pav_CIPHERV128
; goto do_AvCipherV128
;
6197 case Iop_CipherLV128
: op
= Pav_CIPHERLV128
; goto do_AvCipherV128
;
6198 case Iop_NCipherV128
: op
= Pav_NCIPHERV128
; goto do_AvCipherV128
;
6199 case Iop_NCipherLV128
:op
= Pav_NCIPHERLV128
; goto do_AvCipherV128
;
6201 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6202 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6203 HReg dst
= newVRegV(env
);
6204 addInstr(env
, PPCInstr_AvCipherV128Binary(op
, dst
, arg1
, arg2
));
6208 case Iop_SHA256
:op
= Pav_SHA256
; goto do_AvHashV128
;
6209 case Iop_SHA512
:op
= Pav_SHA512
; goto do_AvHashV128
;
6211 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6212 HReg dst
= newVRegV(env
);
6213 PPCRI
* s_field
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6214 addInstr(env
, PPCInstr_AvHashV128Binary(op
, dst
, arg1
, s_field
));
6219 case Iop_I128StoBCD128
:
6221 HReg dst
= newVRegV(env
);
6222 HReg arg
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6223 PPCRI
* ps
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6225 addInstr(env
, PPCInstr_AvBinaryInt( Pav_I128StoBCD128
, dst
, arg
,
6230 case Iop_MulI128by10E
: op
= Pav_MulI128by10E
; goto do_MulI128E
;
6231 case Iop_MulI128by10ECarry
: op
= Pav_MulI128by10ECarry
; goto do_MulI128E
;
6233 HReg dst
= newVRegV(env
);
6234 HReg argL
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6235 HReg argR
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6236 addInstr(env
, PPCInstr_AvBinary(op
, dst
, argL
, argR
));
6240 case Iop_BCDAdd
:op
= Pav_BCDAdd
; goto do_AvBCDV128
;
6241 case Iop_BCDSub
:op
= Pav_BCDSub
; goto do_AvBCDV128
;
6243 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6244 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6245 HReg dst
= newVRegV(env
);
6246 addInstr(env
, PPCInstr_AvBCDV128Binary(op
, dst
, arg1
, arg2
));
6252 } /* switch (e->Iex.Binop.op) */
6253 } /* if (e->tag == Iex_Binop) */
6255 if (e
->tag
== Iex_Triop
) {
6256 IRTriop
*triop
= e
->Iex
.Triop
.details
;
6257 switch (triop
->op
) {
6258 case Iop_Add32Fx4
: fpop
= Pavfp_ADDF
; goto do_32Fx4_with_rm
;
6259 case Iop_Sub32Fx4
: fpop
= Pavfp_SUBF
; goto do_32Fx4_with_rm
;
6260 case Iop_Mul32Fx4
: fpop
= Pavfp_MULF
; goto do_32Fx4_with_rm
;
6263 HReg argL
= iselVecExpr(env
, triop
->arg2
, IEndianess
);
6264 HReg argR
= iselVecExpr(env
, triop
->arg3
, IEndianess
);
6265 HReg dst
= newVRegV(env
);
6266 /* FIXME: this is bogus, in the sense that Altivec ignores
6267 FPSCR.RM, at least for some FP operations. So setting the
6268 RM is pointless. This is only really correct in the case
6269 where the RM is known, at JIT time, to be Irrm_NEAREST,
6270 since -- at least for Altivec FP add/sub/mul -- the
6271 emitted insn is hardwired to round to nearest. */
6272 set_FPU_rounding_mode(env
, triop
->arg1
, IEndianess
);
6273 addInstr(env
, PPCInstr_AvBin32Fx4(fpop
, dst
, argL
, argR
));
6279 } /* switch (e->Iex.Triop.op) */
6280 } /* if (e->tag == Iex_Trinop) */
6283 if (e
->tag
== Iex_Const
) {
6284 vassert(e
->Iex
.Const
.con
->tag
== Ico_V128
);
6285 if (e
->Iex
.Const
.con
->Ico
.V128
== 0x0000) {
6286 return generate_zeroes_V128(env
);
6288 else if (e
->Iex
.Const
.con
->Ico
.V128
== 0xffff) {
6289 return generate_ones_V128(env
);
6293 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
6294 LibVEX_ppVexHwCaps(mode64
? VexArchPPC64
: VexArchPPC32
,
6297 vpanic("iselVecExpr_wrk(ppc)");
6301 /*---------------------------------------------------------*/
6302 /*--- ISEL: Statements ---*/
6303 /*---------------------------------------------------------*/
6305 static void iselStmt ( ISelEnv
* env
, IRStmt
* stmt
, IREndness IEndianess
)
6307 Bool mode64
= env
->mode64
;
6308 if (vex_traceflags
& VEX_TRACE_VCODE
) {
6309 vex_printf("\n -- ");
6314 switch (stmt
->tag
) {
6316 /* --------- STORE --------- */
6318 IRType tya
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.Store
.addr
);
6319 IRType tyd
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.Store
.data
);
6320 IREndness end
= stmt
->Ist
.Store
.end
;
6322 if (end
!= IEndianess
)
6324 if (!mode64
&& (tya
!= Ity_I32
))
6326 if (mode64
&& (tya
!= Ity_I64
))
6329 if (tyd
== Ity_I8
|| tyd
== Ity_I16
|| tyd
== Ity_I32
||
6330 (mode64
&& (tyd
== Ity_I64
))) {
6332 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6334 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6335 addInstr(env
, PPCInstr_Store( toUChar(sizeofIRType(tyd
)),
6336 am_addr
, r_src
, mode64
));
6339 if (tyd
== Ity_F64
) {
6341 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6343 HReg fr_src
= iselDblExpr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6345 PPCInstr_FpLdSt(False
/*store*/, 8, fr_src
, am_addr
));
6348 if (tyd
== Ity_F32
) {
6350 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6352 HReg fr_src
= iselFltExpr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6354 PPCInstr_FpLdSt(False
/*store*/, 4, fr_src
, am_addr
));
6357 if (tyd
== Ity_D64
) {
6359 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6361 HReg fr_src
= iselDfp64Expr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6363 PPCInstr_FpLdSt(False
/*store*/, 8, fr_src
, am_addr
));
6366 if (tyd
== Ity_D32
) {
6368 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6370 HReg fr_src
= iselDfp32Expr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6372 PPCInstr_FpLdSt(False
/*store*/, 4, fr_src
, am_addr
));
6375 if (tyd
== Ity_V128
) {
6377 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6379 HReg v_src
= iselVecExpr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6381 PPCInstr_AvLdSt(False
/*store*/, 16, v_src
, am_addr
));
6384 if (tyd
== Ity_I64
&& !mode64
) {
6385 /* Just calculate the address in the register. Life is too
6386 short to arse around trying and possibly failing to adjust
6387 the offset in a 'reg+offset' style amode. */
6389 HReg r_addr
= iselWordExpr_R(env
, stmt
->Ist
.Store
.addr
, IEndianess
);
6390 iselInt64Expr( &rHi32
, &rLo32
, env
, stmt
->Ist
.Store
.data
,
6392 addInstr(env
, PPCInstr_Store( 4/*byte-store*/,
6393 PPCAMode_IR( 0, r_addr
),
6395 False
/*32-bit insn please*/) );
6396 addInstr(env
, PPCInstr_Store( 4/*byte-store*/,
6397 PPCAMode_IR( 4, r_addr
),
6399 False
/*32-bit insn please*/) );
6405 /* --------- PUT --------- */
6407 IRType ty
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.Put
.data
);
6408 if (ty
== Ity_I8
|| ty
== Ity_I16
||
6409 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) {
6410 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6411 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6412 GuestStatePtr(mode64
) );
6413 addInstr(env
, PPCInstr_Store( toUChar(sizeofIRType(ty
)),
6414 am_addr
, r_src
, mode64
));
6417 if (!mode64
&& ty
== Ity_I64
) {
6419 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6420 GuestStatePtr(mode64
) );
6421 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
6422 iselInt64Expr(&rHi
,&rLo
, env
, stmt
->Ist
.Put
.data
, IEndianess
);
6423 addInstr(env
, PPCInstr_Store( 4, am_addr
, rHi
, mode64
));
6424 addInstr(env
, PPCInstr_Store( 4, am_addr4
, rLo
, mode64
));
6427 if (ty
== Ity_I128
) {
6429 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6430 GuestStatePtr(mode64
) );
6431 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
6433 iselInt128Expr(&rHi
,&rLo
, env
, stmt
->Ist
.Put
.data
, IEndianess
);
6434 addInstr(env
, PPCInstr_Store( 4, am_addr
, rHi
, mode64
));
6435 addInstr(env
, PPCInstr_Store( 4, am_addr4
, rLo
, mode64
));
6438 if (ty
== Ity_F128
) {
6439 /* Guest state vectors are 16byte aligned,
6440 so don't need to worry here */
6441 HReg v_src
= iselFp128Expr(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6443 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6444 GuestStatePtr(mode64
) );
6446 PPCInstr_AvLdSt(False
/*store*/, 16, v_src
, am_addr
));
6449 if (ty
== Ity_V128
) {
6450 /* Guest state vectors are 16byte aligned,
6451 so don't need to worry here */
6452 HReg v_src
= iselVecExpr(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6453 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6454 GuestStatePtr(mode64
) );
6456 PPCInstr_AvLdSt(False
/*store*/, 16, v_src
, am_addr
));
6459 if (ty
== Ity_F64
) {
6460 HReg fr_src
= iselDblExpr(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6461 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6462 GuestStatePtr(mode64
) );
6463 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
6467 if (ty
== Ity_D32
) {
6468 /* The 32-bit value is stored in a 64-bit register */
6469 HReg fr_src
= iselDfp32Expr( env
, stmt
->Ist
.Put
.data
, IEndianess
);
6470 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6471 GuestStatePtr(mode64
) );
6472 addInstr( env
, PPCInstr_FpLdSt( False
/*store*/, 8,
6473 fr_src
, am_addr
) );
6476 if (ty
== Ity_D64
) {
6477 HReg fr_src
= iselDfp64Expr( env
, stmt
->Ist
.Put
.data
, IEndianess
);
6478 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6479 GuestStatePtr(mode64
) );
6480 addInstr( env
, PPCInstr_FpLdSt( False
/*store*/, 8, fr_src
, am_addr
) );
6486 /* --------- Indexed PUT --------- */
6488 IRPutI
*puti
= stmt
->Ist
.PutI
.details
;
6491 = genGuestArrayOffset(
6493 puti
->ix
, puti
->bias
,
6495 IRType ty
= typeOfIRExpr(env
->type_env
, puti
->data
);
6496 if (mode64
&& ty
== Ity_I64
) {
6497 HReg r_src
= iselWordExpr_R(env
, puti
->data
, IEndianess
);
6498 addInstr(env
, PPCInstr_Store( toUChar(8),
6499 dst_am
, r_src
, mode64
));
6502 if ((!mode64
) && ty
== Ity_I32
) {
6503 HReg r_src
= iselWordExpr_R(env
, puti
->data
, IEndianess
);
6504 addInstr(env
, PPCInstr_Store( toUChar(4),
6505 dst_am
, r_src
, mode64
));
6511 /* --------- TMP --------- */
6513 IRTemp tmp
= stmt
->Ist
.WrTmp
.tmp
;
6514 IRType ty
= typeOfIRTemp(env
->type_env
, tmp
);
6515 if (ty
== Ity_I8
|| ty
== Ity_I16
||
6516 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) {
6517 HReg r_dst
= lookupIRTemp(env
, tmp
);
6518 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6519 addInstr(env
, mk_iMOVds_RR( r_dst
, r_src
));
6522 if (!mode64
&& ty
== Ity_I64
) {
6523 HReg r_srcHi
, r_srcLo
, r_dstHi
, r_dstLo
;
6525 iselInt64Expr(&r_srcHi
,&r_srcLo
, env
, stmt
->Ist
.WrTmp
.data
,
6527 lookupIRTempPair( &r_dstHi
, &r_dstLo
, env
, tmp
);
6528 addInstr(env
, mk_iMOVds_RR(r_dstHi
, r_srcHi
) );
6529 addInstr(env
, mk_iMOVds_RR(r_dstLo
, r_srcLo
) );
6532 if (mode64
&& ty
== Ity_I128
) {
6533 HReg r_srcHi
, r_srcLo
, r_dstHi
, r_dstLo
;
6534 iselInt128Expr(&r_srcHi
,&r_srcLo
, env
, stmt
->Ist
.WrTmp
.data
,
6536 lookupIRTempPair( &r_dstHi
, &r_dstLo
, env
, tmp
);
6537 addInstr(env
, mk_iMOVds_RR(r_dstHi
, r_srcHi
) );
6538 addInstr(env
, mk_iMOVds_RR(r_dstLo
, r_srcLo
) );
6541 if (!mode64
&& ty
== Ity_I128
) {
6542 HReg r_srcHi
, r_srcMedHi
, r_srcMedLo
, r_srcLo
;
6543 HReg r_dstHi
, r_dstMedHi
, r_dstMedLo
, r_dstLo
;
6545 iselInt128Expr_to_32x4(&r_srcHi
, &r_srcMedHi
,
6546 &r_srcMedLo
, &r_srcLo
,
6547 env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6549 lookupIRTempQuad( &r_dstHi
, &r_dstMedHi
, &r_dstMedLo
,
6550 &r_dstLo
, env
, tmp
);
6552 addInstr(env
, mk_iMOVds_RR(r_dstHi
, r_srcHi
) );
6553 addInstr(env
, mk_iMOVds_RR(r_dstMedHi
, r_srcMedHi
) );
6554 addInstr(env
, mk_iMOVds_RR(r_dstMedLo
, r_srcMedLo
) );
6555 addInstr(env
, mk_iMOVds_RR(r_dstLo
, r_srcLo
) );
6559 PPCCondCode cond
= iselCondCode(env
, stmt
->Ist
.WrTmp
.data
,
6561 HReg r_dst
= lookupIRTemp(env
, tmp
);
6562 addInstr(env
, PPCInstr_Set(cond
, r_dst
));
6565 if (ty
== Ity_F64
) {
6566 HReg fr_dst
= lookupIRTemp(env
, tmp
);
6567 HReg fr_src
= iselDblExpr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6568 addInstr(env
, PPCInstr_FpUnary(Pfp_MOV
, fr_dst
, fr_src
));
6571 if (ty
== Ity_F32
) {
6572 HReg fr_dst
= lookupIRTemp(env
, tmp
);
6573 HReg fr_src
= iselFltExpr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6574 addInstr(env
, PPCInstr_FpUnary(Pfp_MOV
, fr_dst
, fr_src
));
6577 if (ty
== Ity_D32
) {
6578 HReg fr_dst
= lookupIRTemp(env
, tmp
);
6579 HReg fr_src
= iselDfp32Expr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6580 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_MOV
, fr_dst
, fr_src
));
6583 if (ty
== Ity_F128
) {
6584 HReg v_dst
= lookupIRTemp(env
, tmp
);
6585 HReg v_src
= iselFp128Expr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6586 addInstr(env
, PPCInstr_AvUnary(Pav_MOV
, v_dst
, v_src
));
6589 if (ty
== Ity_V128
) {
6590 HReg v_dst
= lookupIRTemp(env
, tmp
);
6591 HReg v_src
= iselVecExpr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6592 addInstr(env
, PPCInstr_AvUnary(Pav_MOV
, v_dst
, v_src
));
6595 if (ty
== Ity_D64
) {
6596 HReg fr_dst
= lookupIRTemp( env
, tmp
);
6597 HReg fr_src
= iselDfp64Expr( env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6598 addInstr( env
, PPCInstr_Dfp64Unary( Pfp_MOV
, fr_dst
, fr_src
) );
6601 if (ty
== Ity_D128
) {
6602 HReg fr_srcHi
, fr_srcLo
, fr_dstHi
, fr_dstLo
;
6603 // lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
6604 lookupIRTempPair( &fr_dstHi
, &fr_dstLo
, env
, tmp
);
6605 iselDfp128Expr( &fr_srcHi
, &fr_srcLo
, env
, stmt
->Ist
.WrTmp
.data
,
6607 addInstr( env
, PPCInstr_Dfp64Unary( Pfp_MOV
, fr_dstHi
, fr_srcHi
) );
6608 addInstr( env
, PPCInstr_Dfp64Unary( Pfp_MOV
, fr_dstLo
, fr_srcLo
) );
6614 /* --------- Load Linked or Store Conditional --------- */
6616 IRTemp res
= stmt
->Ist
.LLSC
.result
;
6617 IRType tyRes
= typeOfIRTemp(env
->type_env
, res
);
6618 IRType tyAddr
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.LLSC
.addr
);
6620 if (stmt
->Ist
.LLSC
.end
!= IEndianess
)
6622 if (!mode64
&& (tyAddr
!= Ity_I32
))
6624 if (mode64
&& (tyAddr
!= Ity_I64
))
6627 if (stmt
->Ist
.LLSC
.storedata
== NULL
) {
6629 HReg r_addr
= iselWordExpr_R( env
, stmt
->Ist
.LLSC
.addr
, IEndianess
);
6630 HReg r_dst
= lookupIRTemp(env
, res
);
6631 if (tyRes
== Ity_I8
) {
6632 addInstr(env
, PPCInstr_LoadL( 1, r_dst
, r_addr
, mode64
));
6635 if (tyRes
== Ity_I16
) {
6636 addInstr(env
, PPCInstr_LoadL( 2, r_dst
, r_addr
, mode64
));
6639 if (tyRes
== Ity_I32
) {
6640 addInstr(env
, PPCInstr_LoadL( 4, r_dst
, r_addr
, mode64
));
6643 if (tyRes
== Ity_I64
&& mode64
) {
6644 addInstr(env
, PPCInstr_LoadL( 8, r_dst
, r_addr
, mode64
));
6650 HReg r_res
= lookupIRTemp(env
, res
); /* :: Ity_I1 */
6651 HReg r_a
= iselWordExpr_R(env
, stmt
->Ist
.LLSC
.addr
, IEndianess
);
6652 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.LLSC
.storedata
,
6654 HReg r_tmp
= newVRegI(env
);
6655 IRType tyData
= typeOfIRExpr(env
->type_env
,
6656 stmt
->Ist
.LLSC
.storedata
);
6657 vassert(tyRes
== Ity_I1
);
6658 if (tyData
== Ity_I8
|| tyData
== Ity_I16
|| tyData
== Ity_I32
||
6659 (tyData
== Ity_I64
&& mode64
)) {
6662 if (tyData
== Ity_I64
)
6664 else if (tyData
== Ity_I32
)
6666 else if (tyData
== Ity_I16
)
6668 else if (tyData
== Ity_I8
)
6671 addInstr(env
, PPCInstr_StoreC( size
,
6672 r_a
, r_src
, mode64
));
6673 addInstr(env
, PPCInstr_MfCR( r_tmp
));
6674 addInstr(env
, PPCInstr_Shft(
6676 env
->mode64
? False
: True
6677 /*F:64-bit, T:32-bit shift*/,
6679 PPCRH_Imm(False
/*unsigned*/, 29)));
6680 /* Probably unnecessary, since the IR dest type is Ity_I1,
6681 and so we are entitled to leave whatever junk we like
6682 drifting round in the upper 31 or 63 bits of r_res.
6683 However, for the sake of conservativeness .. */
6684 addInstr(env
, PPCInstr_Alu(
6687 PPCRH_Imm(False
/*signed*/, 1)));
6696 /* --------- Call to DIRTY helper --------- */
6698 IRDirty
* d
= stmt
->Ist
.Dirty
.details
;
6700 /* Figure out the return type, if any. */
6701 IRType retty
= Ity_INVALID
;
6702 if (d
->tmp
!= IRTemp_INVALID
)
6703 retty
= typeOfIRTemp(env
->type_env
, d
->tmp
);
6705 /* Throw out any return types we don't know about. The set of
6706 acceptable return types is the same in both 32- and 64-bit
6707 mode, so we don't need to inspect mode64 to make a
6709 Bool retty_ok
= False
;
6711 case Ity_INVALID
: /* function doesn't return anything */
6713 case Ity_I64
: case Ity_I32
: case Ity_I16
: case Ity_I8
:
6714 retty_ok
= True
; break;
6719 break; /* will go to stmt_fail: */
6721 /* Marshal args, do the call, clear stack, set the return value
6722 to 0x555..555 if this is a conditional call that returns a
6723 value and the call is skipped. */
6725 RetLoc rloc
= mk_RetLoc_INVALID();
6726 doHelperCall( &addToSp
, &rloc
, env
, d
->guard
, d
->cee
, retty
, d
->args
,
6728 vassert(is_sane_RetLoc(rloc
));
6730 /* Now figure out what to do with the returned value, if any. */
6733 /* No return value. Nothing to do. */
6734 vassert(d
->tmp
== IRTemp_INVALID
);
6735 vassert(rloc
.pri
== RLPri_None
);
6736 vassert(addToSp
== 0);
6739 case Ity_I32
: case Ity_I16
: case Ity_I8
: {
6740 /* The returned value is in %r3. Park it in the register
6741 associated with tmp. */
6742 HReg r_dst
= lookupIRTemp(env
, d
->tmp
);
6743 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
6744 vassert(rloc
.pri
== RLPri_Int
);
6745 vassert(addToSp
== 0);
6750 /* The returned value is in %r3. Park it in the register
6751 associated with tmp. */
6752 HReg r_dst
= lookupIRTemp(env
, d
->tmp
);
6753 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
6754 vassert(rloc
.pri
== RLPri_Int
);
6755 vassert(addToSp
== 0);
6757 /* The returned value is in %r3:%r4. Park it in the
6758 register-pair associated with tmp. */
6759 HReg r_dstHi
= INVALID_HREG
;
6760 HReg r_dstLo
= INVALID_HREG
;
6761 lookupIRTempPair( &r_dstHi
, &r_dstLo
, env
, d
->tmp
);
6762 addInstr(env
, mk_iMOVds_RR(r_dstHi
, hregPPC_GPR3(mode64
)));
6763 addInstr(env
, mk_iMOVds_RR(r_dstLo
, hregPPC_GPR4(mode64
)));
6764 vassert(rloc
.pri
== RLPri_2Int
);
6765 vassert(addToSp
== 0);
6769 /* The returned value is on the stack, and *retloc tells
6770 us where. Fish it off the stack and then move the
6771 stack pointer upwards to clear it, as directed by
6773 vassert(rloc
.pri
== RLPri_V128SpRel
);
6774 vassert(addToSp
>= 16);
6775 HReg dst
= lookupIRTemp(env
, d
->tmp
);
6776 PPCAMode
* am
= PPCAMode_IR(rloc
.spOff
, StackFramePtr(mode64
));
6777 addInstr(env
, PPCInstr_AvLdSt( True
/*load*/, 16, dst
, am
));
6778 add_to_sp(env
, addToSp
);
6787 /* --------- MEM FENCE --------- */
6789 switch (stmt
->Ist
.MBE
.event
) {
6791 addInstr(env
, PPCInstr_MFence());
6798 /* --------- INSTR MARK --------- */
6799 /* Doesn't generate any executable code ... */
6803 /* --------- ABI HINT --------- */
6804 /* These have no meaning (denotation in the IR) and so we ignore
6805 them ... if any actually made it this far. */
6809 /* --------- NO-OP --------- */
6810 /* Fairly self-explanatory, wouldn't you say? */
6814 /* --------- EXIT --------- */
6816 IRConst
* dst
= stmt
->Ist
.Exit
.dst
;
6817 if (!mode64
&& dst
->tag
!= Ico_U32
)
6818 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
6819 if (mode64
&& dst
->tag
!= Ico_U64
)
6820 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
6822 PPCCondCode cc
= iselCondCode(env
, stmt
->Ist
.Exit
.guard
, IEndianess
);
6823 PPCAMode
* amCIA
= PPCAMode_IR(stmt
->Ist
.Exit
.offsIP
,
6824 hregPPC_GPR31(mode64
));
6826 /* Case: boring transfer to known address */
6827 if (stmt
->Ist
.Exit
.jk
== Ijk_Boring
6828 || stmt
->Ist
.Exit
.jk
== Ijk_Call
6829 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
6830 if (env
->chainingAllowed
) {
6831 /* .. almost always true .. */
6832 /* Skip the event check at the dst if this is a forwards
6836 ? (((Addr64
)stmt
->Ist
.Exit
.dst
->Ico
.U64
) > (Addr64
)env
->max_ga
)
6837 : (((Addr32
)stmt
->Ist
.Exit
.dst
->Ico
.U32
) > (Addr32
)env
->max_ga
);
6838 if (0) vex_printf("%s", toFastEP
? "Y" : ",");
6839 addInstr(env
, PPCInstr_XDirect(
6840 mode64
? (Addr64
)stmt
->Ist
.Exit
.dst
->Ico
.U64
6841 : (Addr64
)stmt
->Ist
.Exit
.dst
->Ico
.U32
,
6842 amCIA
, cc
, toFastEP
));
6844 /* .. very occasionally .. */
6845 /* We can't use chaining, so ask for an assisted transfer,
6846 as that's the only alternative that is allowable. */
6847 HReg r
= iselWordExpr_R(env
, IRExpr_Const(stmt
->Ist
.Exit
.dst
),
6849 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, cc
, Ijk_Boring
));
6854 /* Case: assisted transfer to arbitrary address */
6855 switch (stmt
->Ist
.Exit
.jk
) {
6856 /* Keep this list in sync with that in iselNext below */
6864 case Ijk_Sys_syscall
:
6865 case Ijk_InvalICache
:
6867 HReg r
= iselWordExpr_R(env
, IRExpr_Const(stmt
->Ist
.Exit
.dst
),
6869 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, cc
,
6870 stmt
->Ist
.Exit
.jk
));
6877 /* Do we ever expect to see any other kind? */
6885 vpanic("iselStmt(ppc)");
6889 /*---------------------------------------------------------*/
6890 /*--- ISEL: Basic block terminators (Nexts) ---*/
6891 /*---------------------------------------------------------*/
6893 static void iselNext ( ISelEnv
* env
,
6894 IRExpr
* next
, IRJumpKind jk
, Int offsIP
,
6895 IREndness IEndianess
)
6897 if (vex_traceflags
& VEX_TRACE_VCODE
) {
6898 vex_printf( "\n-- PUT(%d) = ", offsIP
);
6900 vex_printf( "; exit-");
6905 PPCCondCode always
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
6907 /* Case: boring transfer to known address */
6908 if (next
->tag
== Iex_Const
) {
6909 IRConst
* cdst
= next
->Iex
.Const
.con
;
6910 vassert(cdst
->tag
== (env
->mode64
? Ico_U64
:Ico_U32
));
6911 if (jk
== Ijk_Boring
|| jk
== Ijk_Call
) {
6912 /* Boring transfer to known address */
6913 PPCAMode
* amCIA
= PPCAMode_IR(offsIP
, hregPPC_GPR31(env
->mode64
));
6914 if (env
->chainingAllowed
) {
6915 /* .. almost always true .. */
6916 /* Skip the event check at the dst if this is a forwards
6920 ? (((Addr64
)cdst
->Ico
.U64
) > (Addr64
)env
->max_ga
)
6921 : (((Addr32
)cdst
->Ico
.U32
) > (Addr32
)env
->max_ga
);
6922 if (0) vex_printf("%s", toFastEP
? "X" : ".");
6923 addInstr(env
, PPCInstr_XDirect(
6924 env
->mode64
? (Addr64
)cdst
->Ico
.U64
6925 : (Addr64
)cdst
->Ico
.U32
,
6926 amCIA
, always
, toFastEP
));
6928 /* .. very occasionally .. */
6929 /* We can't use chaining, so ask for an assisted transfer,
6930 as that's the only alternative that is allowable. */
6931 HReg r
= iselWordExpr_R(env
, next
, IEndianess
);
6932 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, always
,
6939 /* Case: call/return (==boring) transfer to any address */
6941 case Ijk_Boring
: case Ijk_Ret
: case Ijk_Call
: {
6942 HReg r
= iselWordExpr_R(env
, next
, IEndianess
);
6943 PPCAMode
* amCIA
= PPCAMode_IR(offsIP
, hregPPC_GPR31(env
->mode64
));
6944 if (env
->chainingAllowed
) {
6945 addInstr(env
, PPCInstr_XIndir(r
, amCIA
, always
));
6947 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, always
,
6956 /* Case: assisted transfer to arbitrary address */
6958 /* Keep this list in sync with that for Ist_Exit above */
6966 case Ijk_Sys_syscall
:
6967 case Ijk_InvalICache
:
6969 HReg r
= iselWordExpr_R(env
, next
, IEndianess
);
6970 PPCAMode
* amCIA
= PPCAMode_IR(offsIP
, hregPPC_GPR31(env
->mode64
));
6971 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, always
, jk
));
6978 vex_printf( "\n-- PUT(%d) = ", offsIP
);
6980 vex_printf( "; exit-");
6983 vassert(0); // are we expecting any other kind?
6987 /*---------------------------------------------------------*/
6988 /*--- Insn selector top-level ---*/
6989 /*---------------------------------------------------------*/
6991 /* Translate an entire SB to ppc code. */
6992 HInstrArray
* iselSB_PPC ( const IRSB
* bb
,
6994 const VexArchInfo
* archinfo_host
,
6995 const VexAbiInfo
* vbi
,
6996 Int offs_Host_EvC_Counter
,
6997 Int offs_Host_EvC_FailAddr
,
6998 Bool chainingAllowed
,
7004 HReg hregLo
, hregMedLo
, hregMedHi
, hregHi
;
7006 UInt hwcaps_host
= archinfo_host
->hwcaps
;
7007 Bool mode64
= False
;
7008 UInt mask32
, mask64
;
7009 PPCAMode
*amCounter
, *amFailAddr
;
7010 IREndness IEndianess
;
7012 vassert(arch_host
== VexArchPPC32
|| arch_host
== VexArchPPC64
);
7013 mode64
= arch_host
== VexArchPPC64
;
7015 /* do some sanity checks,
7016 * Note: no 32-bit support for ISA 3.0
7018 mask32
= VEX_HWCAPS_PPC32_F
| VEX_HWCAPS_PPC32_V
7019 | VEX_HWCAPS_PPC32_FX
| VEX_HWCAPS_PPC32_GX
| VEX_HWCAPS_PPC32_VX
7020 | VEX_HWCAPS_PPC32_DFP
| VEX_HWCAPS_PPC32_ISA2_07
;
7022 mask64
= VEX_HWCAPS_PPC64_V
| VEX_HWCAPS_PPC64_FX
7023 | VEX_HWCAPS_PPC64_GX
| VEX_HWCAPS_PPC64_VX
| VEX_HWCAPS_PPC64_DFP
7024 | VEX_HWCAPS_PPC64_ISA2_07
| VEX_HWCAPS_PPC64_ISA3_0
;
7027 vassert((hwcaps_host
& mask32
) == 0);
7029 vassert((hwcaps_host
& mask64
) == 0);
7032 /* Check that the host's endianness is as expected. */
7033 vassert((archinfo_host
->endness
== VexEndnessBE
) ||
7034 (archinfo_host
->endness
== VexEndnessLE
));
7036 if (archinfo_host
->endness
== VexEndnessBE
)
7037 IEndianess
= Iend_BE
;
7039 IEndianess
= Iend_LE
;
7041 /* Make up an initial environment to use. */
7042 env
= LibVEX_Alloc_inline(sizeof(ISelEnv
));
7045 /* Are we being ppc32 or ppc64? */
7046 env
->mode64
= mode64
;
7048 /* Set up output code array. */
7049 env
->code
= newHInstrArray();
7051 /* Copy BB's type env. */
7052 env
->type_env
= bb
->tyenv
;
7054 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
7055 * change as we go along.
7057 * vregmap2 and vregmap3 are only used in 32 bit mode
7058 * for supporting I128 in 32-bit mode
7060 env
->n_vregmap
= bb
->tyenv
->types_used
;
7061 env
->vregmapLo
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7062 env
->vregmapMedLo
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7064 env
->vregmapMedHi
= NULL
;
7065 env
->vregmapHi
= NULL
;
7067 env
->vregmapMedHi
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7068 env
->vregmapHi
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7071 /* and finally ... */
7072 env
->chainingAllowed
= chainingAllowed
;
7073 env
->max_ga
= max_ga
;
7074 env
->hwcaps
= hwcaps_host
;
7075 env
->previous_rm
= NULL
;
7078 /* For each IR temporary, allocate a suitably-kinded virtual
7081 for (i
= 0; i
< env
->n_vregmap
; i
++) {
7082 hregLo
= hregMedLo
= hregMedHi
= hregHi
= INVALID_HREG
;
7083 switch (bb
->tyenv
->types
[i
]) {
7089 hregLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7091 hregLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7096 hregLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7098 hregLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7099 hregMedLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7104 hregLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7105 hregMedLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7107 hregLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7108 hregMedLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7109 hregMedHi
= mkHReg(True
, HRcInt32
, 0, j
++);
7110 hregHi
= mkHReg(True
, HRcInt32
, 0, j
++);
7115 hregLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7119 hregLo
= mkHReg(True
, HRcVec128
, 0, j
++);
7123 hregLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7126 hregLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7127 hregMedLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7130 ppIRType(bb
->tyenv
->types
[i
]);
7131 vpanic("iselBB(ppc): IRTemp type");
7133 env
->vregmapLo
[i
] = hregLo
;
7134 env
->vregmapMedLo
[i
] = hregMedLo
;
7136 env
->vregmapMedHi
[i
] = hregMedHi
;
7137 env
->vregmapHi
[i
] = hregHi
;
7142 /* The very first instruction must be an event check. */
7143 amCounter
= PPCAMode_IR(offs_Host_EvC_Counter
, hregPPC_GPR31(mode64
));
7144 amFailAddr
= PPCAMode_IR(offs_Host_EvC_FailAddr
, hregPPC_GPR31(mode64
));
7145 addInstr(env
, PPCInstr_EvCheck(amCounter
, amFailAddr
));
7147 /* Possibly a block counter increment (for profiling). At this
7148 point we don't know the address of the counter, so just pretend
7149 it is zero. It will have to be patched later, but before this
7150 translation is used, by a call to LibVEX_patchProfCtr. */
7152 addInstr(env
, PPCInstr_ProfInc());
7155 /* Ok, finally we can iterate over the statements. */
7156 for (i
= 0; i
< bb
->stmts_used
; i
++)
7157 iselStmt(env
, bb
->stmts
[i
], IEndianess
);
7159 iselNext(env
, bb
->next
, bb
->jumpkind
, bb
->offsIP
, IEndianess
);
7161 /* record the number of vregs we used. */
7162 env
->code
->n_vregs
= env
->vreg_ctr
;
7167 /*---------------------------------------------------------------*/
7168 /*--- end host_ppc_isel.c ---*/
7169 /*---------------------------------------------------------------*/