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
)));
2218 if (op_unop
== Iop_Left64
&& !mode64
)
2220 r_dst
= newVRegI(env
);
2221 r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2222 addInstr(env
, PPCInstr_Unary(Pun_NEG
,r_dst
,r_src
));
2223 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_dst
, r_dst
, PPCRH_Reg(r_src
)));
2227 case Iop_CmpwNEZ32
: {
2228 HReg r_dst
= newVRegI(env
);
2229 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2230 addInstr(env
, PPCInstr_Unary(Pun_NEG
,r_dst
,r_src
));
2231 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_dst
, r_dst
, PPCRH_Reg(r_src
)));
2232 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
2233 r_dst
, r_dst
, PPCRH_Imm(False
, 31)));
2237 case Iop_CmpwNEZ64
: {
2238 HReg r_dst
= newVRegI(env
);
2239 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2240 if (!mode64
) goto irreducible
;
2241 addInstr(env
, PPCInstr_Unary(Pun_NEG
,r_dst
,r_src
));
2242 addInstr(env
, PPCInstr_Alu(Palu_OR
, r_dst
, r_dst
, PPCRH_Reg(r_src
)));
2243 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, False
/*64bit shift*/,
2244 r_dst
, r_dst
, PPCRH_Imm(False
, 63)));
2248 case Iop_V128to32
: {
2250 HReg dst
= newVRegI(env
);
2251 HReg vec
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2252 PPCAMode
*am_off0
, *am_off_word0
;
2253 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
2255 // get a quadword aligned address within our stack space
2256 r_aligned16
= get_sp_aligned16( env
);
2257 am_off0
= PPCAMode_IR( 0, r_aligned16
);
2259 /* Note that the store below (done via PPCInstr_AvLdSt) uses
2260 * stvx, which stores the vector in proper LE format,
2261 * with byte zero (far right byte of the register in LE format)
2262 * stored at the lowest memory address. Therefore, to obtain
2263 * integer word zero, we need to use that lowest memory address
2264 * as the base for the load.
2266 if (IEndianess
== Iend_LE
)
2267 am_off_word0
= am_off0
;
2269 am_off_word0
= PPCAMode_IR( 12,r_aligned16
);
2271 // store vec, load low word to dst
2273 PPCInstr_AvLdSt( False
/*store*/, 16, vec
, am_off0
));
2275 PPCInstr_Load( 4, dst
, am_off_word0
, mode64
));
2277 add_to_sp( env
, 32 ); // Reset SP
2282 case Iop_V128HIto64
:
2285 HReg dst
= newVRegI(env
);
2286 HReg vec
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2287 PPCAMode
*am_off0
, *am_off8
, *am_off_arg
;
2288 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
2290 // get a quadword aligned address within our stack space
2291 r_aligned16
= get_sp_aligned16( env
);
2292 am_off0
= PPCAMode_IR( 0, r_aligned16
);
2293 am_off8
= PPCAMode_IR( 8 ,r_aligned16
);
2295 // store vec, load low word or high to dst
2297 PPCInstr_AvLdSt( False
/*store*/, 16, vec
, am_off0
));
2298 if (IEndianess
== Iend_LE
) {
2299 if (op_unop
== Iop_V128HIto64
)
2300 am_off_arg
= am_off8
;
2302 am_off_arg
= am_off0
;
2304 if (op_unop
== Iop_V128HIto64
)
2305 am_off_arg
= am_off0
;
2307 am_off_arg
= am_off8
;
2315 add_to_sp( env
, 32 ); // Reset SP
2323 /* These are no-ops. */
2324 return iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2326 /* ReinterpF64asI64(e) */
2327 /* Given an IEEE754 double, produce an I64 with the same bit
2329 case Iop_ReinterpF64asI64
:
2332 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2333 HReg r_dst
= newVRegI(env
);
2335 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
2336 am_addr
= PPCAMode_IR( 0, StackFramePtr(mode64
) );
2339 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
2342 addInstr(env
, PPCInstr_Load( 8, r_dst
, am_addr
, mode64
));
2344 add_to_sp( env
, 16 ); // Reset SP
2349 /* ReinterpF32asI32(e) */
2350 /* Given an IEEE754 float, produce an I32 with the same bit
2352 case Iop_ReinterpF32asI32
: {
2353 /* I believe this generates correct code for both 32- and
2356 HReg fr_src
= iselFltExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2357 HReg r_dst
= newVRegI(env
);
2359 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
2360 am_addr
= PPCAMode_IR( 0, StackFramePtr(mode64
) );
2363 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 4,
2366 addInstr(env
, PPCInstr_Load( 4, r_dst
, am_addr
, mode64
));
2368 add_to_sp( env
, 16 ); // Reset SP
2373 case Iop_ReinterpD64asI64
:
2376 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2377 HReg r_dst
= newVRegI(env
);
2379 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
2380 am_addr
= PPCAMode_IR( 0, StackFramePtr(mode64
) );
2383 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
2386 addInstr(env
, PPCInstr_Load( 8, r_dst
, am_addr
, mode64
));
2387 add_to_sp( env
, 16 ); // Reset SP
2392 case Iop_BCDtoDPB
: {
2393 /* the following is only valid in 64 bit mode */
2399 HReg r_dst
= newVRegI(env
);
2404 argregs
[0] = hregPPC_GPR3(mode64
);
2406 argiregs
|= (1 << (argreg
+3));
2407 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++],
2408 iselWordExpr_R(env
, e
->Iex
.Unop
.arg
,
2411 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
2412 if (IEndianess
== Iend_LE
) {
2413 addInstr(env
, PPCInstr_Call( cc
, (Addr
)h_calc_BCDtoDPB
,
2415 mk_RetLoc_simple(RLPri_Int
)) );
2418 fdescr
= (HWord
*)h_calc_BCDtoDPB
;
2419 addInstr(env
, PPCInstr_Call( cc
, (Addr64
)(fdescr
[0]),
2421 mk_RetLoc_simple(RLPri_Int
)) );
2424 addInstr(env
, mk_iMOVds_RR(r_dst
, argregs
[0]));
2428 case Iop_DPBtoBCD
: {
2429 /* the following is only valid in 64 bit mode */
2435 HReg r_dst
= newVRegI(env
);
2440 argregs
[0] = hregPPC_GPR3(mode64
);
2442 argiregs
|= (1 << (argreg
+3));
2443 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++],
2444 iselWordExpr_R(env
, e
->Iex
.Unop
.arg
,
2447 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
2449 if (IEndianess
== Iend_LE
) {
2450 addInstr(env
, PPCInstr_Call( cc
, (Addr
)h_calc_DPBtoBCD
,
2452 mk_RetLoc_simple(RLPri_Int
) ) );
2455 fdescr
= (HWord
*)h_calc_DPBtoBCD
;
2456 addInstr(env
, PPCInstr_Call( cc
, (Addr64
)(fdescr
[0]),
2458 mk_RetLoc_simple(RLPri_Int
) ) );
2461 addInstr(env
, mk_iMOVds_RR(r_dst
, argregs
[0]));
2464 case Iop_F32toF16x4
: {
2465 HReg vdst
= newVRegV(env
); /* V128 */
2466 HReg dst
= newVRegI(env
); /* I64*/
2467 HReg r0
= newVRegI(env
); /* I16*/
2468 HReg r1
= newVRegI(env
); /* I16*/
2469 HReg r2
= newVRegI(env
); /* I16*/
2470 HReg r3
= newVRegI(env
); /* I16*/
2471 HReg vsrc
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2472 PPCAMode
*am_off0
, *am_off2
, *am_off4
, *am_off6
, *am_off8
;
2473 PPCAMode
*am_off10
, *am_off12
, *am_off14
;
2476 sub_from_sp( env
, 32 ); // Move SP down
2478 /* issue instruction */
2479 addInstr(env
, PPCInstr_AvUnary(Pav_F32toF16x4
, vdst
, vsrc
));
2481 /* Get a quadword aligned address within our stack space */
2482 r_aligned16
= get_sp_aligned16( env
);
2483 am_off0
= PPCAMode_IR( 0, r_aligned16
);
2484 am_off2
= PPCAMode_IR( 2, r_aligned16
);
2485 am_off4
= PPCAMode_IR( 4, r_aligned16
);
2486 am_off6
= PPCAMode_IR( 6, r_aligned16
);
2487 am_off8
= PPCAMode_IR( 8, r_aligned16
);
2488 am_off10
= PPCAMode_IR( 10, r_aligned16
);
2489 am_off12
= PPCAMode_IR( 12, r_aligned16
);
2490 am_off14
= PPCAMode_IR( 14, r_aligned16
);
2492 /* Store v128 result to stack. */
2493 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, vdst
, am_off0
));
2495 /* fetch four I16 from V128, store into contiguous I64 via stack, */
2496 if (IEndianess
== Iend_LE
) {
2497 addInstr(env
, PPCInstr_Load( 2, r3
, am_off12
, mode64
));
2498 addInstr(env
, PPCInstr_Load( 2, r2
, am_off8
, mode64
));
2499 addInstr(env
, PPCInstr_Load( 2, r1
, am_off4
, mode64
));
2500 addInstr(env
, PPCInstr_Load( 2, r0
, am_off0
, mode64
));
2502 addInstr(env
, PPCInstr_Load( 2, r0
, am_off14
, mode64
));
2503 addInstr(env
, PPCInstr_Load( 2, r1
, am_off10
, mode64
));
2504 addInstr(env
, PPCInstr_Load( 2, r2
, am_off6
, mode64
));
2505 addInstr(env
, PPCInstr_Load( 2, r3
, am_off2
, mode64
));
2508 /* store in contiguous 64-bit values */
2509 addInstr(env
, PPCInstr_Store( 2, am_off6
, r3
, mode64
));
2510 addInstr(env
, PPCInstr_Store( 2, am_off4
, r2
, mode64
));
2511 addInstr(env
, PPCInstr_Store( 2, am_off2
, r1
, mode64
));
2512 addInstr(env
, PPCInstr_Store( 2, am_off0
, r0
, mode64
));
2515 addInstr(env
, PPCInstr_Load(8, dst
, am_off0
, mode64
));
2517 add_to_sp( env
, 32 ); // Reset SP
2525 switch (e
->Iex
.Unop
.op
) {
2526 case Iop_ExtractExpD64
: {
2528 HReg fr_dst
= newVRegI(env
);
2529 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
2530 HReg tmp
= newVRegF(env
);
2531 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
2532 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DXEX
, tmp
, fr_src
));
2534 // put the D64 result into a integer register
2535 sub_from_sp( env
, 16 );
2536 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
2537 addInstr(env
, PPCInstr_Load(8, fr_dst
, zero_r1
, env
->mode64
));
2538 add_to_sp( env
, 16 );
2541 case Iop_ExtractExpD128
: {
2542 HReg fr_dst
= newVRegI(env
);
2545 HReg tmp
= newVRegF(env
);
2546 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
2548 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
,
2550 addInstr(env
, PPCInstr_ExtractExpD128(Pfp_DXEXQ
, tmp
,
2553 sub_from_sp( env
, 16 );
2554 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
2555 addInstr(env
, PPCInstr_Load(8, fr_dst
, zero_r1
, env
->mode64
));
2556 add_to_sp( env
, 16 );
2566 /* --------- GET --------- */
2568 if (ty
== Ity_I8
|| ty
== Ity_I16
||
2569 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) {
2570 HReg r_dst
= newVRegI(env
);
2571 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
2572 GuestStatePtr(mode64
) );
2573 addInstr(env
, PPCInstr_Load( toUChar(sizeofIRType(ty
)),
2574 r_dst
, am_addr
, mode64
));
2582 = genGuestArrayOffset( env
, e
->Iex
.GetI
.descr
,
2583 e
->Iex
.GetI
.ix
, e
->Iex
.GetI
.bias
,
2585 HReg r_dst
= newVRegI(env
);
2586 if (mode64
&& ty
== Ity_I64
) {
2587 addInstr(env
, PPCInstr_Load( toUChar(8),
2588 r_dst
, src_am
, mode64
));
2591 if ((!mode64
) && ty
== Ity_I32
) {
2592 addInstr(env
, PPCInstr_Load( toUChar(4),
2593 r_dst
, src_am
, mode64
));
2599 /* --------- CCALL --------- */
2601 vassert(ty
== e
->Iex
.CCall
.retty
); /* well-formedness of IR */
2603 /* be very restrictive for now. Only 32/64-bit ints allowed for
2604 args, and 32 bits or host machine word for return type. */
2605 if (!(ty
== Ity_I32
|| (mode64
&& ty
== Ity_I64
)))
2608 /* Marshal args, do the call, clear stack. */
2610 RetLoc rloc
= mk_RetLoc_INVALID();
2611 doHelperCall( &addToSp
, &rloc
, env
, NULL
/*guard*/,
2612 e
->Iex
.CCall
.cee
, e
->Iex
.CCall
.retty
, e
->Iex
.CCall
.args
,
2614 vassert(is_sane_RetLoc(rloc
));
2615 vassert(rloc
.pri
== RLPri_Int
);
2616 vassert(addToSp
== 0);
2618 /* GPR3 now holds the destination address from Pin_Goto */
2619 HReg r_dst
= newVRegI(env
);
2620 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
2624 /* --------- LITERAL --------- */
2625 /* 32/16/8-bit literals */
2628 HReg r_dst
= newVRegI(env
);
2629 IRConst
* con
= e
->Iex
.Const
.con
;
2631 case Ico_U64
: if (!mode64
) goto irreducible
;
2632 l
= (Long
) con
->Ico
.U64
; break;
2633 case Ico_U32
: l
= (Long
)(Int
) con
->Ico
.U32
; break;
2634 case Ico_U16
: l
= (Long
)(Int
)(Short
)con
->Ico
.U16
; break;
2635 case Ico_U8
: l
= (Long
)(Int
)(Char
)con
->Ico
.U8
; break;
2636 default: vpanic("iselIntExpr_R.const(ppc)");
2638 addInstr(env
, PPCInstr_LI(r_dst
, (ULong
)l
, mode64
));
2642 /* --------- MULTIPLEX --------- */
2643 case Iex_ITE
: { // VFD
2644 if ((ty
== Ity_I8
|| ty
== Ity_I16
||
2645 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) &&
2646 typeOfIRExpr(env
->type_env
,e
->Iex
.ITE
.cond
) == Ity_I1
) {
2647 PPCRI
* r1
= iselWordExpr_RI(env
, e
->Iex
.ITE
.iftrue
, IEndianess
);
2648 HReg r0
= iselWordExpr_R(env
, e
->Iex
.ITE
.iffalse
, IEndianess
);
2649 HReg r_dst
= newVRegI(env
);
2650 addInstr(env
, mk_iMOVds_RR(r_dst
,r0
));
2651 PPCCondCode cc
= iselCondCode(env
, e
->Iex
.ITE
.cond
, IEndianess
);
2652 addInstr(env
, PPCInstr_CMov(cc
, r_dst
, r1
));
2660 } /* switch (e->tag) */
2663 /* We get here if no pattern matched. */
2666 vpanic("iselIntExpr_R(ppc): cannot reduce tree");
2670 /*---------------------------------------------------------*/
2671 /*--- ISEL: Integer expression auxiliaries ---*/
2672 /*---------------------------------------------------------*/
2674 /* --------------------- AMODEs --------------------- */
2676 /* Return an AMode which computes the value of the specified
2677 expression, possibly also adding insns to the code list as a
2678 result. The expression may only be a word-size one.
2681 static Bool
uInt_fits_in_16_bits ( UInt u
)
2683 /* Is u the same as the sign-extend of its lower 16 bits? */
2684 UInt v
= u
& 0xFFFF;
2686 v
= (Int
)(v
<< 16) >> 16; /* sign extend */
2691 static Bool
uLong_fits_in_16_bits ( ULong u
)
2693 /* Is u the same as the sign-extend of its lower 16 bits? */
2694 ULong v
= u
& 0xFFFFULL
;
2696 v
= (Long
)(v
<< 48) >> 48; /* sign extend */
2701 static Bool
uLong_is_4_aligned ( ULong u
)
2703 return toBool((u
& 3ULL) == 0);
2706 static Bool
sane_AMode ( ISelEnv
* env
, PPCAMode
* am
)
2708 Bool mode64
= env
->mode64
;
2711 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2712 somehow, but I think it's OK. */
2713 return toBool( hregClass(am
->Pam
.IR
.base
) == HRcGPR(mode64
) &&
2714 hregIsVirtual(am
->Pam
.IR
.base
) &&
2715 uInt_fits_in_16_bits(am
->Pam
.IR
.index
) );
2717 return toBool( hregClass(am
->Pam
.RR
.base
) == HRcGPR(mode64
) &&
2718 hregIsVirtual(am
->Pam
.RR
.base
) &&
2719 hregClass(am
->Pam
.RR
.index
) == HRcGPR(mode64
) &&
2720 hregIsVirtual(am
->Pam
.RR
.index
) );
2722 vpanic("sane_AMode: unknown ppc amode tag");
2727 PPCAMode
* iselWordExpr_AMode ( ISelEnv
* env
, const IRExpr
* e
, IRType xferTy
,
2728 IREndness IEndianess
)
2730 PPCAMode
* am
= iselWordExpr_AMode_wrk(env
, e
, xferTy
, IEndianess
);
2731 vassert(sane_AMode(env
, am
));
2735 /* DO NOT CALL THIS DIRECTLY ! */
2736 static PPCAMode
* iselWordExpr_AMode_wrk ( ISelEnv
* env
, const IRExpr
* e
,
2737 IRType xferTy
, IREndness IEndianess
)
2739 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2743 /* If the data load/store type is I32 or I64, this amode might
2744 be destined for use in ld/ldu/lwa/st/stu. In which case
2745 insist that if it comes out as an _IR, the immediate must
2746 have its bottom two bits be zero. This does assume that for
2747 any other type (I8/I16/I128/F32/F64/V128) the amode will not
2748 be parked in any such instruction. But that seems a
2749 reasonable assumption. */
2750 Bool aligned4imm
= toBool(xferTy
== Ity_I32
|| xferTy
== Ity_I64
);
2752 vassert(ty
== Ity_I64
);
2754 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2755 if (e
->tag
== Iex_Binop
2756 && e
->Iex
.Binop
.op
== Iop_Add64
2757 && e
->Iex
.Binop
.arg2
->tag
== Iex_Const
2758 && e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->tag
== Ico_U64
2759 && (aligned4imm
? uLong_is_4_aligned(e
->Iex
.Binop
.arg2
2760 ->Iex
.Const
.con
->Ico
.U64
)
2762 && uLong_fits_in_16_bits(e
->Iex
.Binop
.arg2
2763 ->Iex
.Const
.con
->Ico
.U64
)) {
2764 return PPCAMode_IR( (Int
)e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->Ico
.U64
,
2765 iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
,
2769 /* Add64(expr,expr) */
2770 if (e
->tag
== Iex_Binop
2771 && e
->Iex
.Binop
.op
== Iop_Add64
) {
2772 HReg r_base
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
2773 HReg r_idx
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
2774 return PPCAMode_RR( r_idx
, r_base
);
2779 vassert(ty
== Ity_I32
);
2781 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2782 if (e
->tag
== Iex_Binop
2783 && e
->Iex
.Binop
.op
== Iop_Add32
2784 && e
->Iex
.Binop
.arg2
->tag
== Iex_Const
2785 && e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->tag
== Ico_U32
2786 && uInt_fits_in_16_bits(e
->Iex
.Binop
.arg2
2787 ->Iex
.Const
.con
->Ico
.U32
)) {
2788 return PPCAMode_IR( (Int
)e
->Iex
.Binop
.arg2
->Iex
.Const
.con
->Ico
.U32
,
2789 iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
,
2793 /* Add32(expr,expr) */
2794 if (e
->tag
== Iex_Binop
2795 && e
->Iex
.Binop
.op
== Iop_Add32
) {
2796 HReg r_base
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
2797 HReg r_idx
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
2798 return PPCAMode_RR( r_idx
, r_base
);
2803 /* Doesn't match anything in particular. Generate it into
2804 a register and use that. */
2805 return PPCAMode_IR( 0, iselWordExpr_R(env
,e
,IEndianess
) );
2809 /* --------------------- RH --------------------- */
2811 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2812 (reg-or-halfword-immediate). It's important to specify whether the
2813 immediate is to be regarded as signed or not. If yes, this will
2814 never return -32768 as an immediate; this guaranteed that all
2815 signed immediates that are return can have their sign inverted if
2818 static PPCRH
* iselWordExpr_RH ( ISelEnv
* env
, Bool syned
, const IRExpr
* e
,
2819 IREndness IEndianess
)
2821 PPCRH
* ri
= iselWordExpr_RH_wrk(env
, syned
, e
, IEndianess
);
2822 /* sanity checks ... */
2825 vassert(ri
->Prh
.Imm
.syned
== syned
);
2827 vassert(ri
->Prh
.Imm
.imm16
!= 0x8000);
2830 vassert(hregClass(ri
->Prh
.Reg
.reg
) == HRcGPR(env
->mode64
));
2831 vassert(hregIsVirtual(ri
->Prh
.Reg
.reg
));
2834 vpanic("iselIntExpr_RH: unknown ppc RH tag");
2838 /* DO NOT CALL THIS DIRECTLY ! */
2839 static PPCRH
* iselWordExpr_RH_wrk ( ISelEnv
* env
, Bool syned
, const IRExpr
* e
,
2840 IREndness IEndianess
)
2844 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2845 vassert(ty
== Ity_I8
|| ty
== Ity_I16
||
2846 ty
== Ity_I32
|| ((ty
== Ity_I64
) && env
->mode64
));
2848 /* special case: immediate */
2849 if (e
->tag
== Iex_Const
) {
2850 IRConst
* con
= e
->Iex
.Const
.con
;
2851 /* What value are we aiming to generate? */
2853 /* Note: Not sign-extending - we carry 'syned' around */
2854 case Ico_U64
: vassert(env
->mode64
);
2855 u
= con
->Ico
.U64
; break;
2856 case Ico_U32
: u
= 0xFFFFFFFF & con
->Ico
.U32
; break;
2857 case Ico_U16
: u
= 0x0000FFFF & con
->Ico
.U16
; break;
2858 case Ico_U8
: u
= 0x000000FF & con
->Ico
.U8
; break;
2859 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2862 /* Now figure out if it's representable. */
2863 if (!syned
&& u
<= 65535) {
2864 return PPCRH_Imm(False
/*unsigned*/, toUShort(u
& 0xFFFF));
2866 if (syned
&& l
>= -32767 && l
<= 32767) {
2867 return PPCRH_Imm(True
/*signed*/, toUShort(u
& 0xFFFF));
2869 /* no luck; use the Slow Way. */
2872 /* default case: calculate into a register and return that */
2873 return PPCRH_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
2877 /* --------------------- RIs --------------------- */
2879 /* Calculate an expression into an PPCRI operand. As with
2880 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2881 in 64-bit mode, 64 bits. */
2883 static PPCRI
* iselWordExpr_RI ( ISelEnv
* env
, const IRExpr
* e
,
2884 IREndness IEndianess
)
2886 PPCRI
* ri
= iselWordExpr_RI_wrk(env
, e
, IEndianess
);
2887 /* sanity checks ... */
2892 vassert(hregClass(ri
->Pri
.Reg
) == HRcGPR(env
->mode64
));
2893 vassert(hregIsVirtual(ri
->Pri
.Reg
));
2896 vpanic("iselIntExpr_RI: unknown ppc RI tag");
2900 /* DO NOT CALL THIS DIRECTLY ! */
2901 static PPCRI
* iselWordExpr_RI_wrk ( ISelEnv
* env
, const IRExpr
* e
,
2902 IREndness IEndianess
)
2905 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2906 vassert(ty
== Ity_I8
|| ty
== Ity_I16
||
2907 ty
== Ity_I32
|| ((ty
== Ity_I64
) && env
->mode64
));
2909 /* special case: immediate */
2910 if (e
->tag
== Iex_Const
) {
2911 IRConst
* con
= e
->Iex
.Const
.con
;
2913 case Ico_U64
: vassert(env
->mode64
);
2914 l
= (Long
) con
->Ico
.U64
; break;
2915 case Ico_U32
: l
= (Long
)(Int
) con
->Ico
.U32
; break;
2916 case Ico_U16
: l
= (Long
)(Int
)(Short
)con
->Ico
.U16
; break;
2917 case Ico_U8
: l
= (Long
)(Int
)(Char
)con
->Ico
.U8
; break;
2918 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2920 return PPCRI_Imm((ULong
)l
);
2923 /* default case: calculate into a register and return that */
2924 return PPCRI_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
2928 /* --------------------- RH5u --------------------- */
2930 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2931 being an immediate in the range 1 .. 31 inclusive. Used for doing
2932 shift amounts. Only used in 32-bit mode. */
2934 static PPCRH
* iselWordExpr_RH5u ( ISelEnv
* env
, const IRExpr
* e
,
2935 IREndness IEndianess
)
2938 vassert(!env
->mode64
);
2939 ri
= iselWordExpr_RH5u_wrk(env
, e
, IEndianess
);
2940 /* sanity checks ... */
2943 vassert(ri
->Prh
.Imm
.imm16
>= 1 && ri
->Prh
.Imm
.imm16
<= 31);
2944 vassert(!ri
->Prh
.Imm
.syned
);
2947 vassert(hregClass(ri
->Prh
.Reg
.reg
) == HRcGPR(env
->mode64
));
2948 vassert(hregIsVirtual(ri
->Prh
.Reg
.reg
));
2951 vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2955 /* DO NOT CALL THIS DIRECTLY ! */
2956 static PPCRH
* iselWordExpr_RH5u_wrk ( ISelEnv
* env
, const IRExpr
* e
,
2957 IREndness IEndianess
)
2959 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
2960 vassert(ty
== Ity_I8
);
2962 /* special case: immediate */
2963 if (e
->tag
== Iex_Const
2964 && e
->Iex
.Const
.con
->tag
== Ico_U8
2965 && e
->Iex
.Const
.con
->Ico
.U8
>= 1
2966 && e
->Iex
.Const
.con
->Ico
.U8
<= 31) {
2967 return PPCRH_Imm(False
/*unsigned*/, e
->Iex
.Const
.con
->Ico
.U8
);
2970 /* default case: calculate into a register and return that */
2971 return PPCRH_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
2975 /* --------------------- RH6u --------------------- */
2977 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2978 being an immediate in the range 1 .. 63 inclusive. Used for doing
2979 shift amounts. Only used in 64-bit mode. */
2981 static PPCRH
* iselWordExpr_RH6u ( ISelEnv
* env
, const IRExpr
* e
,
2982 IREndness IEndianess
)
2985 vassert(env
->mode64
);
2986 ri
= iselWordExpr_RH6u_wrk(env
, e
, IEndianess
);
2987 /* sanity checks ... */
2990 vassert(ri
->Prh
.Imm
.imm16
>= 1 && ri
->Prh
.Imm
.imm16
<= 63);
2991 vassert(!ri
->Prh
.Imm
.syned
);
2994 vassert(hregClass(ri
->Prh
.Reg
.reg
) == HRcGPR(env
->mode64
));
2995 vassert(hregIsVirtual(ri
->Prh
.Reg
.reg
));
2998 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
3002 /* DO NOT CALL THIS DIRECTLY ! */
3003 static PPCRH
* iselWordExpr_RH6u_wrk ( ISelEnv
* env
, const IRExpr
* e
,
3004 IREndness IEndianess
)
3006 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
3007 vassert(ty
== Ity_I8
);
3009 /* special case: immediate */
3010 if (e
->tag
== Iex_Const
3011 && e
->Iex
.Const
.con
->tag
== Ico_U8
3012 && e
->Iex
.Const
.con
->Ico
.U8
>= 1
3013 && e
->Iex
.Const
.con
->Ico
.U8
<= 63) {
3014 return PPCRH_Imm(False
/*unsigned*/, e
->Iex
.Const
.con
->Ico
.U8
);
3017 /* default case: calculate into a register and return that */
3018 return PPCRH_Reg( iselWordExpr_R ( env
, e
, IEndianess
) );
3022 /* --------------------- CONDCODE --------------------- */
3024 /* Generate code to evaluated a bit-typed expression, returning the
3025 condition code which would correspond when the expression would
3026 notionally have returned 1. */
3028 static PPCCondCode
iselCondCode ( ISelEnv
* env
, const IRExpr
* e
,
3029 IREndness IEndianess
)
3031 /* Uh, there's nothing we can sanity check here, unfortunately. */
3032 return iselCondCode_wrk(env
,e
, IEndianess
);
3035 /* DO NOT CALL THIS DIRECTLY ! */
3036 static PPCCondCode
iselCondCode_wrk ( ISelEnv
* env
, const IRExpr
* e
,
3037 IREndness IEndianess
)
3040 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I1
);
3042 /* Constant 1:Bit */
3043 if (e
->tag
== Iex_Const
&& e
->Iex
.Const
.con
->Ico
.U1
== True
) {
3044 // Make a compare that will always be true:
3045 HReg r_zero
= newVRegI(env
);
3046 addInstr(env
, PPCInstr_LI(r_zero
, 0, env
->mode64
));
3047 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3048 7/*cr*/, r_zero
, PPCRH_Reg(r_zero
)));
3049 return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3053 if (e
->tag
== Iex_Unop
&& e
->Iex
.Unop
.op
== Iop_Not1
) {
3054 /* Generate code for the arg, and negate the test condition */
3055 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3056 cond
.test
= invertCondTest(cond
.test
);
3060 /* --- patterns rooted at: 32to1 or 64to1 --- */
3063 if (e
->tag
== Iex_Unop
&&
3064 (e
->Iex
.Unop
.op
== Iop_32to1
|| e
->Iex
.Unop
.op
== Iop_64to1
)) {
3065 HReg src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3066 HReg tmp
= newVRegI(env
);
3067 /* could do better, probably -- andi. */
3068 addInstr(env
, PPCInstr_Alu(Palu_AND
, tmp
,
3069 src
, PPCRH_Imm(False
,1)));
3070 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3071 7/*cr*/, tmp
, PPCRH_Imm(False
,1)));
3072 return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3075 /* --- patterns rooted at: CmpNEZ8 --- */
3078 /* Note this cloned as CmpNE8(x,0) below. */
3079 /* could do better -- andi. */
3080 if (e
->tag
== Iex_Unop
3081 && e
->Iex
.Unop
.op
== Iop_CmpNEZ8
) {
3082 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3083 HReg tmp
= newVRegI(env
);
3084 addInstr(env
, PPCInstr_Alu(Palu_AND
, tmp
, arg
,
3085 PPCRH_Imm(False
,0xFF)));
3086 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3087 7/*cr*/, tmp
, PPCRH_Imm(False
,0)));
3088 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3091 /* --- patterns rooted at: CmpNEZ32 --- */
3094 if (e
->tag
== Iex_Unop
3095 && e
->Iex
.Unop
.op
== Iop_CmpNEZ32
) {
3096 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3097 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3098 7/*cr*/, r1
, PPCRH_Imm(False
,0)));
3099 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3102 /* --- patterns rooted at: Cmp*32* --- */
3105 if (e
->tag
== Iex_Binop
3106 && (e
->Iex
.Binop
.op
== Iop_CmpEQ32
3107 || e
->Iex
.Binop
.op
== Iop_CmpNE32
3108 || e
->Iex
.Binop
.op
== Iop_CmpLT32S
3109 || e
->Iex
.Binop
.op
== Iop_CmpLT32U
3110 || e
->Iex
.Binop
.op
== Iop_CmpLE32S
3111 || e
->Iex
.Binop
.op
== Iop_CmpLE32U
)) {
3112 Bool syned
= (e
->Iex
.Binop
.op
== Iop_CmpLT32S
||
3113 e
->Iex
.Binop
.op
== Iop_CmpLE32S
);
3114 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3115 PPCRH
* ri2
= iselWordExpr_RH(env
, syned
, e
->Iex
.Binop
.arg2
, IEndianess
);
3116 addInstr(env
, PPCInstr_Cmp(syned
, True
/*32bit cmp*/,
3119 switch (e
->Iex
.Binop
.op
) {
3120 case Iop_CmpEQ32
: return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3121 case Iop_CmpNE32
: return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3122 case Iop_CmpLT32U
: case Iop_CmpLT32S
:
3123 return mk_PPCCondCode( Pct_TRUE
, Pcf_7LT
);
3124 case Iop_CmpLE32U
: case Iop_CmpLE32S
:
3125 return mk_PPCCondCode( Pct_FALSE
, Pcf_7GT
);
3126 default: vpanic("iselCondCode(ppc): CmpXX32");
3130 /* --- patterns rooted at: CmpNEZ64 --- */
3133 if (e
->tag
== Iex_Unop
3134 && e
->Iex
.Unop
.op
== Iop_CmpNEZ64
) {
3137 HReg tmp
= newVRegI(env
);
3138 iselInt64Expr( &hi
, &lo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3139 addInstr(env
, PPCInstr_Alu(Palu_OR
, tmp
, lo
, PPCRH_Reg(hi
)));
3140 addInstr(env
, PPCInstr_Cmp(False
/*sign*/, True
/*32bit cmp*/,
3141 7/*cr*/, tmp
,PPCRH_Imm(False
,0)));
3142 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3144 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3145 addInstr(env
, PPCInstr_Cmp(False
/*sign*/, False
/*64bit cmp*/,
3146 7/*cr*/, r_src
,PPCRH_Imm(False
,0)));
3147 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3151 /* --- patterns rooted at: Cmp*64* --- */
3154 if (e
->tag
== Iex_Binop
3155 && (e
->Iex
.Binop
.op
== Iop_CmpEQ64
3156 || e
->Iex
.Binop
.op
== Iop_CmpNE64
3157 || e
->Iex
.Binop
.op
== Iop_CmpLT64S
3158 || e
->Iex
.Binop
.op
== Iop_CmpLT64U
3159 || e
->Iex
.Binop
.op
== Iop_CmpLE64S
3160 || e
->Iex
.Binop
.op
== Iop_CmpLE64U
)) {
3161 Bool syned
= (e
->Iex
.Binop
.op
== Iop_CmpLT64S
||
3162 e
->Iex
.Binop
.op
== Iop_CmpLE64S
);
3163 HReg r1
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3164 PPCRH
* ri2
= iselWordExpr_RH(env
, syned
, e
->Iex
.Binop
.arg2
, IEndianess
);
3165 vassert(env
->mode64
);
3166 addInstr(env
, PPCInstr_Cmp(syned
, False
/*64bit cmp*/,
3169 switch (e
->Iex
.Binop
.op
) {
3170 case Iop_CmpEQ64
: return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3171 case Iop_CmpNE64
: return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3172 case Iop_CmpLT64U
: return mk_PPCCondCode( Pct_TRUE
, Pcf_7LT
);
3173 case Iop_CmpLE64U
: return mk_PPCCondCode( Pct_FALSE
, Pcf_7GT
);
3174 default: vpanic("iselCondCode(ppc): CmpXX64");
3178 /* --- patterns rooted at: CmpNE8 --- */
3181 /* Note this is a direct copy of CmpNEZ8 above. */
3182 /* could do better -- andi. */
3183 if (e
->tag
== Iex_Binop
3184 && e
->Iex
.Binop
.op
== Iop_CmpNE8
3185 && isZeroU8(e
->Iex
.Binop
.arg2
)) {
3186 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3187 HReg tmp
= newVRegI(env
);
3188 addInstr(env
, PPCInstr_Alu(Palu_AND
, tmp
, arg
,
3189 PPCRH_Imm(False
,0xFF)));
3190 addInstr(env
, PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3191 7/*cr*/, tmp
, PPCRH_Imm(False
,0)));
3192 return mk_PPCCondCode( Pct_FALSE
, Pcf_7EQ
);
3196 if (e
->tag
== Iex_RdTmp
) {
3197 HReg r_src
= lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
3198 HReg src_masked
= newVRegI(env
);
3200 PPCInstr_Alu(Palu_AND
, src_masked
,
3201 r_src
, PPCRH_Imm(False
,1)));
3203 PPCInstr_Cmp(False
/*unsigned*/, True
/*32bit cmp*/,
3204 7/*cr*/, src_masked
, PPCRH_Imm(False
,1)));
3205 return mk_PPCCondCode( Pct_TRUE
, Pcf_7EQ
);
3208 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e
->tag
);
3210 vpanic("iselCondCode(ppc)");
3214 /*---------------------------------------------------------*/
3215 /*--- ISEL: Integer expressions (128 bit) ---*/
3216 /*---------------------------------------------------------*/
3218 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3219 which is returned as the first two parameters. As with
3220 iselWordExpr_R, these may be either real or virtual regs; in any
3221 case they must not be changed by subsequent code emitted by the
3224 static void iselInt128Expr ( HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
,
3225 const IRExpr
* e
, IREndness IEndianess
)
3227 vassert(env
->mode64
);
3228 iselInt128Expr_wrk(rHi
, rLo
, env
, e
, IEndianess
);
3230 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
3232 vassert(hregClass(*rHi
) == HRcGPR(env
->mode64
));
3233 vassert(hregIsVirtual(*rHi
));
3234 vassert(hregClass(*rLo
) == HRcGPR(env
->mode64
));
3235 vassert(hregIsVirtual(*rLo
));
3238 /* DO NOT CALL THIS DIRECTLY ! */
3239 static void iselInt128Expr_wrk ( HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
,
3240 const IRExpr
* e
, IREndness IEndianess
)
3242 Bool mode64
= env
->mode64
;
3245 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I128
);
3247 /* read 128-bit IRTemp */
3248 if (e
->tag
== Iex_RdTmp
) {
3249 lookupIRTempPair( rHi
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
3254 if (e
->tag
== Iex_Get
) {
3255 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
3256 GuestStatePtr(mode64
) );
3257 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
3258 HReg tLo
= newVRegI(env
);
3259 HReg tHi
= newVRegI(env
);
3261 addInstr(env
, PPCInstr_Load( 8, tHi
, am_addr
, mode64
));
3262 addInstr(env
, PPCInstr_Load( 8, tLo
, am_addr4
, mode64
));
3268 /* --------- BINARY ops --------- */
3269 if (e
->tag
== Iex_Binop
) {
3270 switch (e
->Iex
.Binop
.op
) {
3271 /* 64 x 64 -> 128 multiply */
3274 HReg tLo
= newVRegI(env
);
3275 HReg tHi
= newVRegI(env
);
3276 Bool syned
= toBool(e
->Iex
.Binop
.op
== Iop_MullS64
);
3277 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3278 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3279 addInstr(env
, PPCInstr_MulL(False
/*signedness irrelevant*/,
3280 False
/*lo64*/, False
/*64bit mul*/,
3281 tLo
, r_srcL
, r_srcR
));
3282 addInstr(env
, PPCInstr_MulL(syned
,
3283 True
/*hi64*/, False
/*64bit mul*/,
3284 tHi
, r_srcL
, r_srcR
));
3290 /* 64HLto128(e1,e2) */
3292 *rHi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3293 *rLo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3298 } /* if (e->tag == Iex_Binop) */
3301 /* --------- UNARY ops --------- */
3302 if (e
->tag
== Iex_Unop
) {
3303 switch (e
->Iex
.Unop
.op
) {
3307 } /* if (e->tag == Iex_Unop) */
3309 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e
->tag
);
3311 vpanic("iselInt128Expr(ppc64)");
3315 /*---------------------------------------------------------*/
3316 /*--- ISEL: Integer expressions (64 bit) ---*/
3317 /*---------------------------------------------------------*/
3319 /* 32-bit mode ONLY: compute a 128-bit value into a register quad */
3320 static void iselInt128Expr_to_32x4 ( HReg
* rHi
, HReg
* rMedHi
, HReg
* rMedLo
,
3321 HReg
* rLo
, ISelEnv
* env
, const IRExpr
* e
,
3322 IREndness IEndianess
)
3324 vassert(!env
->mode64
);
3325 iselInt128Expr_to_32x4_wrk(rHi
, rMedHi
, rMedLo
, rLo
, env
, e
, IEndianess
);
3327 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
3329 vassert(hregClass(*rHi
) == HRcInt32
);
3330 vassert(hregIsVirtual(*rHi
));
3331 vassert(hregClass(*rMedHi
) == HRcInt32
);
3332 vassert(hregIsVirtual(*rMedHi
));
3333 vassert(hregClass(*rMedLo
) == HRcInt32
);
3334 vassert(hregIsVirtual(*rMedLo
));
3335 vassert(hregClass(*rLo
) == HRcInt32
);
3336 vassert(hregIsVirtual(*rLo
));
3339 static void iselInt128Expr_to_32x4_wrk ( HReg
* rHi
, HReg
* rMedHi
,
3340 HReg
* rMedLo
, HReg
* rLo
,
3341 ISelEnv
* env
, const IRExpr
* e
,
3342 IREndness IEndianess
)
3345 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I128
);
3347 /* read 128-bit IRTemp */
3348 if (e
->tag
== Iex_RdTmp
) {
3349 lookupIRTempQuad( rHi
, rMedHi
, rMedLo
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
3353 if (e
->tag
== Iex_Binop
) {
3355 IROp op_binop
= e
->Iex
.Binop
.op
;
3358 iselInt64Expr(rHi
, rMedHi
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3359 iselInt64Expr(rMedLo
, rLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3362 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3368 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e
->tag
);
3372 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3373 which is returned as the first two parameters. As with
3374 iselIntExpr_R, these may be either real or virtual regs; in any
3375 case they must not be changed by subsequent code emitted by the
3378 static void iselInt64Expr ( HReg
* rHi
, HReg
* rLo
,
3379 ISelEnv
* env
, const IRExpr
* e
,
3380 IREndness IEndianess
)
3382 vassert(!env
->mode64
);
3383 iselInt64Expr_wrk(rHi
, rLo
, env
, e
, IEndianess
);
3385 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
3387 vassert(hregClass(*rHi
) == HRcInt32
);
3388 vassert(hregIsVirtual(*rHi
));
3389 vassert(hregClass(*rLo
) == HRcInt32
);
3390 vassert(hregIsVirtual(*rLo
));
3393 /* DO NOT CALL THIS DIRECTLY ! */
3394 static void iselInt64Expr_wrk ( HReg
* rHi
, HReg
* rLo
,
3395 ISelEnv
* env
, const IRExpr
* e
,
3396 IREndness IEndianess
)
3399 vassert(typeOfIRExpr(env
->type_env
,e
) == Ity_I64
);
3402 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
3403 HReg tLo
= newVRegI(env
);
3404 HReg tHi
= newVRegI(env
);
3405 HReg r_addr
= iselWordExpr_R(env
, e
->Iex
.Load
.addr
, IEndianess
);
3406 vassert(!env
->mode64
);
3407 addInstr(env
, PPCInstr_Load( 4/*byte-load*/,
3408 tHi
, PPCAMode_IR( 0, r_addr
),
3409 False
/*32-bit insn please*/) );
3410 addInstr(env
, PPCInstr_Load( 4/*byte-load*/,
3411 tLo
, PPCAMode_IR( 4, r_addr
),
3412 False
/*32-bit insn please*/) );
3418 /* 64-bit literal */
3419 if (e
->tag
== Iex_Const
) {
3420 ULong w64
= e
->Iex
.Const
.con
->Ico
.U64
;
3421 UInt wHi
= ((UInt
)(w64
>> 32)) & 0xFFFFFFFF;
3422 UInt wLo
= ((UInt
)w64
) & 0xFFFFFFFF;
3423 HReg tLo
= newVRegI(env
);
3424 HReg tHi
= newVRegI(env
);
3425 vassert(e
->Iex
.Const
.con
->tag
== Ico_U64
);
3426 addInstr(env
, PPCInstr_LI(tHi
, (Long
)(Int
)wHi
, False
/*mode32*/));
3427 addInstr(env
, PPCInstr_LI(tLo
, (Long
)(Int
)wLo
, False
/*mode32*/));
3433 /* read 64-bit IRTemp */
3434 if (e
->tag
== Iex_RdTmp
) {
3435 lookupIRTempPair( rHi
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
3440 if (e
->tag
== Iex_Get
) {
3441 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
3442 GuestStatePtr(False
/*mode32*/) );
3443 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
3444 HReg tLo
= newVRegI(env
);
3445 HReg tHi
= newVRegI(env
);
3446 addInstr(env
, PPCInstr_Load( 4, tHi
, am_addr
, False
/*mode32*/ ));
3447 addInstr(env
, PPCInstr_Load( 4, tLo
, am_addr4
, False
/*mode32*/ ));
3453 /* --------- CCALL --------- */
3454 if(e
->tag
== Iex_CCall
) {
3455 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
3456 Bool mode64
= env
->mode64
;
3458 vassert(ty
== e
->Iex
.CCall
.retty
); /* well-formedness of IR */
3460 /* be very restrictive for now. Only 32-bit ints allowed for
3461 args, and 32 bits or host machine word for return type. */
3462 vassert(!(ty
== Ity_I32
|| (mode64
&& ty
== Ity_I64
)));
3464 /* Marshal args, do the call, clear stack. */
3466 RetLoc rloc
= mk_RetLoc_INVALID();
3467 doHelperCall( &addToSp
, &rloc
, env
, NULL
/*guard*/,
3468 e
->Iex
.CCall
.cee
, e
->Iex
.CCall
.retty
, e
->Iex
.CCall
.args
,
3470 vassert(is_sane_RetLoc(rloc
));
3472 vassert(rloc
.pri
== RLPri_2Int
);
3473 vassert(addToSp
== 0);
3475 /* GPR3 now holds the destination address from Pin_Goto */
3476 HReg r_dst
= newVRegI(env
);
3477 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
3484 if (e
->tag
== Iex_ITE
) { // VFD
3485 HReg e0Lo
, e0Hi
, eXLo
, eXHi
;
3486 iselInt64Expr(&eXHi
, &eXLo
, env
, e
->Iex
.ITE
.iftrue
, IEndianess
);
3487 iselInt64Expr(&e0Hi
, &e0Lo
, env
, e
->Iex
.ITE
.iffalse
, IEndianess
);
3488 HReg tLo
= newVRegI(env
);
3489 HReg tHi
= newVRegI(env
);
3490 addInstr(env
, mk_iMOVds_RR(tHi
,e0Hi
));
3491 addInstr(env
, mk_iMOVds_RR(tLo
,e0Lo
));
3492 PPCCondCode cc
= iselCondCode(env
, e
->Iex
.ITE
.cond
, IEndianess
);
3493 addInstr(env
, PPCInstr_CMov(cc
,tHi
,PPCRI_Reg(eXHi
)));
3494 addInstr(env
, PPCInstr_CMov(cc
,tLo
,PPCRI_Reg(eXLo
)));
3500 /* --------- BINARY ops --------- */
3501 if (e
->tag
== Iex_Binop
) {
3502 IROp op_binop
= e
->Iex
.Binop
.op
;
3504 /* 32 x 32 -> 64 multiply */
3507 HReg tLo
= newVRegI(env
);
3508 HReg tHi
= newVRegI(env
);
3509 Bool syned
= toBool(op_binop
== Iop_MullS32
);
3510 HReg r_srcL
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
,
3512 HReg r_srcR
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
,
3514 addInstr(env
, PPCInstr_MulL(False
/*signedness irrelevant*/,
3515 False
/*lo32*/, True
/*32bit mul*/,
3516 tLo
, r_srcL
, r_srcR
));
3517 addInstr(env
, PPCInstr_MulL(syned
,
3518 True
/*hi32*/, True
/*32bit mul*/,
3519 tHi
, r_srcL
, r_srcR
));
3525 /* Or64/And64/Xor64 */
3529 HReg xLo
, xHi
, yLo
, yHi
;
3530 HReg tLo
= newVRegI(env
);
3531 HReg tHi
= newVRegI(env
);
3532 PPCAluOp op
= (op_binop
== Iop_Or64
) ? Palu_OR
:
3533 (op_binop
== Iop_And64
) ? Palu_AND
: Palu_XOR
;
3534 iselInt64Expr(&xHi
, &xLo
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3535 iselInt64Expr(&yHi
, &yLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3536 addInstr(env
, PPCInstr_Alu(op
, tHi
, xHi
, PPCRH_Reg(yHi
)));
3537 addInstr(env
, PPCInstr_Alu(op
, tLo
, xLo
, PPCRH_Reg(yLo
)));
3545 HReg xLo
, xHi
, yLo
, yHi
;
3546 HReg tLo
= newVRegI(env
);
3547 HReg tHi
= newVRegI(env
);
3548 iselInt64Expr(&xHi
, &xLo
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3549 iselInt64Expr(&yHi
, &yLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3550 addInstr(env
, PPCInstr_AddSubC( True
/*add*/, True
/*set carry*/,
3552 addInstr(env
, PPCInstr_AddSubC( True
/*add*/, False
/*read carry*/,
3559 /* 32HLto64(e1,e2) */
3561 *rHi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3562 *rLo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3566 case Iop_F64toI64S
: case Iop_F64toI64U
: {
3567 HReg tLo
= newVRegI(env
);
3568 HReg tHi
= newVRegI(env
);
3569 HReg r1
= StackFramePtr(env
->mode64
);
3570 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
3571 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
3572 HReg fsrc
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
,
3574 HReg ftmp
= newVRegF(env
);
3576 vassert(!env
->mode64
);
3577 /* Set host rounding mode */
3578 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3580 sub_from_sp( env
, 16 );
3581 addInstr(env
, PPCInstr_FpCftI(False
/*F->I*/, False
/*int64*/,
3582 (op_binop
== Iop_F64toI64S
) ? True
: False
,
3584 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
3585 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3586 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3587 add_to_sp( env
, 16 );
3589 ///* Restore default FPU rounding. */
3590 //set_FPU_rounding_default( env );
3595 case Iop_D64toI64S
: {
3596 HReg tLo
= newVRegI(env
);
3597 HReg tHi
= newVRegI(env
);
3598 HReg r1
= StackFramePtr(env
->mode64
);
3599 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
3600 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
3601 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
3602 HReg tmp
= newVRegF(env
);
3604 vassert(!env
->mode64
);
3605 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3606 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DCTFIX
, tmp
, fr_src
));
3608 sub_from_sp( env
, 16 );
3609 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
3610 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3611 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3612 add_to_sp( env
, 16 );
3617 case Iop_D128toI64S
: {
3618 PPCFpOp fpop
= Pfp_DCTFIXQ
;
3619 HReg r_srcHi
= newVRegF(env
);
3620 HReg r_srcLo
= newVRegF(env
);
3621 HReg tLo
= newVRegI(env
);
3622 HReg tHi
= newVRegI(env
);
3623 HReg ftmp
= newVRegF(env
);
3624 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
3625 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
3627 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
3628 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
3630 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, ftmp
, r_srcHi
, r_srcLo
));
3632 // put the D64 result into an integer register pair
3633 sub_from_sp( env
, 16 );
3634 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, ftmp
, zero_r1
));
3635 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3636 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3637 add_to_sp( env
, 16 );
3645 } /* if (e->tag == Iex_Binop) */
3648 /* --------- UNARY ops --------- */
3649 if (e
->tag
== Iex_Unop
) {
3650 switch (e
->Iex
.Unop
.op
) {
3653 case Iop_CmpwNEZ64
: {
3655 HReg tmp1
= newVRegI(env
);
3656 HReg tmp2
= newVRegI(env
);
3657 iselInt64Expr(&argHi
, &argLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3658 /* tmp1 = argHi | argLo */
3659 addInstr(env
, PPCInstr_Alu(Palu_OR
, tmp1
, argHi
, PPCRH_Reg(argLo
)));
3660 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3661 addInstr(env
, PPCInstr_Unary(Pun_NEG
,tmp2
,tmp1
));
3662 addInstr(env
, PPCInstr_Alu(Palu_OR
, tmp2
, tmp2
, PPCRH_Reg(tmp1
)));
3663 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
3664 tmp2
, tmp2
, PPCRH_Imm(False
, 31)));
3666 *rLo
= tmp2
; /* yes, really tmp2 */
3673 HReg zero32
= newVRegI(env
);
3674 HReg resHi
= newVRegI(env
);
3675 HReg resLo
= newVRegI(env
);
3676 iselInt64Expr(&argHi
, &argLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3677 vassert(env
->mode64
== False
);
3678 addInstr(env
, PPCInstr_LI(zero32
, 0, env
->mode64
));
3679 /* resHi:resLo = - argHi:argLo */
3680 addInstr(env
, PPCInstr_AddSubC( False
/*sub*/, True
/*set carry*/,
3681 resLo
, zero32
, argLo
));
3682 addInstr(env
, PPCInstr_AddSubC( False
/*sub*/, False
/*read carry*/,
3683 resHi
, zero32
, argHi
));
3684 /* resHi:resLo |= srcHi:srcLo */
3685 addInstr(env
, PPCInstr_Alu(Palu_OR
, resLo
, resLo
, PPCRH_Reg(argLo
)));
3686 addInstr(env
, PPCInstr_Alu(Palu_OR
, resHi
, resHi
, PPCRH_Reg(argHi
)));
3694 HReg tHi
= newVRegI(env
);
3695 HReg src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3696 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
3697 tHi
, src
, PPCRH_Imm(False
,31)));
3702 case Iop_ExtractExpD64
: {
3703 HReg tmp
= newVRegF(env
);
3704 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3705 HReg tLo
= newVRegI(env
);
3706 HReg tHi
= newVRegI(env
);
3707 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
3708 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
3710 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DXEX
, tmp
, fr_src
));
3712 // put the D64 result into a integer register pair
3713 sub_from_sp( env
, 16 );
3714 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
3715 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3716 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3717 add_to_sp( env
, 16 );
3722 case Iop_ExtractExpD128
: {
3725 HReg tmp
= newVRegF(env
);
3726 HReg tLo
= newVRegI(env
);
3727 HReg tHi
= newVRegI(env
);
3728 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
3729 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
3731 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3732 addInstr(env
, PPCInstr_ExtractExpD128(Pfp_DXEXQ
, tmp
,
3735 // put the D64 result into a integer register pair
3736 sub_from_sp( env
, 16 );
3737 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, tmp
, zero_r1
));
3738 addInstr(env
, PPCInstr_Load(4, tHi
, zero_r1
, False
/*mode32*/));
3739 addInstr(env
, PPCInstr_Load(4, tLo
, four_r1
, False
/*mode32*/));
3740 add_to_sp( env
, 16 );
3748 HReg tHi
= newVRegI(env
);
3749 HReg tLo
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3750 addInstr(env
, PPCInstr_LI(tHi
, 0, False
/*mode32*/));
3757 /* Narrow, return the low 64-bit half as a 32-bit
3759 HReg r_Hi
= INVALID_HREG
;
3760 HReg r_MedHi
= INVALID_HREG
;
3761 HReg r_MedLo
= INVALID_HREG
;
3762 HReg r_Lo
= INVALID_HREG
;
3764 iselInt128Expr_to_32x4(&r_Hi
, &r_MedHi
, &r_MedLo
, &r_Lo
,
3765 env
, e
->Iex
.Unop
.arg
, IEndianess
);
3771 case Iop_128HIto64
: {
3772 /* Narrow, return the high 64-bit half as a 32-bit
3774 HReg r_Hi
= INVALID_HREG
;
3775 HReg r_MedHi
= INVALID_HREG
;
3776 HReg r_MedLo
= INVALID_HREG
;
3777 HReg r_Lo
= INVALID_HREG
;
3779 iselInt128Expr_to_32x4(&r_Hi
, &r_MedHi
, &r_MedLo
, &r_Lo
,
3780 env
, e
->Iex
.Unop
.arg
, IEndianess
);
3787 case Iop_V128HIto64
:
3788 case Iop_V128to64
: {
3790 Int off
= e
->Iex
.Unop
.op
==Iop_V128HIto64
? 0 : 8;
3791 HReg tLo
= newVRegI(env
);
3792 HReg tHi
= newVRegI(env
);
3793 HReg vec
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3794 PPCAMode
*am_off0
, *am_offLO
, *am_offHI
;
3795 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
3797 // get a quadword aligned address within our stack space
3798 r_aligned16
= get_sp_aligned16( env
);
3799 am_off0
= PPCAMode_IR( 0, r_aligned16
);
3800 am_offHI
= PPCAMode_IR( off
, r_aligned16
);
3801 am_offLO
= PPCAMode_IR( off
+4, r_aligned16
);
3805 PPCInstr_AvLdSt( False
/*store*/, 16, vec
, am_off0
));
3807 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3809 PPCInstr_Load( 4, tHi
, am_offHI
, False
/*mode32*/ ));
3811 PPCInstr_Load( 4, tLo
, am_offLO
, False
/*mode32*/ ));
3813 add_to_sp( env
, 32 ); // Reset SP
3819 /* could do better than this, but for now ... */
3821 HReg tLo
= newVRegI(env
);
3822 HReg tHi
= newVRegI(env
);
3823 PPCCondCode cond
= iselCondCode(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3824 addInstr(env
, PPCInstr_Set(cond
,tLo
));
3825 addInstr(env
, PPCInstr_Shft(Pshft_SHL
, True
/*32bit shift*/,
3826 tLo
, tLo
, PPCRH_Imm(False
,31)));
3827 addInstr(env
, PPCInstr_Shft(Pshft_SAR
, True
/*32bit shift*/,
3828 tLo
, tLo
, PPCRH_Imm(False
,31)));
3829 addInstr(env
, mk_iMOVds_RR(tHi
, tLo
));
3837 HReg tmpLo
= newVRegI(env
);
3838 HReg tmpHi
= newVRegI(env
);
3839 iselInt64Expr(&xHi
, &xLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3840 addInstr(env
, PPCInstr_Unary(Pun_NOT
,tmpLo
,xLo
));
3841 addInstr(env
, PPCInstr_Unary(Pun_NOT
,tmpHi
,xHi
));
3847 /* ReinterpF64asI64(e) */
3848 /* Given an IEEE754 double, produce an I64 with the same bit
3850 case Iop_ReinterpF64asI64
: {
3851 PPCAMode
*am_addr0
, *am_addr1
;
3852 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3853 HReg r_dstLo
= newVRegI(env
);
3854 HReg r_dstHi
= newVRegI(env
);
3856 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
3857 am_addr0
= PPCAMode_IR( 0, StackFramePtr(False
/*mode32*/) );
3858 am_addr1
= PPCAMode_IR( 4, StackFramePtr(False
/*mode32*/) );
3861 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
3862 fr_src
, am_addr0
));
3864 // load hi,lo as Ity_I32's
3865 addInstr(env
, PPCInstr_Load( 4, r_dstHi
,
3866 am_addr0
, False
/*mode32*/ ));
3867 addInstr(env
, PPCInstr_Load( 4, r_dstLo
,
3868 am_addr1
, False
/*mode32*/ ));
3872 add_to_sp( env
, 16 ); // Reset SP
3876 case Iop_ReinterpD64asI64
: {
3877 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
3878 PPCAMode
*am_addr0
, *am_addr1
;
3879 HReg r_dstLo
= newVRegI(env
);
3880 HReg r_dstHi
= newVRegI(env
);
3883 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
3884 am_addr0
= PPCAMode_IR( 0, StackFramePtr(False
/*mode32*/) );
3885 am_addr1
= PPCAMode_IR( 4, StackFramePtr(False
/*mode32*/) );
3888 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
3889 fr_src
, am_addr0
));
3891 // load hi,lo as Ity_I32's
3892 addInstr(env
, PPCInstr_Load( 4, r_dstHi
,
3893 am_addr0
, False
/*mode32*/ ));
3894 addInstr(env
, PPCInstr_Load( 4, r_dstLo
,
3895 am_addr1
, False
/*mode32*/ ));
3899 add_to_sp( env
, 16 ); // Reset SP
3904 case Iop_BCDtoDPB
: {
3909 HReg tLo
= newVRegI(env
);
3910 HReg tHi
= newVRegI(env
);
3913 Bool mode64
= env
->mode64
;
3915 argregs
[0] = hregPPC_GPR3(mode64
);
3916 argregs
[1] = hregPPC_GPR4(mode64
);
3921 iselInt64Expr( &tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3923 argiregs
|= ( 1 << (argreg
+3 ) );
3924 addInstr( env
, mk_iMOVds_RR( argregs
[argreg
++], tmpHi
) );
3926 argiregs
|= ( 1 << (argreg
+3 ) );
3927 addInstr( env
, mk_iMOVds_RR( argregs
[argreg
], tmpLo
) );
3929 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
3931 if (IEndianess
== Iend_LE
) {
3932 addInstr( env
, PPCInstr_Call( cc
, (Addr
)h_calc_BCDtoDPB
,
3934 mk_RetLoc_simple(RLPri_2Int
) ) );
3937 target
= mode64
? (Addr
)h_calc_BCDtoDPB
:
3938 toUInt( (Addr
)h_calc_BCDtoDPB
);
3939 addInstr( env
, PPCInstr_Call( cc
, target
,
3941 mk_RetLoc_simple(RLPri_2Int
) ) );
3944 addInstr( env
, mk_iMOVds_RR( tHi
, argregs
[argreg
-1] ) );
3945 addInstr( env
, mk_iMOVds_RR( tLo
, argregs
[argreg
] ) );
3952 case Iop_DPBtoBCD
: {
3957 HReg tLo
= newVRegI(env
);
3958 HReg tHi
= newVRegI(env
);
3961 Bool mode64
= env
->mode64
;
3963 argregs
[0] = hregPPC_GPR3(mode64
);
3964 argregs
[1] = hregPPC_GPR4(mode64
);
3969 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
, IEndianess
);
3971 argiregs
|= (1 << (argreg
+3));
3972 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
++], tmpHi
));
3974 argiregs
|= (1 << (argreg
+3));
3975 addInstr(env
, mk_iMOVds_RR( argregs
[argreg
], tmpLo
));
3977 cc
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
3979 if (IEndianess
== Iend_LE
) {
3980 addInstr(env
, PPCInstr_Call( cc
, (Addr
)h_calc_DPBtoBCD
,
3982 mk_RetLoc_simple(RLPri_2Int
) ) );
3985 target
= mode64
? (Addr
)h_calc_DPBtoBCD
:
3986 toUInt( (Addr
)h_calc_DPBtoBCD
);
3987 addInstr(env
, PPCInstr_Call( cc
, target
, argiregs
,
3988 mk_RetLoc_simple(RLPri_2Int
) ) );
3991 addInstr(env
, mk_iMOVds_RR(tHi
, argregs
[argreg
-1]));
3992 addInstr(env
, mk_iMOVds_RR(tLo
, argregs
[argreg
]));
4002 } /* if (e->tag == Iex_Unop) */
4004 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e
->tag
);
4006 vpanic("iselInt64Expr(ppc)");
4010 /*---------------------------------------------------------*/
4011 /*--- ISEL: Floating point expressions (32 bit) ---*/
4012 /*---------------------------------------------------------*/
4014 /* Nothing interesting here; really just wrappers for
4017 static HReg
iselFltExpr ( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4019 HReg r
= iselFltExpr_wrk( env
, e
, IEndianess
);
4021 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
4023 vassert(hregClass(r
) == HRcFlt64
); /* yes, really Flt64 */
4024 vassert(hregIsVirtual(r
));
4028 /* DO NOT CALL THIS DIRECTLY */
4029 static HReg
iselFltExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
4030 IREndness IEndianess
)
4032 Bool mode64
= env
->mode64
;
4034 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
4035 vassert(ty
== Ity_F32
);
4037 if (e
->tag
== Iex_RdTmp
) {
4038 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
4041 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4043 HReg r_dst
= newVRegF(env
);
4044 vassert(e
->Iex
.Load
.ty
== Ity_F32
);
4045 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_F32
/*xfer*/,
4047 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 4, r_dst
, am_addr
));
4051 if (e
->tag
== Iex_Get
) {
4052 HReg r_dst
= newVRegF(env
);
4053 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4054 GuestStatePtr(env
->mode64
) );
4055 addInstr(env
, PPCInstr_FpLdSt( True
/*load*/, 4, r_dst
, am_addr
));
4059 if (e
->tag
== Iex_Unop
&& e
->Iex
.Unop
.op
== Iop_TruncF64asF32
) {
4060 /* This is quite subtle. The only way to do the relevant
4061 truncation is to do a single-precision store and then a
4062 double precision load to get it back into a register. The
4063 problem is, if the data is then written to memory a second
4066 STbe(...) = TruncF64asF32(...)
4068 then will the second truncation further alter the value? The
4069 answer is no: flds (as generated here) followed by fsts
4070 (generated for the STbe) is the identity function on 32-bit
4071 floats, so we are safe.
4073 Another upshot of this is that if iselStmt can see the
4076 STbe(...) = TruncF64asF32(arg)
4078 then it can short circuit having to deal with TruncF64asF32
4079 individually; instead just compute arg into a 64-bit FP
4080 register and do 'fsts' (since that itself does the
4083 We generate pretty poor code here (should be ok both for
4084 32-bit and 64-bit mode); but it is expected that for the most
4085 part the latter optimisation will apply and hence this code
4086 will not often be used.
4088 HReg fsrc
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4089 HReg fdst
= newVRegF(env
);
4090 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4092 sub_from_sp( env
, 16 );
4093 // store as F32, hence truncating
4094 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 4,
4096 // and reload. Good huh?! (sigh)
4097 addInstr(env
, PPCInstr_FpLdSt( True
/*load*/, 4,
4099 add_to_sp( env
, 16 );
4103 if (e
->tag
== Iex_Binop
&& e
->Iex
.Binop
.op
== Iop_I64UtoF32
) {
4105 HReg fdst
= newVRegF(env
);
4106 HReg isrc
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4107 HReg r1
= StackFramePtr(env
->mode64
);
4108 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4110 /* Set host rounding mode */
4111 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4113 sub_from_sp( env
, 16 );
4115 addInstr(env
, PPCInstr_Store(8, zero_r1
, isrc
, True
/*mode64*/));
4116 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4117 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4121 add_to_sp( env
, 16 );
4123 ///* Restore default FPU rounding. */
4124 //set_FPU_rounding_default( env );
4128 HReg fdst
= newVRegF(env
);
4129 HReg isrcHi
, isrcLo
;
4130 HReg r1
= StackFramePtr(env
->mode64
);
4131 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4132 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
4134 iselInt64Expr(&isrcHi
, &isrcLo
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4136 /* Set host rounding mode */
4137 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4139 sub_from_sp( env
, 16 );
4141 addInstr(env
, PPCInstr_Store(4, zero_r1
, isrcHi
, False
/*mode32*/));
4142 addInstr(env
, PPCInstr_Store(4, four_r1
, isrcLo
, False
/*mode32*/));
4143 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4144 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4148 add_to_sp( env
, 16 );
4150 ///* Restore default FPU rounding. */
4151 //set_FPU_rounding_default( env );
4157 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e
->tag
);
4159 vpanic("iselFltExpr_wrk(ppc)");
4163 /*---------------------------------------------------------*/
4164 /*--- ISEL: Floating point expressions (64 bit) ---*/
4165 /*---------------------------------------------------------*/
4167 /* Compute a 64-bit floating point value into a register, the identity
4168 of which is returned. As with iselIntExpr_R, the reg may be either
4169 real or virtual; in any case it must not be changed by subsequent
4170 code emitted by the caller. */
4172 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
4174 Type S (1 bit) E (11 bits) F (52 bits)
4175 ---- --------- ----------- -----------
4176 signalling NaN u 2047 (max) .0uuuuu---u
4179 quiet NaN u 2047 (max) .1uuuuu---u
4181 negative infinity 1 2047 (max) .000000---0
4183 positive infinity 0 2047 (max) .000000---0
4185 negative zero 1 0 .000000---0
4187 positive zero 0 0 .000000---0
4190 static HReg
iselDblExpr ( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4192 HReg r
= iselDblExpr_wrk( env
, e
, IEndianess
);
4194 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
4196 vassert(hregClass(r
) == HRcFlt64
);
4197 vassert(hregIsVirtual(r
));
4201 /* DO NOT CALL THIS DIRECTLY */
4202 static HReg
iselDblExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
4203 IREndness IEndianess
)
4205 Bool mode64
= env
->mode64
;
4206 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
4208 vassert(ty
== Ity_F64
);
4210 if (e
->tag
== Iex_RdTmp
) {
4211 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
4214 /* --------- LITERAL --------- */
4215 if (e
->tag
== Iex_Const
) {
4216 union { UInt u32x2
[2]; ULong u64
; Double f64
; } u
;
4217 vassert(sizeof(u
) == 8);
4218 vassert(sizeof(u
.u64
) == 8);
4219 vassert(sizeof(u
.f64
) == 8);
4220 vassert(sizeof(u
.u32x2
) == 8);
4222 if (e
->Iex
.Const
.con
->tag
== Ico_F64
) {
4223 u
.f64
= e
->Iex
.Const
.con
->Ico
.F64
;
4225 else if (e
->Iex
.Const
.con
->tag
== Ico_F64i
) {
4226 u
.u64
= e
->Iex
.Const
.con
->Ico
.F64i
;
4229 vpanic("iselDblExpr(ppc): const");
4232 HReg r_srcHi
= newVRegI(env
);
4233 HReg r_srcLo
= newVRegI(env
);
4234 addInstr(env
, PPCInstr_LI(r_srcHi
, u
.u32x2
[0], mode64
));
4235 addInstr(env
, PPCInstr_LI(r_srcLo
, u
.u32x2
[1], mode64
));
4236 return mk_LoadRR32toFPR( env
, r_srcHi
, r_srcLo
);
4238 HReg r_src
= newVRegI(env
);
4239 addInstr(env
, PPCInstr_LI(r_src
, u
.u64
, mode64
));
4240 return mk_LoadR64toFPR( env
, r_src
); // 1*I64 -> F64
4244 /* --------- LOAD --------- */
4245 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4246 HReg r_dst
= newVRegF(env
);
4248 vassert(e
->Iex
.Load
.ty
== Ity_F64
);
4249 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_F64
/*xfer*/,
4251 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dst
, am_addr
));
4255 /* --------- GET --------- */
4256 if (e
->tag
== Iex_Get
) {
4257 HReg r_dst
= newVRegF(env
);
4258 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4259 GuestStatePtr(mode64
) );
4260 addInstr(env
, PPCInstr_FpLdSt( True
/*load*/, 8, r_dst
, am_addr
));
4264 /* --------- OPS --------- */
4265 if (e
->tag
== Iex_Qop
) {
4266 PPCFpOp fpop
= Pfp_INVALID
;
4267 switch (e
->Iex
.Qop
.details
->op
) {
4268 case Iop_MAddF64
: fpop
= Pfp_MADDD
; break;
4269 case Iop_MAddF64r32
: fpop
= Pfp_MADDS
; break;
4270 case Iop_MSubF64
: fpop
= Pfp_MSUBD
; break;
4271 case Iop_MSubF64r32
: fpop
= Pfp_MSUBS
; break;
4274 if (fpop
!= Pfp_INVALID
) {
4275 HReg r_dst
= newVRegF(env
);
4276 HReg r_srcML
= iselDblExpr(env
, e
->Iex
.Qop
.details
->arg2
,
4278 HReg r_srcMR
= iselDblExpr(env
, e
->Iex
.Qop
.details
->arg3
,
4280 HReg r_srcAcc
= iselDblExpr(env
, e
->Iex
.Qop
.details
->arg4
,
4282 set_FPU_rounding_mode( env
, e
->Iex
.Qop
.details
->arg1
, IEndianess
);
4283 addInstr(env
, PPCInstr_FpMulAcc(fpop
, r_dst
,
4284 r_srcML
, r_srcMR
, r_srcAcc
));
4289 if (e
->tag
== Iex_Triop
) {
4290 IRTriop
*triop
= e
->Iex
.Triop
.details
;
4291 PPCFpOp fpop
= Pfp_INVALID
;
4292 switch (triop
->op
) {
4293 case Iop_AddF64
: fpop
= Pfp_ADDD
; break;
4294 case Iop_SubF64
: fpop
= Pfp_SUBD
; break;
4295 case Iop_MulF64
: fpop
= Pfp_MULD
; break;
4296 case Iop_DivF64
: fpop
= Pfp_DIVD
; break;
4297 case Iop_AddF64r32
: fpop
= Pfp_ADDS
; break;
4298 case Iop_SubF64r32
: fpop
= Pfp_SUBS
; break;
4299 case Iop_MulF64r32
: fpop
= Pfp_MULS
; break;
4300 case Iop_DivF64r32
: fpop
= Pfp_DIVS
; break;
4303 if (fpop
!= Pfp_INVALID
) {
4304 HReg r_dst
= newVRegF(env
);
4305 HReg r_srcL
= iselDblExpr(env
, triop
->arg2
, IEndianess
);
4306 HReg r_srcR
= iselDblExpr(env
, triop
->arg3
, IEndianess
);
4307 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4308 addInstr(env
, PPCInstr_FpBinary(fpop
, r_dst
, r_srcL
, r_srcR
));
4313 if (e
->tag
== Iex_Binop
) {
4314 PPCFpOp fpop
= Pfp_INVALID
;
4315 switch (e
->Iex
.Binop
.op
) {
4316 case Iop_SqrtF64
: fpop
= Pfp_SQRT
; break;
4319 if (fpop
== Pfp_SQRT
) {
4320 HReg fr_dst
= newVRegF(env
);
4321 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4322 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4323 addInstr(env
, PPCInstr_FpUnary(fpop
, fr_dst
, fr_src
));
4328 if (e
->tag
== Iex_Binop
) {
4330 if (e
->Iex
.Binop
.op
== Iop_F128toF64
) {
4331 HReg fr_dst
= newVRegF(env
);
4332 HReg fr_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4333 HReg tmp
= newVRegV(env
);
4334 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4335 PPCAMode
* eight_r1
= PPCAMode_IR( 8, StackFramePtr(env
->mode64
) );
4336 PPCFpOp fpop
= Pfp_INVALID
;
4338 if (FPU_rounding_mode_isOdd(e
->Iex
.Binop
.arg1
)) {
4339 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4340 fpop
= Pfp_FPQTODRNDODD
;
4342 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4346 addInstr(env
, PPCInstr_Fp128Unary(fpop
, tmp
, fr_src
));
4348 /* result is in a 128-bit vector register, move to 64-bit reg to
4349 * match the Iop specification. The result will get moved back
4350 * to a 128-bit register and stored once the value is returned.
4352 sub_from_sp( env
, 16 );
4353 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, tmp
, zero_r1
));
4354 if (IEndianess
== Iend_LE
)
4355 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_dst
, eight_r1
));
4357 /* High 64-bits stored at lower address */
4358 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_dst
, zero_r1
));
4360 add_to_sp( env
, 16 );
4365 if (e
->Iex
.Binop
.op
== Iop_RoundF64toF32
) {
4366 HReg r_dst
= newVRegF(env
);
4367 HReg r_src
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4368 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4369 addInstr(env
, PPCInstr_FpRSP(r_dst
, r_src
));
4370 //set_FPU_rounding_default( env );
4374 if (e
->Iex
.Binop
.op
== Iop_I64StoF64
|| e
->Iex
.Binop
.op
== Iop_I64UtoF64
) {
4376 HReg fdst
= newVRegF(env
);
4377 HReg isrc
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4378 HReg r1
= StackFramePtr(env
->mode64
);
4379 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4381 /* Set host rounding mode */
4382 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4384 sub_from_sp( env
, 16 );
4386 addInstr(env
, PPCInstr_Store(8, zero_r1
, isrc
, True
/*mode64*/));
4387 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4388 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4389 e
->Iex
.Binop
.op
== Iop_I64StoF64
,
4390 True
/*fdst is 64 bit*/,
4393 add_to_sp( env
, 16 );
4395 ///* Restore default FPU rounding. */
4396 //set_FPU_rounding_default( env );
4400 HReg fdst
= newVRegF(env
);
4401 HReg isrcHi
, isrcLo
;
4402 HReg r1
= StackFramePtr(env
->mode64
);
4403 PPCAMode
* zero_r1
= PPCAMode_IR( 0, r1
);
4404 PPCAMode
* four_r1
= PPCAMode_IR( 4, r1
);
4406 iselInt64Expr(&isrcHi
, &isrcLo
, env
, e
->Iex
.Binop
.arg2
,
4409 /* Set host rounding mode */
4410 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4412 sub_from_sp( env
, 16 );
4414 addInstr(env
, PPCInstr_Store(4, zero_r1
, isrcHi
, False
/*mode32*/));
4415 addInstr(env
, PPCInstr_Store(4, four_r1
, isrcLo
, False
/*mode32*/));
4416 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fdst
, zero_r1
));
4417 addInstr(env
, PPCInstr_FpCftI(True
/*I->F*/, False
/*int64*/,
4418 e
->Iex
.Binop
.op
== Iop_I64StoF64
,
4419 True
/*fdst is 64 bit*/,
4422 add_to_sp( env
, 16 );
4424 ///* Restore default FPU rounding. */
4425 //set_FPU_rounding_default( env );
4432 if (e
->tag
== Iex_Unop
) {
4433 PPCFpOp fpop
= Pfp_INVALID
;
4434 switch (e
->Iex
.Unop
.op
) {
4435 case Iop_NegF64
: fpop
= Pfp_NEG
; break;
4436 case Iop_AbsF64
: fpop
= Pfp_ABS
; break;
4437 case Iop_RSqrtEst5GoodF64
: fpop
= Pfp_RSQRTE
; break;
4438 case Iop_RoundF64toF64_NegINF
: fpop
= Pfp_FRIM
; break;
4439 case Iop_RoundF64toF64_PosINF
: fpop
= Pfp_FRIP
; break;
4440 case Iop_RoundF64toF64_NEAREST
: fpop
= Pfp_FRIN
; break;
4441 case Iop_RoundF64toF64_ZERO
: fpop
= Pfp_FRIZ
; break;
4444 if (fpop
!= Pfp_INVALID
) {
4445 HReg fr_dst
= newVRegF(env
);
4446 HReg fr_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4447 addInstr(env
, PPCInstr_FpUnary(fpop
, fr_dst
, fr_src
));
4452 if (e
->tag
== Iex_Unop
) {
4453 switch (e
->Iex
.Unop
.op
) {
4454 case Iop_F128HItoF64
:
4455 case Iop_F128LOtoF64
:
4457 /* put upper/lower 64-bits of F128 into an F64. */
4459 HReg fdst
= newVRegF(env
);
4460 HReg fsrc
= iselFp128Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4461 PPCAMode
*am_off0
, *am_off8
, *am_off_arg
;
4462 sub_from_sp( env
, 32 ); // Move SP down 32 bytes
4464 // get a quadword aligned address within our stack space
4465 r_aligned16
= get_sp_aligned16( env
);
4466 am_off0
= PPCAMode_IR( 0, r_aligned16
);
4467 am_off8
= PPCAMode_IR( 8 ,r_aligned16
);
4469 /* store 128-bit floating point value to memory, load low word
4470 * or high to 64-bit destination floating point register
4472 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, fsrc
, am_off0
));
4473 if (IEndianess
== Iend_LE
) {
4474 if (e
->Iex
.Binop
.op
== Iop_F128HItoF64
)
4475 am_off_arg
= am_off8
;
4477 am_off_arg
= am_off0
;
4479 if (e
->Iex
.Binop
.op
== Iop_F128HItoF64
)
4480 am_off_arg
= am_off0
;
4482 am_off_arg
= am_off8
;
4485 PPCInstr_FpLdSt( True
/*load*/,
4488 add_to_sp( env
, 32 ); // Reset SP
4491 case Iop_ReinterpI64asF64
: {
4492 /* Given an I64, produce an IEEE754 double with the same
4495 HReg r_srcHi
, r_srcLo
;
4496 iselInt64Expr( &r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
,
4498 return mk_LoadRR32toFPR( env
, r_srcHi
, r_srcLo
);
4500 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4501 return mk_LoadR64toFPR( env
, r_src
);
4505 case Iop_F32toF64
: {
4506 if (e
->Iex
.Unop
.arg
->tag
== Iex_Unop
&&
4507 e
->Iex
.Unop
.arg
->Iex
.Unop
.op
== Iop_ReinterpI32asF32
) {
4508 e
= e
->Iex
.Unop
.arg
;
4510 HReg src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4511 HReg fr_dst
= newVRegF(env
);
4514 sub_from_sp( env
, 16 ); // Move SP down 16 bytes
4515 am_addr
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4517 // store src as Ity_I32's
4518 addInstr(env
, PPCInstr_Store( 4, am_addr
, src
, env
->mode64
));
4520 // load single precision float, but the end results loads into a
4521 // 64-bit FP register -- i.e., F64.
4522 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 4, fr_dst
, am_addr
));
4524 add_to_sp( env
, 16 ); // Reset SP
4529 /* this is a no-op */
4530 HReg res
= iselFltExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4538 /* --------- MULTIPLEX --------- */
4539 if (e
->tag
== Iex_ITE
) { // VFD
4541 && typeOfIRExpr(env
->type_env
,e
->Iex
.ITE
.cond
) == Ity_I1
) {
4542 HReg fr1
= iselDblExpr(env
, e
->Iex
.ITE
.iftrue
, IEndianess
);
4543 HReg fr0
= iselDblExpr(env
, e
->Iex
.ITE
.iffalse
, IEndianess
);
4544 HReg fr_dst
= newVRegF(env
);
4545 addInstr(env
, PPCInstr_FpUnary( Pfp_MOV
, fr_dst
, fr0
));
4546 PPCCondCode cc
= iselCondCode(env
, e
->Iex
.ITE
.cond
, IEndianess
);
4547 addInstr(env
, PPCInstr_FpCMov( cc
, fr_dst
, fr1
));
4552 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e
->tag
);
4554 vpanic("iselDblExpr_wrk(ppc)");
4557 static HReg
iselDfp32Expr(ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4559 HReg r
= iselDfp32Expr_wrk( env
, e
, IEndianess
);
4560 vassert(hregClass(r
) == HRcFlt64
);
4561 vassert( hregIsVirtual(r
) );
4565 /* DO NOT CALL THIS DIRECTLY */
4566 static HReg
iselDfp32Expr_wrk(ISelEnv
* env
, const IRExpr
* e
,
4567 IREndness IEndianess
)
4569 Bool mode64
= env
->mode64
;
4570 IRType ty
= typeOfIRExpr( env
->type_env
, e
);
4573 vassert( ty
== Ity_D32
);
4575 /* --------- GET --------- */
4576 if (e
->tag
== Iex_Get
) {
4577 HReg r_dst
= newVRegF( env
);
4578 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4579 GuestStatePtr(mode64
) );
4580 addInstr( env
, PPCInstr_FpLdSt( True
/*load*/, 8, r_dst
, am_addr
) );
4584 /* --------- LOAD --------- */
4585 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4587 HReg r_dst
= newVRegF(env
);
4588 vassert(e
->Iex
.Load
.ty
== Ity_D32
);
4589 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_D32
/*xfer*/,
4591 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 4, r_dst
, am_addr
));
4595 /* --------- OPS --------- */
4596 if (e
->tag
== Iex_Binop
) {
4597 if (e
->Iex
.Binop
.op
== Iop_D64toD32
) {
4598 HReg fr_dst
= newVRegF(env
);
4599 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4600 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4601 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DRSP
, fr_dst
, fr_src
));
4607 vpanic( "iselDfp32Expr_wrk(ppc)" );
4610 static HReg
iselFp128Expr( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4612 HReg r
= iselFp128Expr_wrk( env
, e
, IEndianess
);
4613 vassert(hregClass(r
) == HRcVec128
);
4614 vassert(hregIsVirtual(r
));
4618 /* DO NOT CALL THIS DIRECTLY */
4619 static HReg
iselFp128Expr_wrk( ISelEnv
* env
, const IRExpr
* e
,
4620 IREndness IEndianess
)
4622 Bool mode64
= env
->mode64
;
4623 PPCFpOp fpop
= Pfp_INVALID
;
4624 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
4627 vassert( ty
== Ity_F128
);
4629 /* read 128-bit IRTemp */
4630 if (e
->tag
== Iex_RdTmp
) {
4631 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
4634 if (e
->tag
== Iex_Get
) {
4635 /* Guest state vectors are 16byte aligned,
4636 so don't need to worry here */
4637 HReg dst
= newVRegV(env
);
4640 PPCInstr_AvLdSt( True
/*load*/, 16, dst
,
4641 PPCAMode_IR( e
->Iex
.Get
.offset
,
4642 GuestStatePtr(mode64
) )));
4646 if (e
->tag
== Iex_Unop
) {
4647 switch (e
->Iex
.Unop
.op
) {
4648 case Iop_TruncF128toI64S
:
4649 fpop
= Pfp_TRUNCFPQTOISD
; goto do_Un_F128
;
4650 case Iop_TruncF128toI32S
:
4651 fpop
= Pfp_TRUNCFPQTOISW
; goto do_Un_F128
;
4652 case Iop_TruncF128toI64U
:
4653 fpop
= Pfp_TRUNCFPQTOIUD
; goto do_Un_F128
;
4654 case Iop_TruncF128toI32U
:
4655 fpop
= Pfp_TRUNCFPQTOIUW
; goto do_Un_F128
;
4658 HReg r_dst
= newVRegV(env
);
4659 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4660 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, r_src
));
4664 case Iop_F64toF128
: {
4666 HReg r_dst
= newVRegV(env
);
4667 HReg r_src
= iselDblExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4668 HReg v128tmp
= newVRegV(env
);
4669 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
4671 /* value is in 64-bit float reg, need to move to 128-bit vector reg */
4672 sub_from_sp( env
, 16 );
4673 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8, r_src
, zero_r1
));
4674 addInstr(env
, PPCInstr_AvLdSt(True
/*load*/, 16, v128tmp
, zero_r1
));
4675 add_to_sp( env
, 16 );
4677 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, v128tmp
));
4681 case Iop_I64StoF128
:
4682 fpop
= Pfp_IDSTOQ
; goto do_Un_int_F128
;
4683 case Iop_I64UtoF128
:
4684 fpop
= Pfp_IDUTOQ
; goto do_Un_int_F128
;
4687 HReg r_dst
= newVRegV(env
);
4688 HReg tmp
= newVRegV(env
);
4689 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4690 PPCAMode
*am_offhi
, *am_offlo
;
4693 /* source is in a 64-bit integer reg, move to 128-bit float reg
4694 * do this via the stack (easy, convenient, etc).
4696 sub_from_sp( env
, 32 ); // Move SP down
4698 /* Get a quadword aligned address within our stack space */
4699 r_aligned16
= get_sp_aligned16( env
);
4701 am_offlo
= PPCAMode_IR( 0, r_aligned16
);
4702 am_offhi
= PPCAMode_IR( 8, r_aligned16
);
4704 /* Inst only uses the upper 64-bit of the source */
4705 addInstr(env
, PPCInstr_Load(8, r_src
, am_offhi
, mode64
));
4707 /* Fetch result back from stack. */
4708 addInstr(env
, PPCInstr_AvLdSt(True
/*load*/, 16, tmp
, am_offlo
));
4710 add_to_sp( env
, 32 ); // Reset SP
4712 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, tmp
));
4718 } /* switch (e->Iex.Unop.op) */
4719 } /* if (e->tag == Iex_Unop) */
4721 if (e
->tag
== Iex_Binop
) {
4722 switch (e
->Iex
.Binop
.op
) {
4724 case Iop_F64HLtoF128
:
4726 HReg dst
= newVRegV(env
);
4727 HReg r_src_hi
= iselDblExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4728 HReg r_src_lo
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4729 PPCAMode
*am_offhi
, *am_offlo
;
4732 /* do this via the stack (easy, convenient, etc) */
4733 sub_from_sp( env
, 16 ); // Move SP down
4735 /* Get a quadword aligned address within our stack space */
4736 r_aligned16
= get_sp_aligned16( env
);
4738 am_offlo
= PPCAMode_IR( 0, r_aligned16
);
4739 am_offhi
= PPCAMode_IR( 8, r_aligned16
);
4741 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8,
4742 r_src_lo
, am_offlo
));
4743 addInstr(env
, PPCInstr_FpLdSt(False
/*store*/, 8,
4744 r_src_hi
, am_offhi
));
4746 /* Fetch result back from stack. */
4747 addInstr(env
, PPCInstr_AvLdSt(True
/*load*/, 16,
4750 add_to_sp( env
, 16 ); // Reset SP
4753 case Iop_F128toI128S
:
4755 HReg dst
= newVRegV(env
);
4756 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4757 PPCRI
* rm
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4758 /* Note: rm is a set of three bit fields that specify the
4759 * rounding mode and which of the two instructions to issue.
4761 addInstr(env
, PPCInstr_AvBinaryInt(Pav_F128toI128S
, dst
,
4767 HReg dst
= newVRegV(env
);
4768 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4769 PPCRI
* rm
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4770 /* Note: rm is a set of three bit fields that specify the
4771 * rounding mode and which of the two instructions to issue.
4773 addInstr(env
, PPCInstr_AvBinaryInt(Pav_ROUNDFPQ
, dst
,
4778 if (FPU_rounding_mode_isOdd(e
->Iex
.Binop
.arg1
)) {
4779 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4780 fpop
= Pfp_FPSQRTQRNDODD
;
4783 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4788 if (FPU_rounding_mode_isOdd(e
->Iex
.Binop
.arg1
)) {
4789 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4790 fpop
= Pfp_FPQTOWRNDODD
;
4793 set_FPU_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
4798 HReg r_dst
= newVRegV(env
);
4799 HReg r_src
= iselFp128Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
4800 addInstr(env
, PPCInstr_Fp128Unary(fpop
, r_dst
, r_src
));
4806 } /* switch (e->Iex.Binop.op) */
4807 } /* if (e->tag == Iex_Binop) */
4809 if (e
->tag
== Iex_Triop
) {
4810 IRTriop
*triop
= e
->Iex
.Triop
.details
;
4812 switch (triop
->op
) {
4814 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4815 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4816 fpop
= Pfp_FPADDQRNDODD
; goto do_Tri_F128
;
4818 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4819 fpop
= Pfp_FPADDQ
; goto do_Tri_F128
;
4822 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4823 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4824 fpop
= Pfp_FPSUBQRNDODD
; goto do_Tri_F128
;
4826 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4827 fpop
= Pfp_FPSUBQ
; goto do_Tri_F128
;
4830 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4831 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4832 fpop
= Pfp_FPMULQRNDODD
; goto do_Tri_F128
;
4834 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4835 fpop
= Pfp_FPMULQ
; goto do_Tri_F128
;
4838 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4839 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4840 fpop
= Pfp_FPDIVQRNDODD
; goto do_Tri_F128
;
4842 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4843 fpop
= Pfp_FPDIVQ
; goto do_Tri_F128
;
4846 if (FPU_rounding_mode_isOdd(triop
->arg1
)) {
4847 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4848 fpop
= Pfp_FPMULADDQRNDODD
; goto do_Tri_F128
;
4850 set_FPU_rounding_mode( env
, triop
->arg1
, IEndianess
);
4851 fpop
= Pfp_FPMULADDQ
; goto do_Tri_F128
;
4855 HReg r_dst
= newVRegV(env
);
4856 HReg r_srcL
= iselFp128Expr(env
, triop
->arg2
, IEndianess
);
4857 HReg r_srcR
= iselFp128Expr(env
, triop
->arg3
, IEndianess
);
4859 addInstr(env
, PPCInstr_Fp128Binary(fpop
, r_dst
, r_srcL
, r_srcR
));
4865 } /* switch (e->Iex.Triop.op) */
4867 } /* if (e->tag == Iex_Trinop) */
4869 if (e
->tag
== Iex_Qop
) {
4870 IRQop
*qop
= e
->Iex
.Qop
.details
;
4874 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4875 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4876 fpop
= Pfp_FPMULADDQRNDODD
; goto do_Quad_F128
;
4878 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4879 fpop
= Pfp_FPMULADDQ
; goto do_Quad_F128
;
4882 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4883 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4884 fpop
= Pfp_FPMULSUBQRNDODD
; goto do_Quad_F128
;
4886 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4887 fpop
= Pfp_FPMULSUBQ
; goto do_Quad_F128
;
4889 case Iop_NegMAddF128
:
4890 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4891 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4892 fpop
= Pfp_FPNEGMULADDQRNDODD
; goto do_Quad_F128
;
4894 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4895 fpop
= Pfp_FPNEGMULADDQ
; goto do_Quad_F128
;
4897 case Iop_NegMSubF128
:
4898 if (FPU_rounding_mode_isOdd(qop
->arg1
)) {
4899 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4900 fpop
= Pfp_FPNEGMULSUBQRNDODD
; goto do_Quad_F128
;
4902 set_FPU_rounding_mode( env
, qop
->arg1
, IEndianess
);
4903 fpop
= Pfp_FPNEGMULSUBQ
; goto do_Quad_F128
;
4907 HReg r_dst
= iselFp128Expr(env
, qop
->arg3
,
4909 HReg r_srcL
= iselFp128Expr(env
, qop
->arg2
,
4911 HReg r_srcR
= iselFp128Expr(env
, qop
->arg4
,
4914 addInstr(env
, PPCInstr_Fp128Trinary(fpop
, r_dst
, r_srcL
, r_srcR
));
4921 } /* if (e->tag == Iex_Qop) */
4924 vpanic( "iselFp128Expr(ppc64)" );
4927 static HReg
iselDfp64Expr(ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
4929 HReg r
= iselDfp64Expr_wrk( env
, e
, IEndianess
);
4930 vassert(hregClass(r
) == HRcFlt64
);
4931 vassert( hregIsVirtual(r
) );
4935 /* DO NOT CALL THIS DIRECTLY */
4936 static HReg
iselDfp64Expr_wrk(ISelEnv
* env
, const IRExpr
* e
,
4937 IREndness IEndianess
)
4939 Bool mode64
= env
->mode64
;
4940 IRType ty
= typeOfIRExpr( env
->type_env
, e
);
4941 HReg r_dstHi
, r_dstLo
;
4944 vassert( ty
== Ity_D64
);
4946 if (e
->tag
== Iex_RdTmp
) {
4947 return lookupIRTemp( env
, e
->Iex
.RdTmp
.tmp
);
4950 /* --------- GET --------- */
4951 if (e
->tag
== Iex_Get
) {
4952 HReg r_dst
= newVRegF( env
);
4953 PPCAMode
* am_addr
= PPCAMode_IR( e
->Iex
.Get
.offset
,
4954 GuestStatePtr(mode64
) );
4955 addInstr( env
, PPCInstr_FpLdSt( True
/*load*/, 8, r_dst
, am_addr
) );
4959 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
4961 HReg r_dst
= newVRegF(env
);
4962 vassert(e
->Iex
.Load
.ty
== Ity_D64
);
4963 am_addr
= iselWordExpr_AMode(env
, e
->Iex
.Load
.addr
, Ity_D64
/*xfer*/,
4965 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dst
, am_addr
));
4969 /* --------- OPS --------- */
4970 if (e
->tag
== Iex_Qop
) {
4971 HReg r_dst
= newVRegF( env
);
4975 if (e
->tag
== Iex_Unop
) {
4976 HReg fr_dst
= newVRegF(env
);
4977 switch (e
->Iex
.Unop
.op
) {
4978 case Iop_ReinterpI64asD64
: {
4979 /* Given an I64, produce an IEEE754 DFP with the same
4982 HReg r_srcHi
, r_srcLo
;
4983 iselInt64Expr( &r_srcHi
, &r_srcLo
, env
, e
->Iex
.Unop
.arg
,
4985 return mk_LoadRR32toFPR( env
, r_srcHi
, r_srcLo
);
4987 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4988 return mk_LoadR64toFPR( env
, r_src
);
4991 case Iop_D32toD64
: {
4992 HReg fr_src
= iselDfp32Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
4993 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_DCTDP
, fr_dst
, fr_src
));
4996 case Iop_D128HItoD64
:
4997 iselDfp128Expr( &r_dstHi
, &r_dstLo
, env
, e
->Iex
.Unop
.arg
,
5000 case Iop_D128LOtoD64
:
5001 iselDfp128Expr( &r_dstHi
, &r_dstLo
, env
, e
->Iex
.Unop
.arg
,
5004 case Iop_InsertExpD64
: {
5005 HReg fr_srcL
= iselDblExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5006 HReg fr_srcR
= iselDblExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5008 addInstr(env
, PPCInstr_Dfp64Binary(Pfp_DIEX
, fr_dst
, fr_srcL
,
5013 vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
5014 (Int
)e
->Iex
.Unop
.op
);
5018 if (e
->tag
== Iex_Binop
) {
5019 PPCFpOp fpop
= Pfp_INVALID
;
5020 HReg fr_dst
= newVRegF(env
);
5022 switch (e
->Iex
.Binop
.op
) {
5023 case Iop_D128toD64
: fpop
= Pfp_DRDPQ
; break;
5024 case Iop_D64toD32
: fpop
= Pfp_DRSP
; break;
5025 case Iop_I64StoD64
: fpop
= Pfp_DCFFIX
; break;
5026 case Iop_RoundD64toInt
: fpop
= Pfp_DRINTN
; break;
5029 if (fpop
== Pfp_DRDPQ
) {
5030 HReg r_srcHi
= newVRegF(env
);
5031 HReg r_srcLo
= newVRegF(env
);
5033 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5034 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5036 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, fr_dst
, r_srcHi
, r_srcLo
));
5039 } else if (fpop
== Pfp_DRINTN
) {
5040 HReg fr_src
= newVRegF(env
);
5041 PPCRI
* r_rmc
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5043 /* NOTE, this IOP takes a DFP value and rounds to the
5044 * neares floating point integer value, i.e. fractional part
5045 * is zero. The result is a decimal floating point number.
5046 * the INT in the name is a bit misleading.
5048 fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5049 addInstr(env
, PPCInstr_DfpRound(fr_dst
, fr_src
, r_rmc
));
5052 } else if (fpop
== Pfp_DRSP
) {
5053 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5054 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5055 addInstr(env
, PPCInstr_Dfp64Unary(fpop
, fr_dst
, fr_src
));
5058 } else if (fpop
== Pfp_DCFFIX
) {
5059 HReg fr_src
= newVRegF(env
);
5060 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5062 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5063 sub_from_sp( env
, 16 );
5065 // put the I64 value into a floating point register
5067 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5069 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5072 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5074 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Binop
.arg2
,
5076 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*mode32*/));
5077 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*mode32*/));
5080 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_src
, zero_r1
));
5081 addInstr(env
, PPCInstr_Dfp64Unary(fpop
, fr_dst
, fr_src
));
5082 add_to_sp( env
, 16 );
5086 switch (e
->Iex
.Binop
.op
) {
5087 /* shift instructions D64, I32 -> D64 */
5088 case Iop_ShlD64
: fpop
= Pfp_DSCLI
; break;
5089 case Iop_ShrD64
: fpop
= Pfp_DSCRI
; break;
5092 if (fpop
!= Pfp_INVALID
) {
5093 HReg fr_src
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5094 PPCRI
* shift
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5096 /* shift value must be an immediate value */
5097 vassert(shift
->tag
== Pri_Imm
);
5099 addInstr(env
, PPCInstr_DfpShift(fpop
, fr_dst
, fr_src
, shift
));
5103 switch (e
->Iex
.Binop
.op
) {
5104 case Iop_InsertExpD64
:
5109 if (fpop
!= Pfp_INVALID
) {
5110 HReg fr_srcL
= newVRegF(env
);
5111 HReg fr_srcR
= iselDfp64Expr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5112 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5113 sub_from_sp( env
, 16 );
5116 // put the I64 value into a floating point reg
5117 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5119 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5121 // put the I64 register pair into a floating point reg
5124 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5126 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Binop
.arg1
,
5128 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*!mode64*/));
5129 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*!mode64*/));
5131 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_srcL
, zero_r1
));
5132 addInstr(env
, PPCInstr_Dfp64Binary(fpop
, fr_dst
, fr_srcL
,
5134 add_to_sp( env
, 16 );
5139 if (e
->tag
== Iex_Triop
) {
5140 IRTriop
*triop
= e
->Iex
.Triop
.details
;
5141 PPCFpOp fpop
= Pfp_INVALID
;
5143 switch (triop
->op
) {
5159 if (fpop
!= Pfp_INVALID
) {
5160 HReg r_dst
= newVRegF( env
);
5161 HReg r_srcL
= iselDfp64Expr( env
, triop
->arg2
, IEndianess
);
5162 HReg r_srcR
= iselDfp64Expr( env
, triop
->arg3
, IEndianess
);
5164 set_FPU_DFP_rounding_mode( env
, triop
->arg1
, IEndianess
);
5165 addInstr( env
, PPCInstr_Dfp64Binary( fpop
, r_dst
, r_srcL
, r_srcR
) );
5169 switch (triop
->op
) {
5170 case Iop_QuantizeD64
: fpop
= Pfp_DQUA
; break;
5171 case Iop_SignificanceRoundD64
: fpop
= Pfp_RRDTR
; break;
5174 if (fpop
== Pfp_DQUA
) {
5175 HReg r_dst
= newVRegF(env
);
5176 HReg r_srcL
= iselDfp64Expr(env
, triop
->arg2
, IEndianess
);
5177 HReg r_srcR
= iselDfp64Expr(env
, triop
->arg3
, IEndianess
);
5178 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5179 addInstr(env
, PPCInstr_DfpQuantize(fpop
, r_dst
, r_srcL
, r_srcR
,
5183 } else if (fpop
== Pfp_RRDTR
) {
5184 HReg r_dst
= newVRegF(env
);
5185 HReg r_srcL
= newVRegF(env
);
5186 HReg r_srcR
= iselDfp64Expr(env
, triop
->arg3
, IEndianess
);
5187 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5188 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5189 HReg i8_val
= iselWordExpr_R(env
, triop
->arg2
, IEndianess
);
5191 /* Move I8 to float register to issue instruction */
5192 sub_from_sp( env
, 16 );
5194 addInstr(env
, PPCInstr_Store(8, zero_r1
, i8_val
, True
/*mode64*/));
5196 addInstr(env
, PPCInstr_Store(4, zero_r1
, i8_val
, False
/*mode32*/));
5198 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_srcL
, zero_r1
));
5199 add_to_sp( env
, 16 );
5201 // will set TE and RMC when issuing instruction
5202 addInstr(env
, PPCInstr_DfpQuantize(fpop
, r_dst
, r_srcL
, r_srcR
, rmc
));
5208 vpanic( "iselDfp64Expr_wrk(ppc)" );
5211 static void iselDfp128Expr(HReg
* rHi
, HReg
* rLo
, ISelEnv
* env
, const IRExpr
* e
,
5212 IREndness IEndianess
)
5214 iselDfp128Expr_wrk( rHi
, rLo
, env
, e
, IEndianess
);
5215 vassert( hregIsVirtual(*rHi
) );
5216 vassert( hregIsVirtual(*rLo
) );
5219 /* DO NOT CALL THIS DIRECTLY */
5220 static void iselDfp128Expr_wrk(HReg
* rHi
, HReg
*rLo
, ISelEnv
* env
,
5221 const IRExpr
* e
, IREndness IEndianess
)
5224 vassert( typeOfIRExpr(env
->type_env
,e
) == Ity_D128
);
5226 /* read 128-bit IRTemp */
5227 if (e
->tag
== Iex_RdTmp
) {
5228 lookupIRTempPair( rHi
, rLo
, env
, e
->Iex
.RdTmp
.tmp
);
5232 if (e
->tag
== Iex_Unop
) {
5233 HReg r_dstHi
= newVRegF(env
);
5234 HReg r_dstLo
= newVRegF(env
);
5236 if (e
->Iex
.Unop
.op
== Iop_I64StoD128
) {
5237 HReg fr_src
= newVRegF(env
);
5238 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5240 // put the I64 value into a floating point reg
5242 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5243 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5246 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5248 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
,
5250 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*mode32*/));
5251 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*mode32*/));
5254 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, fr_src
, zero_r1
));
5255 addInstr(env
, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ
, r_dstHi
, r_dstLo
,
5259 if (e
->Iex
.Unop
.op
== Iop_D64toD128
) {
5260 HReg r_src
= iselDfp64Expr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5262 /* Source is 64bit, result is 128 bit. High 64bit source arg,
5263 * is ignored by the instruction. Set high arg to r_src just
5264 * to meet the vassert tests.
5266 addInstr(env
, PPCInstr_Dfp128Unary(Pfp_DCTQPQ
, r_dstHi
, r_dstLo
,
5274 /* --------- OPS --------- */
5275 if (e
->tag
== Iex_Binop
) {
5279 switch (e
->Iex
.Binop
.op
) {
5280 case Iop_D64HLtoD128
:
5281 r_srcHi
= iselDfp64Expr( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5282 r_srcLo
= iselDfp64Expr( env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5287 case Iop_D128toD64
: {
5288 PPCFpOp fpop
= Pfp_DRDPQ
;
5289 HReg fr_dst
= newVRegF(env
);
5291 set_FPU_DFP_rounding_mode( env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5292 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5294 addInstr(env
, PPCInstr_DfpD128toD64(fpop
, fr_dst
, r_srcHi
, r_srcLo
));
5296 /* Need to meet the interface spec but the result is
5297 * just 64-bits so send the result back in both halfs.
5305 HReg fr_dst_hi
= newVRegF(env
);
5306 HReg fr_dst_lo
= newVRegF(env
);
5307 PPCRI
* shift
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5308 PPCFpOp fpop
= Pfp_DSCLIQ
; /* fix later if necessary */
5310 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg1
,
5313 if (e
->Iex
.Binop
.op
== Iop_ShrD128
)
5316 addInstr(env
, PPCInstr_DfpShift128(fpop
, fr_dst_hi
, fr_dst_lo
,
5317 r_srcHi
, r_srcLo
, shift
));
5323 case Iop_RoundD128toInt
: {
5324 HReg r_dstHi
= newVRegF(env
);
5325 HReg r_dstLo
= newVRegF(env
);
5326 PPCRI
* r_rmc
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5328 // will set R and RMC when issuing instruction
5329 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5332 addInstr(env
, PPCInstr_DfpRound128(r_dstHi
, r_dstLo
,
5333 r_srcHi
, r_srcLo
, r_rmc
));
5338 case Iop_InsertExpD128
: {
5339 HReg r_dstHi
= newVRegF(env
);
5340 HReg r_dstLo
= newVRegF(env
);
5341 HReg r_srcL
= newVRegF(env
);
5342 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5343 r_srcHi
= newVRegF(env
);
5344 r_srcLo
= newVRegF(env
);
5346 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, e
->Iex
.Binop
.arg2
,
5349 /* Move I64 to float register to issue instruction */
5351 HReg tmp
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5352 addInstr(env
, PPCInstr_Store(8, zero_r1
, tmp
, True
/*mode64*/));
5355 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5357 iselInt64Expr(&tmpHi
, &tmpLo
, env
, e
->Iex
.Unop
.arg
,
5359 addInstr(env
, PPCInstr_Store(4, zero_r1
, tmpHi
, False
/*mode32*/));
5360 addInstr(env
, PPCInstr_Store(4, four_r1
, tmpLo
, False
/*mode32*/));
5363 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_srcL
, zero_r1
));
5364 addInstr(env
, PPCInstr_InsertExpD128(Pfp_DIEXQ
,
5366 r_srcL
, r_srcHi
, r_srcLo
));
5372 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
5373 (Int
)e
->Iex
.Binop
.op
);
5378 if (e
->tag
== Iex_Triop
) {
5379 IRTriop
*triop
= e
->Iex
.Triop
.details
;
5380 PPCFpOp fpop
= Pfp_INVALID
;
5381 HReg r_dstHi
= newVRegF(env
);
5382 HReg r_dstLo
= newVRegF(env
);
5384 switch (triop
->op
) {
5401 if (fpop
!= Pfp_INVALID
) {
5402 HReg r_srcRHi
= newVRegV( env
);
5403 HReg r_srcRLo
= newVRegV( env
);
5405 /* dst will be used to pass in the left operand and get the result. */
5406 iselDfp128Expr( &r_dstHi
, &r_dstLo
, env
, triop
->arg2
, IEndianess
);
5407 iselDfp128Expr( &r_srcRHi
, &r_srcRLo
, env
, triop
->arg3
, IEndianess
);
5408 set_FPU_DFP_rounding_mode( env
, triop
->arg1
, IEndianess
);
5410 PPCInstr_Dfp128Binary( fpop
, r_dstHi
, r_dstLo
,
5411 r_srcRHi
, r_srcRLo
) );
5416 switch (triop
->op
) {
5417 case Iop_QuantizeD128
: fpop
= Pfp_DQUAQ
; break;
5418 case Iop_SignificanceRoundD128
: fpop
= Pfp_DRRNDQ
; break;
5421 if (fpop
== Pfp_DQUAQ
) {
5422 HReg r_srcHi
= newVRegF(env
);
5423 HReg r_srcLo
= newVRegF(env
);
5424 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5426 /* dst will be used to pass in the left operand and get the result */
5427 iselDfp128Expr(&r_dstHi
, &r_dstLo
, env
, triop
->arg2
, IEndianess
);
5428 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, triop
->arg3
, IEndianess
);
5430 // will set RMC when issuing instruction
5431 addInstr(env
, PPCInstr_DfpQuantize128(fpop
, r_dstHi
, r_dstLo
,
5432 r_srcHi
, r_srcLo
, rmc
));
5437 } else if (fpop
== Pfp_DRRNDQ
) {
5438 HReg r_srcHi
= newVRegF(env
);
5439 HReg r_srcLo
= newVRegF(env
);
5440 PPCRI
* rmc
= iselWordExpr_RI(env
, triop
->arg1
, IEndianess
);
5441 PPCAMode
* zero_r1
= PPCAMode_IR( 0, StackFramePtr(env
->mode64
) );
5442 PPCAMode
* four_r1
= PPCAMode_IR( 4, StackFramePtr(env
->mode64
) );
5443 HReg i8_val
= iselWordExpr_R(env
, triop
->arg2
, IEndianess
);
5444 HReg r_zero
= newVRegI( env
);
5446 iselDfp128Expr(&r_srcHi
, &r_srcLo
, env
, triop
->arg3
, IEndianess
);
5448 /* dst will be used to pass in the left operand and get the result */
5449 /* Move I8 to float register to issue instruction. Note, the
5450 * instruction only looks at the bottom 6 bits so we really don't
5451 * have to clear the upper bits since the iselWordExpr_R sets the
5454 sub_from_sp( env
, 16 );
5457 addInstr(env
, PPCInstr_Store(4, four_r1
, i8_val
, True
/*mode64*/));
5459 addInstr(env
, PPCInstr_Store(4, four_r1
, i8_val
, False
/*mode32*/));
5461 /* Have to write to the upper bits to ensure they have been
5462 * initialized. The instruction ignores all but the lower 6-bits.
5464 addInstr( env
, PPCInstr_LI( r_zero
, 0, env
->mode64
) );
5465 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dstHi
, zero_r1
));
5466 addInstr(env
, PPCInstr_FpLdSt(True
/*load*/, 8, r_dstLo
, zero_r1
));
5468 add_to_sp( env
, 16 );
5470 // will set RMC when issuing instruction
5471 addInstr(env
, PPCInstr_DfpQuantize128(fpop
, r_dstHi
, r_dstLo
,
5472 r_srcHi
, r_srcLo
, rmc
));
5480 vpanic( "iselDfp128Expr(ppc64)" );
5484 /*---------------------------------------------------------*/
5485 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
5486 /*---------------------------------------------------------*/
5488 static HReg
iselVecExpr ( ISelEnv
* env
, const IRExpr
* e
, IREndness IEndianess
)
5490 HReg r
= iselVecExpr_wrk( env
, e
, IEndianess
);
5492 vex_printf("\n"); ppIRExpr(e
); vex_printf("\n");
5494 vassert(hregClass(r
) == HRcVec128
);
5495 vassert(hregIsVirtual(r
));
5499 /* DO NOT CALL THIS DIRECTLY */
5500 static HReg
iselVecExpr_wrk ( ISelEnv
* env
, const IRExpr
* e
,
5501 IREndness IEndianess
)
5503 Bool mode64
= env
->mode64
;
5504 PPCAvOp op
= Pav_INVALID
;
5505 PPCAvFpOp fpop
= Pavfp_INVALID
;
5506 IRType ty
= typeOfIRExpr(env
->type_env
,e
);
5508 vassert(ty
== Ity_V128
);
5510 if (e
->tag
== Iex_RdTmp
) {
5511 return lookupIRTemp(env
, e
->Iex
.RdTmp
.tmp
);
5514 if (e
->tag
== Iex_Get
) {
5515 /* Guest state vectors are 16byte aligned,
5516 so don't need to worry here */
5517 HReg dst
= newVRegV(env
);
5519 PPCInstr_AvLdSt( True
/*load*/, 16, dst
,
5520 PPCAMode_IR( e
->Iex
.Get
.offset
,
5521 GuestStatePtr(mode64
) )));
5525 if (e
->tag
== Iex_Load
&& e
->Iex
.Load
.end
== IEndianess
) {
5526 /* Need to be able to do V128 unaligned loads. The BE unaligned load
5527 * can be accomplised using the following code sequece from the ISA.
5528 * It uses the lvx instruction that does two aligned loads and then
5529 * permute the data to store the required data as if it had been an
5532 * lvx Vhi,0,Rb # load MSQ, using the unaligned address in Rb
5533 * lvsl Vp, 0,Rb # Set permute control vector
5534 * addi Rb,Rb,15 # Address of LSQ
5535 * lvx Vlo,0,Rb # load LSQ
5536 * vperm Vt,Vhi,Vlo,Vp # align the data as requested
5539 HReg Vhi
= newVRegV(env
);
5540 HReg Vlo
= newVRegV(env
);
5541 HReg Vp
= newVRegV(env
);
5542 HReg v_dst
= newVRegV(env
);
5544 HReg rB_plus_15
= newVRegI(env
);
5546 vassert(e
->Iex
.Load
.ty
== Ity_V128
);
5547 rB
= iselWordExpr_R( env
, e
->Iex
.Load
.addr
, IEndianess
);
5550 addInstr(env
, PPCInstr_AvLdSt( True
/*load*/, 16, Vhi
,
5551 PPCAMode_IR(0, rB
)) );
5553 if (IEndianess
== Iend_LE
)
5555 addInstr(env
, PPCInstr_AvSh( False
/*right shift*/, Vp
,
5556 PPCAMode_IR(0, rB
)) );
5559 addInstr(env
, PPCInstr_AvSh( True
/*left shift*/, Vp
,
5560 PPCAMode_IR(0, rB
)) );
5562 // addi Rb_plus_15, Rb, 15
5563 addInstr(env
, PPCInstr_Alu( Palu_ADD
, rB_plus_15
,
5564 rB
, PPCRH_Imm(True
, toUShort(15))) );
5566 // lvx Vlo, 0, Rb_plus_15
5567 addInstr(env
, PPCInstr_AvLdSt( True
/*load*/, 16, Vlo
,
5568 PPCAMode_IR(0, rB_plus_15
)) );
5570 if (IEndianess
== Iend_LE
)
5571 // vperm Vt, Vhi, Vlo, Vp
5572 addInstr(env
, PPCInstr_AvPerm( v_dst
, Vlo
, Vhi
, Vp
));
5574 // vperm Vt, Vhi, Vlo, Vp
5575 addInstr(env
, PPCInstr_AvPerm( v_dst
, Vhi
, Vlo
, Vp
));
5580 if (e
->tag
== Iex_Unop
) {
5581 switch (e
->Iex
.Unop
.op
) {
5583 case Iop_F16toF64x2
:
5585 HReg dst
= newVRegV(env
);
5586 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5587 /* Note: PPC only coverts the 16-bt value in the upper word
5588 * to a 64-bit value stored in the upper word. The
5589 * contents of the lower word is undefined.
5591 addInstr(env
, PPCInstr_AvUnary(Pav_F16toF64x2
, dst
, arg
));
5595 case Iop_F64toF16x2
:
5597 HReg dst
= newVRegV(env
);
5598 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5599 /* Note: PPC only coverts the 64-bt value in the upper 64-bit of V128
5600 * to a 16-bit value stored in the upper 64-bits of the result
5601 * V128. The contents of the lower 64-bits is undefined.
5603 addInstr(env
, PPCInstr_AvUnary(Pav_F64toF16x2
, dst
, arg
));
5607 case Iop_F16toF32x4
:
5609 HReg src
= newVRegV(env
);
5610 HReg dst
= newVRegV(env
);
5611 HReg arg
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5612 PPCAMode
*am_off0
, *am_off8
;
5616 /* need to put I64 src into upper 64-bits of vector register,
5618 sub_from_sp( env
, 32 ); // Move SP down
5620 /* Get a quadword aligned address within our stack space */
5621 r_aligned16
= get_sp_aligned16( env
);
5622 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5623 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5625 /* Store I64 to stack */
5627 if (IEndianess
== Iend_LE
) {
5628 addInstr(env
, PPCInstr_Store( 8, am_off8
, arg
, mode64
));
5630 addInstr(env
, PPCInstr_Store( 8, am_off0
, arg
, mode64
));
5633 /* Fetch new v128 src back from stack. */
5634 addInstr(env
, PPCInstr_AvLdSt(True
/*ld*/, 16, src
, am_off0
));
5636 /* issue instruction */
5637 addInstr(env
, PPCInstr_AvUnary(Pav_F16toF32x4
, dst
, src
));
5638 add_to_sp( env
, 32 ); // Reset SP
5643 case Iop_F32toF16x4
:
5645 HReg dst
= newVRegI(env
);
5646 HReg tmp
= newVRegV(env
);
5647 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5648 PPCAMode
*am_off0
, *am_off8
;
5651 /* Instruction returns a V128, the Iop_F32toF16x4 needs to return
5652 * I64. Move the upper 64-bits from the instruction to an I64 via
5653 * the stack and return it.
5655 sub_from_sp( env
, 32 ); // Move SP down
5657 addInstr(env
, PPCInstr_AvUnary(Pav_F32toF16x4
, tmp
, arg
));
5659 /* Get a quadword aligned address within our stack space */
5660 r_aligned16
= get_sp_aligned16( env
);
5661 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5662 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5664 /* Store v128 tmp to stack. */
5665 addInstr(env
, PPCInstr_AvLdSt(False
/*store*/, 16, tmp
, am_off0
));
5667 /* Fetch I64 from stack */
5668 if (IEndianess
== Iend_LE
) {
5669 addInstr(env
, PPCInstr_Load( 8, dst
, am_off8
, mode64
));
5671 addInstr(env
, PPCInstr_Load( 8, dst
, am_off0
, mode64
));
5674 add_to_sp( env
, 32 ); // Reset SP
5679 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5680 HReg dst
= newVRegV(env
);
5681 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, arg
));
5685 case Iop_CmpNEZ8x16
: {
5686 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5687 HReg zero
= newVRegV(env
);
5688 HReg dst
= newVRegV(env
);
5689 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5690 addInstr(env
, PPCInstr_AvBin8x16(Pav_CMPEQU
, dst
, arg
, zero
));
5691 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5695 case Iop_CmpNEZ16x8
: {
5696 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5697 HReg zero
= newVRegV(env
);
5698 HReg dst
= newVRegV(env
);
5699 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5700 addInstr(env
, PPCInstr_AvBin16x8(Pav_CMPEQU
, dst
, arg
, zero
));
5701 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5705 case Iop_CmpNEZ32x4
: {
5706 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5707 HReg zero
= newVRegV(env
);
5708 HReg dst
= newVRegV(env
);
5709 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5710 addInstr(env
, PPCInstr_AvBin32x4(Pav_CMPEQU
, dst
, arg
, zero
));
5711 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5715 case Iop_CmpNEZ64x2
: {
5716 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5717 HReg zero
= newVRegV(env
);
5718 HReg dst
= newVRegV(env
);
5719 addInstr(env
, PPCInstr_AvBinary(Pav_XOR
, zero
, zero
, zero
));
5720 addInstr(env
, PPCInstr_AvBin64x2(Pav_CMPEQU
, dst
, arg
, zero
));
5721 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5725 case Iop_RecipEst32Fx4
: fpop
= Pavfp_RCPF
; goto do_32Fx4_unary
;
5726 case Iop_RSqrtEst32Fx4
: fpop
= Pavfp_RSQRTF
; goto do_32Fx4_unary
;
5727 case Iop_I32UtoFx4
: fpop
= Pavfp_CVTU2F
; goto do_32Fx4_unary
;
5728 case Iop_I32StoFx4
: fpop
= Pavfp_CVTS2F
; goto do_32Fx4_unary
;
5729 case Iop_QFtoI32Ux4_RZ
: fpop
= Pavfp_QCVTF2U
; goto do_32Fx4_unary
;
5730 case Iop_QFtoI32Sx4_RZ
: fpop
= Pavfp_QCVTF2S
; goto do_32Fx4_unary
;
5731 case Iop_RoundF32x4_RM
: fpop
= Pavfp_ROUNDM
; goto do_32Fx4_unary
;
5732 case Iop_RoundF32x4_RP
: fpop
= Pavfp_ROUNDP
; goto do_32Fx4_unary
;
5733 case Iop_RoundF32x4_RN
: fpop
= Pavfp_ROUNDN
; goto do_32Fx4_unary
;
5734 case Iop_RoundF32x4_RZ
: fpop
= Pavfp_ROUNDZ
; goto do_32Fx4_unary
;
5737 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5738 HReg dst
= newVRegV(env
);
5739 addInstr(env
, PPCInstr_AvUn32Fx4(fpop
, dst
, arg
));
5743 case Iop_32UtoV128
: {
5744 HReg r_aligned16
, r_zeros
;
5745 HReg r_src
= iselWordExpr_R(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5746 HReg dst
= newVRegV(env
);
5747 PPCAMode
*am_off0
, *am_off4
, *am_off8
, *am_off12
;
5748 sub_from_sp( env
, 32 ); // Move SP down
5750 /* Get a quadword aligned address within our stack space */
5751 r_aligned16
= get_sp_aligned16( env
);
5752 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5753 am_off4
= PPCAMode_IR( 4, r_aligned16
);
5754 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5755 am_off12
= PPCAMode_IR( 12, r_aligned16
);
5758 r_zeros
= newVRegI(env
);
5759 addInstr(env
, PPCInstr_LI(r_zeros
, 0x0, mode64
));
5760 if (IEndianess
== Iend_LE
)
5761 addInstr(env
, PPCInstr_Store( 4, am_off0
, r_src
, mode64
));
5763 addInstr(env
, PPCInstr_Store( 4, am_off0
, r_zeros
, mode64
));
5764 addInstr(env
, PPCInstr_Store( 4, am_off4
, r_zeros
, mode64
));
5765 addInstr(env
, PPCInstr_Store( 4, am_off8
, r_zeros
, mode64
));
5767 /* Store r_src in low word of quadword-aligned mem */
5768 if (IEndianess
== Iend_LE
)
5769 addInstr(env
, PPCInstr_Store( 4, am_off12
, r_zeros
, mode64
));
5771 addInstr(env
, PPCInstr_Store( 4, am_off12
, r_src
, mode64
));
5773 /* Load word into low word of quadword vector reg */
5774 if (IEndianess
== Iend_LE
)
5775 addInstr(env
, PPCInstr_AvLdSt( True
/*ld*/, 4, dst
, am_off0
));
5777 addInstr(env
, PPCInstr_AvLdSt( True
/*ld*/, 4, dst
, am_off12
));
5779 add_to_sp( env
, 32 ); // Reset SP
5786 return mk_AvDuplicateRI(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5788 case Iop_CipherSV128
: op
= Pav_CIPHERSUBV128
; goto do_AvCipherV128Un
;
5789 do_AvCipherV128Un
: {
5790 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5791 HReg dst
= newVRegV(env
);
5792 addInstr(env
, PPCInstr_AvCipherV128Unary(op
, dst
, arg
));
5796 case Iop_Clz8x16
: op
= Pav_ZEROCNTBYTE
; goto do_zerocnt
;
5797 case Iop_Clz16x8
: op
= Pav_ZEROCNTHALF
; goto do_zerocnt
;
5798 case Iop_Clz32x4
: op
= Pav_ZEROCNTWORD
; goto do_zerocnt
;
5799 case Iop_Clz64x2
: op
= Pav_ZEROCNTDBL
; goto do_zerocnt
;
5800 case Iop_Ctz8x16
: op
= Pav_TRAILINGZEROCNTBYTE
; goto do_zerocnt
;
5801 case Iop_Ctz16x8
: op
= Pav_TRAILINGZEROCNTHALF
; goto do_zerocnt
;
5802 case Iop_Ctz32x4
: op
= Pav_TRAILINGZEROCNTWORD
; goto do_zerocnt
;
5803 case Iop_Ctz64x2
: op
= Pav_TRAILINGZEROCNTDBL
; goto do_zerocnt
;
5804 case Iop_PwBitMtxXpose64x2
: op
= Pav_BITMTXXPOSE
; goto do_zerocnt
;
5807 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5808 HReg dst
= newVRegV(env
);
5809 addInstr(env
, PPCInstr_AvUnary(op
, dst
, arg
));
5814 case Iop_BCD128toI128S
:
5816 HReg dst
= newVRegV(env
);
5817 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5818 addInstr(env
, PPCInstr_AvUnary( Pav_BCD128toI128S
, dst
, arg
) );
5822 case Iop_MulI128by10
: op
= Pav_MulI128by10
; goto do_MulI128
;
5823 case Iop_MulI128by10Carry
: op
= Pav_MulI128by10Carry
; goto do_MulI128
;
5825 HReg dst
= newVRegV(env
);
5826 HReg arg
= iselVecExpr(env
, e
->Iex
.Unop
.arg
, IEndianess
);
5827 addInstr(env
, PPCInstr_AvUnary(op
, dst
, arg
));
5833 } /* switch (e->Iex.Unop.op) */
5834 } /* if (e->tag == Iex_Unop) */
5836 if (e
->tag
== Iex_Binop
) {
5837 switch (e
->Iex
.Binop
.op
) {
5839 case Iop_64HLtoV128
: {
5841 HReg r3
, r2
, r1
, r0
, r_aligned16
;
5842 PPCAMode
*am_off0
, *am_off4
, *am_off8
, *am_off12
;
5843 HReg dst
= newVRegV(env
);
5844 /* do this via the stack (easy, convenient, etc) */
5845 sub_from_sp( env
, 32 ); // Move SP down
5847 // get a quadword aligned address within our stack space
5848 r_aligned16
= get_sp_aligned16( env
);
5849 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5850 am_off4
= PPCAMode_IR( 4, r_aligned16
);
5851 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5852 am_off12
= PPCAMode_IR( 12, r_aligned16
);
5854 /* Do the less significant 64 bits */
5855 iselInt64Expr(&r1
, &r0
, env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5856 addInstr(env
, PPCInstr_Store( 4, am_off12
, r0
, mode64
));
5857 addInstr(env
, PPCInstr_Store( 4, am_off8
, r1
, mode64
));
5858 /* Do the more significant 64 bits */
5859 iselInt64Expr(&r3
, &r2
, env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5860 addInstr(env
, PPCInstr_Store( 4, am_off4
, r2
, mode64
));
5861 addInstr(env
, PPCInstr_Store( 4, am_off0
, r3
, mode64
));
5863 /* Fetch result back from stack. */
5864 addInstr(env
, PPCInstr_AvLdSt(True
/*ld*/, 16, dst
, am_off0
));
5866 add_to_sp( env
, 32 ); // Reset SP
5869 HReg rHi
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5870 HReg rLo
= iselWordExpr_R(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5871 HReg dst
= newVRegV(env
);
5873 PPCAMode
*am_off0
, *am_off8
;
5874 /* do this via the stack (easy, convenient, etc) */
5875 sub_from_sp( env
, 32 ); // Move SP down
5877 // get a quadword aligned address within our stack space
5878 r_aligned16
= get_sp_aligned16( env
);
5879 am_off0
= PPCAMode_IR( 0, r_aligned16
);
5880 am_off8
= PPCAMode_IR( 8, r_aligned16
);
5882 /* Store 2*I64 to stack */
5883 if (IEndianess
== Iend_LE
) {
5884 addInstr(env
, PPCInstr_Store( 8, am_off0
, rLo
, mode64
));
5885 addInstr(env
, PPCInstr_Store( 8, am_off8
, rHi
, mode64
));
5887 addInstr(env
, PPCInstr_Store( 8, am_off0
, rHi
, mode64
));
5888 addInstr(env
, PPCInstr_Store( 8, am_off8
, rLo
, mode64
));
5890 /* Fetch result back from stack. */
5891 addInstr(env
, PPCInstr_AvLdSt(True
/*ld*/, 16, dst
, am_off0
));
5893 add_to_sp( env
, 32 ); // Reset SP
5898 case Iop_Max32Fx4
: fpop
= Pavfp_MAXF
; goto do_32Fx4
;
5899 case Iop_Min32Fx4
: fpop
= Pavfp_MINF
; goto do_32Fx4
;
5900 case Iop_CmpEQ32Fx4
: fpop
= Pavfp_CMPEQF
; goto do_32Fx4
;
5901 case Iop_CmpGT32Fx4
: fpop
= Pavfp_CMPGTF
; goto do_32Fx4
;
5902 case Iop_CmpGE32Fx4
: fpop
= Pavfp_CMPGEF
; goto do_32Fx4
;
5905 HReg argL
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5906 HReg argR
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5907 HReg dst
= newVRegV(env
);
5908 addInstr(env
, PPCInstr_AvBin32Fx4(fpop
, dst
, argL
, argR
));
5912 case Iop_CmpLE32Fx4
: {
5913 HReg argL
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5914 HReg argR
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5915 HReg dst
= newVRegV(env
);
5917 /* stay consistent with native ppc compares:
5918 if a left/right lane holds a nan, return zeros for that lane
5919 so: le == NOT(gt OR isNan)
5921 HReg isNanLR
= newVRegV(env
);
5922 HReg isNanL
= isNan(env
, argL
, IEndianess
);
5923 HReg isNanR
= isNan(env
, argR
, IEndianess
);
5924 addInstr(env
, PPCInstr_AvBinary(Pav_OR
, isNanLR
,
5927 addInstr(env
, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF
, dst
,
5929 addInstr(env
, PPCInstr_AvBinary(Pav_OR
, dst
, dst
, isNanLR
));
5930 addInstr(env
, PPCInstr_AvUnary(Pav_NOT
, dst
, dst
));
5934 case Iop_AndV128
: op
= Pav_AND
; goto do_AvBin
;
5935 case Iop_OrV128
: op
= Pav_OR
; goto do_AvBin
;
5936 case Iop_XorV128
: op
= Pav_XOR
; goto do_AvBin
;
5938 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5939 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5940 HReg dst
= newVRegV(env
);
5941 addInstr(env
, PPCInstr_AvBinary(op
, dst
, arg1
, arg2
));
5945 case Iop_Shl8x16
: op
= Pav_SHL
; goto do_AvBin8x16
;
5946 case Iop_Shr8x16
: op
= Pav_SHR
; goto do_AvBin8x16
;
5947 case Iop_Sar8x16
: op
= Pav_SAR
; goto do_AvBin8x16
;
5948 case Iop_Rol8x16
: op
= Pav_ROTL
; goto do_AvBin8x16
;
5949 case Iop_InterleaveHI8x16
: op
= Pav_MRGHI
; goto do_AvBin8x16
;
5950 case Iop_InterleaveLO8x16
: op
= Pav_MRGLO
; goto do_AvBin8x16
;
5951 case Iop_Add8x16
: op
= Pav_ADDU
; goto do_AvBin8x16
;
5952 case Iop_QAdd8Ux16
: op
= Pav_QADDU
; goto do_AvBin8x16
;
5953 case Iop_QAdd8Sx16
: op
= Pav_QADDS
; goto do_AvBin8x16
;
5954 case Iop_Sub8x16
: op
= Pav_SUBU
; goto do_AvBin8x16
;
5955 case Iop_QSub8Ux16
: op
= Pav_QSUBU
; goto do_AvBin8x16
;
5956 case Iop_QSub8Sx16
: op
= Pav_QSUBS
; goto do_AvBin8x16
;
5957 case Iop_Avg8Ux16
: op
= Pav_AVGU
; goto do_AvBin8x16
;
5958 case Iop_Avg8Sx16
: op
= Pav_AVGS
; goto do_AvBin8x16
;
5959 case Iop_Max8Ux16
: op
= Pav_MAXU
; goto do_AvBin8x16
;
5960 case Iop_Max8Sx16
: op
= Pav_MAXS
; goto do_AvBin8x16
;
5961 case Iop_Min8Ux16
: op
= Pav_MINU
; goto do_AvBin8x16
;
5962 case Iop_Min8Sx16
: op
= Pav_MINS
; goto do_AvBin8x16
;
5963 case Iop_MullEven8Ux16
: op
= Pav_OMULU
; goto do_AvBin8x16
;
5964 case Iop_MullEven8Sx16
: op
= Pav_OMULS
; goto do_AvBin8x16
;
5965 case Iop_CmpEQ8x16
: op
= Pav_CMPEQU
; goto do_AvBin8x16
;
5966 case Iop_CmpGT8Ux16
: op
= Pav_CMPGTU
; goto do_AvBin8x16
;
5967 case Iop_CmpGT8Sx16
: op
= Pav_CMPGTS
; goto do_AvBin8x16
;
5968 case Iop_PolynomialMulAdd8x16
: op
= Pav_POLYMULADD
; goto do_AvBin8x16
;
5970 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
5971 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
5972 HReg dst
= newVRegV(env
);
5973 addInstr(env
, PPCInstr_AvBin8x16(op
, dst
, arg1
, arg2
));
5977 case Iop_Shl16x8
: op
= Pav_SHL
; goto do_AvBin16x8
;
5978 case Iop_Shr16x8
: op
= Pav_SHR
; goto do_AvBin16x8
;
5979 case Iop_Sar16x8
: op
= Pav_SAR
; goto do_AvBin16x8
;
5980 case Iop_Rol16x8
: op
= Pav_ROTL
; goto do_AvBin16x8
;
5981 case Iop_NarrowBin16to8x16
: op
= Pav_PACKUU
; goto do_AvBin16x8
;
5982 case Iop_QNarrowBin16Uto8Ux16
: op
= Pav_QPACKUU
; goto do_AvBin16x8
;
5983 case Iop_QNarrowBin16Sto8Sx16
: op
= Pav_QPACKSS
; goto do_AvBin16x8
;
5984 case Iop_InterleaveHI16x8
: op
= Pav_MRGHI
; goto do_AvBin16x8
;
5985 case Iop_InterleaveLO16x8
: op
= Pav_MRGLO
; goto do_AvBin16x8
;
5986 case Iop_Add16x8
: op
= Pav_ADDU
; goto do_AvBin16x8
;
5987 case Iop_QAdd16Ux8
: op
= Pav_QADDU
; goto do_AvBin16x8
;
5988 case Iop_QAdd16Sx8
: op
= Pav_QADDS
; goto do_AvBin16x8
;
5989 case Iop_Sub16x8
: op
= Pav_SUBU
; goto do_AvBin16x8
;
5990 case Iop_QSub16Ux8
: op
= Pav_QSUBU
; goto do_AvBin16x8
;
5991 case Iop_QSub16Sx8
: op
= Pav_QSUBS
; goto do_AvBin16x8
;
5992 case Iop_Avg16Ux8
: op
= Pav_AVGU
; goto do_AvBin16x8
;
5993 case Iop_Avg16Sx8
: op
= Pav_AVGS
; goto do_AvBin16x8
;
5994 case Iop_Max16Ux8
: op
= Pav_MAXU
; goto do_AvBin16x8
;
5995 case Iop_Max16Sx8
: op
= Pav_MAXS
; goto do_AvBin16x8
;
5996 case Iop_Min16Ux8
: op
= Pav_MINU
; goto do_AvBin16x8
;
5997 case Iop_Min16Sx8
: op
= Pav_MINS
; goto do_AvBin16x8
;
5998 case Iop_MullEven16Ux8
: op
= Pav_OMULU
; goto do_AvBin16x8
;
5999 case Iop_MullEven16Sx8
: op
= Pav_OMULS
; goto do_AvBin16x8
;
6000 case Iop_CmpEQ16x8
: op
= Pav_CMPEQU
; goto do_AvBin16x8
;
6001 case Iop_CmpGT16Ux8
: op
= Pav_CMPGTU
; goto do_AvBin16x8
;
6002 case Iop_CmpGT16Sx8
: op
= Pav_CMPGTS
; goto do_AvBin16x8
;
6003 case Iop_PolynomialMulAdd16x8
: op
= Pav_POLYMULADD
; goto do_AvBin16x8
;
6005 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6006 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6007 HReg dst
= newVRegV(env
);
6008 addInstr(env
, PPCInstr_AvBin16x8(op
, dst
, arg1
, arg2
));
6012 case Iop_Shl32x4
: op
= Pav_SHL
; goto do_AvBin32x4
;
6013 case Iop_Shr32x4
: op
= Pav_SHR
; goto do_AvBin32x4
;
6014 case Iop_Sar32x4
: op
= Pav_SAR
; goto do_AvBin32x4
;
6015 case Iop_Rol32x4
: op
= Pav_ROTL
; goto do_AvBin32x4
;
6016 case Iop_NarrowBin32to16x8
: op
= Pav_PACKUU
; goto do_AvBin32x4
;
6017 case Iop_QNarrowBin32Uto16Ux8
: op
= Pav_QPACKUU
; goto do_AvBin32x4
;
6018 case Iop_QNarrowBin32Sto16Sx8
: op
= Pav_QPACKSS
; goto do_AvBin32x4
;
6019 case Iop_InterleaveHI32x4
: op
= Pav_MRGHI
; goto do_AvBin32x4
;
6020 case Iop_InterleaveLO32x4
: op
= Pav_MRGLO
; goto do_AvBin32x4
;
6021 case Iop_Add32x4
: op
= Pav_ADDU
; goto do_AvBin32x4
;
6022 case Iop_QAdd32Ux4
: op
= Pav_QADDU
; goto do_AvBin32x4
;
6023 case Iop_QAdd32Sx4
: op
= Pav_QADDS
; goto do_AvBin32x4
;
6024 case Iop_Sub32x4
: op
= Pav_SUBU
; goto do_AvBin32x4
;
6025 case Iop_QSub32Ux4
: op
= Pav_QSUBU
; goto do_AvBin32x4
;
6026 case Iop_QSub32Sx4
: op
= Pav_QSUBS
; goto do_AvBin32x4
;
6027 case Iop_Avg32Ux4
: op
= Pav_AVGU
; goto do_AvBin32x4
;
6028 case Iop_Avg32Sx4
: op
= Pav_AVGS
; goto do_AvBin32x4
;
6029 case Iop_Max32Ux4
: op
= Pav_MAXU
; goto do_AvBin32x4
;
6030 case Iop_Max32Sx4
: op
= Pav_MAXS
; goto do_AvBin32x4
;
6031 case Iop_Min32Ux4
: op
= Pav_MINU
; goto do_AvBin32x4
;
6032 case Iop_Min32Sx4
: op
= Pav_MINS
; goto do_AvBin32x4
;
6033 case Iop_Mul32x4
: op
= Pav_MULU
; goto do_AvBin32x4
;
6034 case Iop_MullEven32Ux4
: op
= Pav_OMULU
; goto do_AvBin32x4
;
6035 case Iop_MullEven32Sx4
: op
= Pav_OMULS
; goto do_AvBin32x4
;
6036 case Iop_CmpEQ32x4
: op
= Pav_CMPEQU
; goto do_AvBin32x4
;
6037 case Iop_CmpGT32Ux4
: op
= Pav_CMPGTU
; goto do_AvBin32x4
;
6038 case Iop_CmpGT32Sx4
: op
= Pav_CMPGTS
; goto do_AvBin32x4
;
6039 case Iop_CatOddLanes32x4
: op
= Pav_CATODD
; goto do_AvBin32x4
;
6040 case Iop_CatEvenLanes32x4
: op
= Pav_CATEVEN
; goto do_AvBin32x4
;
6041 case Iop_PolynomialMulAdd32x4
: op
= Pav_POLYMULADD
; goto do_AvBin32x4
;
6043 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6044 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6045 HReg dst
= newVRegV(env
);
6046 addInstr(env
, PPCInstr_AvBin32x4(op
, dst
, arg1
, arg2
));
6050 case Iop_Shl64x2
: op
= Pav_SHL
; goto do_AvBin64x2
;
6051 case Iop_Shr64x2
: op
= Pav_SHR
; goto do_AvBin64x2
;
6052 case Iop_Sar64x2
: op
= Pav_SAR
; goto do_AvBin64x2
;
6053 case Iop_Rol64x2
: op
= Pav_ROTL
; goto do_AvBin64x2
;
6054 case Iop_NarrowBin64to32x4
: op
= Pav_PACKUU
; goto do_AvBin64x2
;
6055 case Iop_QNarrowBin64Sto32Sx4
: op
= Pav_QPACKSS
; goto do_AvBin64x2
;
6056 case Iop_QNarrowBin64Uto32Ux4
: op
= Pav_QPACKUU
; goto do_AvBin64x2
;
6057 case Iop_InterleaveHI64x2
: op
= Pav_MRGHI
; goto do_AvBin64x2
;
6058 case Iop_InterleaveLO64x2
: op
= Pav_MRGLO
; goto do_AvBin64x2
;
6059 case Iop_Add64x2
: op
= Pav_ADDU
; goto do_AvBin64x2
;
6060 case Iop_Sub64x2
: op
= Pav_SUBU
; goto do_AvBin64x2
;
6061 case Iop_Max64Ux2
: op
= Pav_MAXU
; goto do_AvBin64x2
;
6062 case Iop_Max64Sx2
: op
= Pav_MAXS
; goto do_AvBin64x2
;
6063 case Iop_Min64Ux2
: op
= Pav_MINU
; goto do_AvBin64x2
;
6064 case Iop_Min64Sx2
: op
= Pav_MINS
; goto do_AvBin64x2
;
6065 case Iop_CmpEQ64x2
: op
= Pav_CMPEQU
; goto do_AvBin64x2
;
6066 case Iop_CmpGT64Ux2
: op
= Pav_CMPGTU
; goto do_AvBin64x2
;
6067 case Iop_CmpGT64Sx2
: op
= Pav_CMPGTS
; goto do_AvBin64x2
;
6068 case Iop_PolynomialMulAdd64x2
: op
= Pav_POLYMULADD
; goto do_AvBin64x2
;
6070 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6071 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6072 HReg dst
= newVRegV(env
);
6073 addInstr(env
, PPCInstr_AvBin64x2(op
, dst
, arg1
, arg2
));
6077 case Iop_ShlN8x16
: op
= Pav_SHL
; goto do_AvShift8x16
;
6078 case Iop_SarN8x16
: op
= Pav_SAR
; goto do_AvShift8x16
;
6080 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6081 HReg dst
= newVRegV(env
);
6082 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6083 addInstr(env
, PPCInstr_AvBin8x16(op
, dst
, r_src
, v_shft
));
6087 case Iop_ShlN16x8
: op
= Pav_SHL
; goto do_AvShift16x8
;
6088 case Iop_ShrN16x8
: op
= Pav_SHR
; goto do_AvShift16x8
;
6089 case Iop_SarN16x8
: op
= Pav_SAR
; goto do_AvShift16x8
;
6091 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6092 HReg dst
= newVRegV(env
);
6093 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6094 addInstr(env
, PPCInstr_AvBin16x8(op
, dst
, r_src
, v_shft
));
6098 case Iop_ShlN32x4
: op
= Pav_SHL
; goto do_AvShift32x4
;
6099 case Iop_ShrN32x4
: op
= Pav_SHR
; goto do_AvShift32x4
;
6100 case Iop_SarN32x4
: op
= Pav_SAR
; goto do_AvShift32x4
;
6102 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6103 HReg dst
= newVRegV(env
);
6104 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6105 addInstr(env
, PPCInstr_AvBin32x4(op
, dst
, r_src
, v_shft
));
6109 case Iop_ShlN64x2
: op
= Pav_SHL
; goto do_AvShift64x2
;
6110 case Iop_ShrN64x2
: op
= Pav_SHR
; goto do_AvShift64x2
;
6111 case Iop_SarN64x2
: op
= Pav_SAR
; goto do_AvShift64x2
;
6113 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6114 HReg dst
= newVRegV(env
);
6115 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6116 addInstr(env
, PPCInstr_AvBin64x2(op
, dst
, r_src
, v_shft
));
6120 case Iop_ShrV128
: op
= Pav_SHR
; goto do_AvShiftV128
;
6121 case Iop_ShlV128
: op
= Pav_SHL
; goto do_AvShiftV128
;
6123 HReg dst
= newVRegV(env
);
6124 HReg r_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6125 HReg v_shft
= mk_AvDuplicateRI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6126 /* Note: shift value gets masked by 127 */
6127 addInstr(env
, PPCInstr_AvBinary(op
, dst
, r_src
, v_shft
));
6131 case Iop_Perm8x16
: {
6132 HReg dst
= newVRegV(env
);
6133 HReg v_src
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6134 HReg v_ctl
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6135 addInstr(env
, PPCInstr_AvPerm(dst
, v_src
, v_src
, v_ctl
));
6139 case Iop_CipherV128
: op
= Pav_CIPHERV128
; goto do_AvCipherV128
;
6140 case Iop_CipherLV128
: op
= Pav_CIPHERLV128
; goto do_AvCipherV128
;
6141 case Iop_NCipherV128
: op
= Pav_NCIPHERV128
; goto do_AvCipherV128
;
6142 case Iop_NCipherLV128
:op
= Pav_NCIPHERLV128
; goto do_AvCipherV128
;
6144 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6145 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6146 HReg dst
= newVRegV(env
);
6147 addInstr(env
, PPCInstr_AvCipherV128Binary(op
, dst
, arg1
, arg2
));
6151 case Iop_SHA256
:op
= Pav_SHA256
; goto do_AvHashV128
;
6152 case Iop_SHA512
:op
= Pav_SHA512
; goto do_AvHashV128
;
6154 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6155 HReg dst
= newVRegV(env
);
6156 PPCRI
* s_field
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6157 addInstr(env
, PPCInstr_AvHashV128Binary(op
, dst
, arg1
, s_field
));
6162 case Iop_I128StoBCD128
:
6164 HReg dst
= newVRegV(env
);
6165 HReg arg
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6166 PPCRI
* ps
= iselWordExpr_RI(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6168 addInstr(env
, PPCInstr_AvBinaryInt( Pav_I128StoBCD128
, dst
, arg
,
6173 case Iop_MulI128by10E
: op
= Pav_MulI128by10E
; goto do_MulI128E
;
6174 case Iop_MulI128by10ECarry
: op
= Pav_MulI128by10ECarry
; goto do_MulI128E
;
6176 HReg dst
= newVRegV(env
);
6177 HReg argL
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6178 HReg argR
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6179 addInstr(env
, PPCInstr_AvBinary(op
, dst
, argL
, argR
));
6183 case Iop_BCDAdd
:op
= Pav_BCDAdd
; goto do_AvBCDV128
;
6184 case Iop_BCDSub
:op
= Pav_BCDSub
; goto do_AvBCDV128
;
6186 HReg arg1
= iselVecExpr(env
, e
->Iex
.Binop
.arg1
, IEndianess
);
6187 HReg arg2
= iselVecExpr(env
, e
->Iex
.Binop
.arg2
, IEndianess
);
6188 HReg dst
= newVRegV(env
);
6189 addInstr(env
, PPCInstr_AvBCDV128Binary(op
, dst
, arg1
, arg2
));
6195 } /* switch (e->Iex.Binop.op) */
6196 } /* if (e->tag == Iex_Binop) */
6198 if (e
->tag
== Iex_Triop
) {
6199 IRTriop
*triop
= e
->Iex
.Triop
.details
;
6200 switch (triop
->op
) {
6201 case Iop_Add32Fx4
: fpop
= Pavfp_ADDF
; goto do_32Fx4_with_rm
;
6202 case Iop_Sub32Fx4
: fpop
= Pavfp_SUBF
; goto do_32Fx4_with_rm
;
6203 case Iop_Mul32Fx4
: fpop
= Pavfp_MULF
; goto do_32Fx4_with_rm
;
6206 HReg argL
= iselVecExpr(env
, triop
->arg2
, IEndianess
);
6207 HReg argR
= iselVecExpr(env
, triop
->arg3
, IEndianess
);
6208 HReg dst
= newVRegV(env
);
6209 /* FIXME: this is bogus, in the sense that Altivec ignores
6210 FPSCR.RM, at least for some FP operations. So setting the
6211 RM is pointless. This is only really correct in the case
6212 where the RM is known, at JIT time, to be Irrm_NEAREST,
6213 since -- at least for Altivec FP add/sub/mul -- the
6214 emitted insn is hardwired to round to nearest. */
6215 set_FPU_rounding_mode(env
, triop
->arg1
, IEndianess
);
6216 addInstr(env
, PPCInstr_AvBin32Fx4(fpop
, dst
, argL
, argR
));
6222 } /* switch (e->Iex.Triop.op) */
6223 } /* if (e->tag == Iex_Trinop) */
6226 if (e
->tag
== Iex_Const
) {
6227 vassert(e
->Iex
.Const
.con
->tag
== Ico_V128
);
6228 if (e
->Iex
.Const
.con
->Ico
.V128
== 0x0000) {
6229 return generate_zeroes_V128(env
);
6231 else if (e
->Iex
.Const
.con
->Ico
.V128
== 0xffff) {
6232 return generate_ones_V128(env
);
6236 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
6237 LibVEX_ppVexHwCaps(mode64
? VexArchPPC64
: VexArchPPC32
,
6240 vpanic("iselVecExpr_wrk(ppc)");
6244 /*---------------------------------------------------------*/
6245 /*--- ISEL: Statements ---*/
6246 /*---------------------------------------------------------*/
6248 static void iselStmt ( ISelEnv
* env
, IRStmt
* stmt
, IREndness IEndianess
)
6250 Bool mode64
= env
->mode64
;
6251 if (vex_traceflags
& VEX_TRACE_VCODE
) {
6252 vex_printf("\n -- ");
6257 switch (stmt
->tag
) {
6259 /* --------- STORE --------- */
6261 IRType tya
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.Store
.addr
);
6262 IRType tyd
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.Store
.data
);
6263 IREndness end
= stmt
->Ist
.Store
.end
;
6265 if (end
!= IEndianess
)
6267 if (!mode64
&& (tya
!= Ity_I32
))
6269 if (mode64
&& (tya
!= Ity_I64
))
6272 if (tyd
== Ity_I8
|| tyd
== Ity_I16
|| tyd
== Ity_I32
||
6273 (mode64
&& (tyd
== Ity_I64
))) {
6275 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6277 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6278 addInstr(env
, PPCInstr_Store( toUChar(sizeofIRType(tyd
)),
6279 am_addr
, r_src
, mode64
));
6282 if (tyd
== Ity_F64
) {
6284 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6286 HReg fr_src
= iselDblExpr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6288 PPCInstr_FpLdSt(False
/*store*/, 8, fr_src
, am_addr
));
6291 if (tyd
== Ity_F32
) {
6293 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6295 HReg fr_src
= iselFltExpr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6297 PPCInstr_FpLdSt(False
/*store*/, 4, fr_src
, am_addr
));
6300 if (tyd
== Ity_D64
) {
6302 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6304 HReg fr_src
= iselDfp64Expr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6306 PPCInstr_FpLdSt(False
/*store*/, 8, fr_src
, am_addr
));
6309 if (tyd
== Ity_D32
) {
6311 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6313 HReg fr_src
= iselDfp32Expr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6315 PPCInstr_FpLdSt(False
/*store*/, 4, fr_src
, am_addr
));
6318 if (tyd
== Ity_V128
) {
6320 = iselWordExpr_AMode(env
, stmt
->Ist
.Store
.addr
, tyd
/*of xfer*/,
6322 HReg v_src
= iselVecExpr(env
, stmt
->Ist
.Store
.data
, IEndianess
);
6324 PPCInstr_AvLdSt(False
/*store*/, 16, v_src
, am_addr
));
6327 if (tyd
== Ity_I64
&& !mode64
) {
6328 /* Just calculate the address in the register. Life is too
6329 short to arse around trying and possibly failing to adjust
6330 the offset in a 'reg+offset' style amode. */
6332 HReg r_addr
= iselWordExpr_R(env
, stmt
->Ist
.Store
.addr
, IEndianess
);
6333 iselInt64Expr( &rHi32
, &rLo32
, env
, stmt
->Ist
.Store
.data
,
6335 addInstr(env
, PPCInstr_Store( 4/*byte-store*/,
6336 PPCAMode_IR( 0, r_addr
),
6338 False
/*32-bit insn please*/) );
6339 addInstr(env
, PPCInstr_Store( 4/*byte-store*/,
6340 PPCAMode_IR( 4, r_addr
),
6342 False
/*32-bit insn please*/) );
6348 /* --------- PUT --------- */
6350 IRType ty
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.Put
.data
);
6351 if (ty
== Ity_I8
|| ty
== Ity_I16
||
6352 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) {
6353 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6354 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6355 GuestStatePtr(mode64
) );
6356 addInstr(env
, PPCInstr_Store( toUChar(sizeofIRType(ty
)),
6357 am_addr
, r_src
, mode64
));
6360 if (!mode64
&& ty
== Ity_I64
) {
6362 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6363 GuestStatePtr(mode64
) );
6364 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
6365 iselInt64Expr(&rHi
,&rLo
, env
, stmt
->Ist
.Put
.data
, IEndianess
);
6366 addInstr(env
, PPCInstr_Store( 4, am_addr
, rHi
, mode64
));
6367 addInstr(env
, PPCInstr_Store( 4, am_addr4
, rLo
, mode64
));
6370 if (ty
== Ity_I128
) {
6372 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6373 GuestStatePtr(mode64
) );
6374 PPCAMode
* am_addr4
= advance4(env
, am_addr
);
6376 iselInt128Expr(&rHi
,&rLo
, env
, stmt
->Ist
.Put
.data
, IEndianess
);
6377 addInstr(env
, PPCInstr_Store( 4, am_addr
, rHi
, mode64
));
6378 addInstr(env
, PPCInstr_Store( 4, am_addr4
, rLo
, mode64
));
6381 if (ty
== Ity_F128
) {
6382 /* Guest state vectors are 16byte aligned,
6383 so don't need to worry here */
6384 HReg v_src
= iselFp128Expr(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6386 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6387 GuestStatePtr(mode64
) );
6389 PPCInstr_AvLdSt(False
/*store*/, 16, v_src
, am_addr
));
6392 if (ty
== Ity_V128
) {
6393 /* Guest state vectors are 16byte aligned,
6394 so don't need to worry here */
6395 HReg v_src
= iselVecExpr(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6396 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6397 GuestStatePtr(mode64
) );
6399 PPCInstr_AvLdSt(False
/*store*/, 16, v_src
, am_addr
));
6402 if (ty
== Ity_F64
) {
6403 HReg fr_src
= iselDblExpr(env
, stmt
->Ist
.Put
.data
, IEndianess
);
6404 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6405 GuestStatePtr(mode64
) );
6406 addInstr(env
, PPCInstr_FpLdSt( False
/*store*/, 8,
6410 if (ty
== Ity_D32
) {
6411 /* The 32-bit value is stored in a 64-bit register */
6412 HReg fr_src
= iselDfp32Expr( env
, stmt
->Ist
.Put
.data
, IEndianess
);
6413 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6414 GuestStatePtr(mode64
) );
6415 addInstr( env
, PPCInstr_FpLdSt( False
/*store*/, 8,
6416 fr_src
, am_addr
) );
6419 if (ty
== Ity_D64
) {
6420 HReg fr_src
= iselDfp64Expr( env
, stmt
->Ist
.Put
.data
, IEndianess
);
6421 PPCAMode
* am_addr
= PPCAMode_IR( stmt
->Ist
.Put
.offset
,
6422 GuestStatePtr(mode64
) );
6423 addInstr( env
, PPCInstr_FpLdSt( False
/*store*/, 8, fr_src
, am_addr
) );
6429 /* --------- Indexed PUT --------- */
6431 IRPutI
*puti
= stmt
->Ist
.PutI
.details
;
6434 = genGuestArrayOffset(
6436 puti
->ix
, puti
->bias
,
6438 IRType ty
= typeOfIRExpr(env
->type_env
, puti
->data
);
6439 if (mode64
&& ty
== Ity_I64
) {
6440 HReg r_src
= iselWordExpr_R(env
, puti
->data
, IEndianess
);
6441 addInstr(env
, PPCInstr_Store( toUChar(8),
6442 dst_am
, r_src
, mode64
));
6445 if ((!mode64
) && ty
== Ity_I32
) {
6446 HReg r_src
= iselWordExpr_R(env
, puti
->data
, IEndianess
);
6447 addInstr(env
, PPCInstr_Store( toUChar(4),
6448 dst_am
, r_src
, mode64
));
6454 /* --------- TMP --------- */
6456 IRTemp tmp
= stmt
->Ist
.WrTmp
.tmp
;
6457 IRType ty
= typeOfIRTemp(env
->type_env
, tmp
);
6458 if (ty
== Ity_I8
|| ty
== Ity_I16
||
6459 ty
== Ity_I32
|| ((ty
== Ity_I64
) && mode64
)) {
6460 HReg r_dst
= lookupIRTemp(env
, tmp
);
6461 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6462 addInstr(env
, mk_iMOVds_RR( r_dst
, r_src
));
6465 if (!mode64
&& ty
== Ity_I64
) {
6466 HReg r_srcHi
, r_srcLo
, r_dstHi
, r_dstLo
;
6468 iselInt64Expr(&r_srcHi
,&r_srcLo
, env
, stmt
->Ist
.WrTmp
.data
,
6470 lookupIRTempPair( &r_dstHi
, &r_dstLo
, env
, tmp
);
6471 addInstr(env
, mk_iMOVds_RR(r_dstHi
, r_srcHi
) );
6472 addInstr(env
, mk_iMOVds_RR(r_dstLo
, r_srcLo
) );
6475 if (mode64
&& ty
== Ity_I128
) {
6476 HReg r_srcHi
, r_srcLo
, r_dstHi
, r_dstLo
;
6477 iselInt128Expr(&r_srcHi
,&r_srcLo
, env
, stmt
->Ist
.WrTmp
.data
,
6479 lookupIRTempPair( &r_dstHi
, &r_dstLo
, env
, tmp
);
6480 addInstr(env
, mk_iMOVds_RR(r_dstHi
, r_srcHi
) );
6481 addInstr(env
, mk_iMOVds_RR(r_dstLo
, r_srcLo
) );
6484 if (!mode64
&& ty
== Ity_I128
) {
6485 HReg r_srcHi
, r_srcMedHi
, r_srcMedLo
, r_srcLo
;
6486 HReg r_dstHi
, r_dstMedHi
, r_dstMedLo
, r_dstLo
;
6488 iselInt128Expr_to_32x4(&r_srcHi
, &r_srcMedHi
,
6489 &r_srcMedLo
, &r_srcLo
,
6490 env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6492 lookupIRTempQuad( &r_dstHi
, &r_dstMedHi
, &r_dstMedLo
,
6493 &r_dstLo
, env
, tmp
);
6495 addInstr(env
, mk_iMOVds_RR(r_dstHi
, r_srcHi
) );
6496 addInstr(env
, mk_iMOVds_RR(r_dstMedHi
, r_srcMedHi
) );
6497 addInstr(env
, mk_iMOVds_RR(r_dstMedLo
, r_srcMedLo
) );
6498 addInstr(env
, mk_iMOVds_RR(r_dstLo
, r_srcLo
) );
6502 PPCCondCode cond
= iselCondCode(env
, stmt
->Ist
.WrTmp
.data
,
6504 HReg r_dst
= lookupIRTemp(env
, tmp
);
6505 addInstr(env
, PPCInstr_Set(cond
, r_dst
));
6508 if (ty
== Ity_F64
) {
6509 HReg fr_dst
= lookupIRTemp(env
, tmp
);
6510 HReg fr_src
= iselDblExpr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6511 addInstr(env
, PPCInstr_FpUnary(Pfp_MOV
, fr_dst
, fr_src
));
6514 if (ty
== Ity_F32
) {
6515 HReg fr_dst
= lookupIRTemp(env
, tmp
);
6516 HReg fr_src
= iselFltExpr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6517 addInstr(env
, PPCInstr_FpUnary(Pfp_MOV
, fr_dst
, fr_src
));
6520 if (ty
== Ity_D32
) {
6521 HReg fr_dst
= lookupIRTemp(env
, tmp
);
6522 HReg fr_src
= iselDfp32Expr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6523 addInstr(env
, PPCInstr_Dfp64Unary(Pfp_MOV
, fr_dst
, fr_src
));
6526 if (ty
== Ity_F128
) {
6527 HReg v_dst
= lookupIRTemp(env
, tmp
);
6528 HReg v_src
= iselFp128Expr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6529 addInstr(env
, PPCInstr_AvUnary(Pav_MOV
, v_dst
, v_src
));
6532 if (ty
== Ity_V128
) {
6533 HReg v_dst
= lookupIRTemp(env
, tmp
);
6534 HReg v_src
= iselVecExpr(env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6535 addInstr(env
, PPCInstr_AvUnary(Pav_MOV
, v_dst
, v_src
));
6538 if (ty
== Ity_D64
) {
6539 HReg fr_dst
= lookupIRTemp( env
, tmp
);
6540 HReg fr_src
= iselDfp64Expr( env
, stmt
->Ist
.WrTmp
.data
, IEndianess
);
6541 addInstr( env
, PPCInstr_Dfp64Unary( Pfp_MOV
, fr_dst
, fr_src
) );
6544 if (ty
== Ity_D128
) {
6545 HReg fr_srcHi
, fr_srcLo
, fr_dstHi
, fr_dstLo
;
6546 // lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
6547 lookupIRTempPair( &fr_dstHi
, &fr_dstLo
, env
, tmp
);
6548 iselDfp128Expr( &fr_srcHi
, &fr_srcLo
, env
, stmt
->Ist
.WrTmp
.data
,
6550 addInstr( env
, PPCInstr_Dfp64Unary( Pfp_MOV
, fr_dstHi
, fr_srcHi
) );
6551 addInstr( env
, PPCInstr_Dfp64Unary( Pfp_MOV
, fr_dstLo
, fr_srcLo
) );
6557 /* --------- Load Linked or Store Conditional --------- */
6559 IRTemp res
= stmt
->Ist
.LLSC
.result
;
6560 IRType tyRes
= typeOfIRTemp(env
->type_env
, res
);
6561 IRType tyAddr
= typeOfIRExpr(env
->type_env
, stmt
->Ist
.LLSC
.addr
);
6563 if (stmt
->Ist
.LLSC
.end
!= IEndianess
)
6565 if (!mode64
&& (tyAddr
!= Ity_I32
))
6567 if (mode64
&& (tyAddr
!= Ity_I64
))
6570 if (stmt
->Ist
.LLSC
.storedata
== NULL
) {
6572 HReg r_addr
= iselWordExpr_R( env
, stmt
->Ist
.LLSC
.addr
, IEndianess
);
6573 HReg r_dst
= lookupIRTemp(env
, res
);
6574 if (tyRes
== Ity_I8
) {
6575 addInstr(env
, PPCInstr_LoadL( 1, r_dst
, r_addr
, mode64
));
6578 if (tyRes
== Ity_I16
) {
6579 addInstr(env
, PPCInstr_LoadL( 2, r_dst
, r_addr
, mode64
));
6582 if (tyRes
== Ity_I32
) {
6583 addInstr(env
, PPCInstr_LoadL( 4, r_dst
, r_addr
, mode64
));
6586 if (tyRes
== Ity_I64
&& mode64
) {
6587 addInstr(env
, PPCInstr_LoadL( 8, r_dst
, r_addr
, mode64
));
6593 HReg r_res
= lookupIRTemp(env
, res
); /* :: Ity_I1 */
6594 HReg r_a
= iselWordExpr_R(env
, stmt
->Ist
.LLSC
.addr
, IEndianess
);
6595 HReg r_src
= iselWordExpr_R(env
, stmt
->Ist
.LLSC
.storedata
,
6597 HReg r_tmp
= newVRegI(env
);
6598 IRType tyData
= typeOfIRExpr(env
->type_env
,
6599 stmt
->Ist
.LLSC
.storedata
);
6600 vassert(tyRes
== Ity_I1
);
6601 if (tyData
== Ity_I8
|| tyData
== Ity_I16
|| tyData
== Ity_I32
||
6602 (tyData
== Ity_I64
&& mode64
)) {
6605 if (tyData
== Ity_I64
)
6607 else if (tyData
== Ity_I32
)
6609 else if (tyData
== Ity_I16
)
6611 else if (tyData
== Ity_I8
)
6614 addInstr(env
, PPCInstr_StoreC( size
,
6615 r_a
, r_src
, mode64
));
6616 addInstr(env
, PPCInstr_MfCR( r_tmp
));
6617 addInstr(env
, PPCInstr_Shft(
6619 env
->mode64
? False
: True
6620 /*F:64-bit, T:32-bit shift*/,
6622 PPCRH_Imm(False
/*unsigned*/, 29)));
6623 /* Probably unnecessary, since the IR dest type is Ity_I1,
6624 and so we are entitled to leave whatever junk we like
6625 drifting round in the upper 31 or 63 bits of r_res.
6626 However, for the sake of conservativeness .. */
6627 addInstr(env
, PPCInstr_Alu(
6630 PPCRH_Imm(False
/*signed*/, 1)));
6639 /* --------- Call to DIRTY helper --------- */
6641 IRDirty
* d
= stmt
->Ist
.Dirty
.details
;
6643 /* Figure out the return type, if any. */
6644 IRType retty
= Ity_INVALID
;
6645 if (d
->tmp
!= IRTemp_INVALID
)
6646 retty
= typeOfIRTemp(env
->type_env
, d
->tmp
);
6648 /* Throw out any return types we don't know about. The set of
6649 acceptable return types is the same in both 32- and 64-bit
6650 mode, so we don't need to inspect mode64 to make a
6652 Bool retty_ok
= False
;
6654 case Ity_INVALID
: /* function doesn't return anything */
6656 case Ity_I64
: case Ity_I32
: case Ity_I16
: case Ity_I8
:
6657 retty_ok
= True
; break;
6662 break; /* will go to stmt_fail: */
6664 /* Marshal args, do the call, clear stack, set the return value
6665 to 0x555..555 if this is a conditional call that returns a
6666 value and the call is skipped. */
6668 RetLoc rloc
= mk_RetLoc_INVALID();
6669 doHelperCall( &addToSp
, &rloc
, env
, d
->guard
, d
->cee
, retty
, d
->args
,
6671 vassert(is_sane_RetLoc(rloc
));
6673 /* Now figure out what to do with the returned value, if any. */
6676 /* No return value. Nothing to do. */
6677 vassert(d
->tmp
== IRTemp_INVALID
);
6678 vassert(rloc
.pri
== RLPri_None
);
6679 vassert(addToSp
== 0);
6682 case Ity_I32
: case Ity_I16
: case Ity_I8
: {
6683 /* The returned value is in %r3. Park it in the register
6684 associated with tmp. */
6685 HReg r_dst
= lookupIRTemp(env
, d
->tmp
);
6686 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
6687 vassert(rloc
.pri
== RLPri_Int
);
6688 vassert(addToSp
== 0);
6693 /* The returned value is in %r3. Park it in the register
6694 associated with tmp. */
6695 HReg r_dst
= lookupIRTemp(env
, d
->tmp
);
6696 addInstr(env
, mk_iMOVds_RR(r_dst
, hregPPC_GPR3(mode64
)));
6697 vassert(rloc
.pri
== RLPri_Int
);
6698 vassert(addToSp
== 0);
6700 /* The returned value is in %r3:%r4. Park it in the
6701 register-pair associated with tmp. */
6702 HReg r_dstHi
= INVALID_HREG
;
6703 HReg r_dstLo
= INVALID_HREG
;
6704 lookupIRTempPair( &r_dstHi
, &r_dstLo
, env
, d
->tmp
);
6705 addInstr(env
, mk_iMOVds_RR(r_dstHi
, hregPPC_GPR3(mode64
)));
6706 addInstr(env
, mk_iMOVds_RR(r_dstLo
, hregPPC_GPR4(mode64
)));
6707 vassert(rloc
.pri
== RLPri_2Int
);
6708 vassert(addToSp
== 0);
6712 /* The returned value is on the stack, and *retloc tells
6713 us where. Fish it off the stack and then move the
6714 stack pointer upwards to clear it, as directed by
6716 vassert(rloc
.pri
== RLPri_V128SpRel
);
6717 vassert(addToSp
>= 16);
6718 HReg dst
= lookupIRTemp(env
, d
->tmp
);
6719 PPCAMode
* am
= PPCAMode_IR(rloc
.spOff
, StackFramePtr(mode64
));
6720 addInstr(env
, PPCInstr_AvLdSt( True
/*load*/, 16, dst
, am
));
6721 add_to_sp(env
, addToSp
);
6730 /* --------- MEM FENCE --------- */
6732 switch (stmt
->Ist
.MBE
.event
) {
6734 addInstr(env
, PPCInstr_MFence());
6741 /* --------- INSTR MARK --------- */
6742 /* Doesn't generate any executable code ... */
6746 /* --------- ABI HINT --------- */
6747 /* These have no meaning (denotation in the IR) and so we ignore
6748 them ... if any actually made it this far. */
6752 /* --------- NO-OP --------- */
6753 /* Fairly self-explanatory, wouldn't you say? */
6757 /* --------- EXIT --------- */
6759 IRConst
* dst
= stmt
->Ist
.Exit
.dst
;
6760 if (!mode64
&& dst
->tag
!= Ico_U32
)
6761 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
6762 if (mode64
&& dst
->tag
!= Ico_U64
)
6763 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
6765 PPCCondCode cc
= iselCondCode(env
, stmt
->Ist
.Exit
.guard
, IEndianess
);
6766 PPCAMode
* amCIA
= PPCAMode_IR(stmt
->Ist
.Exit
.offsIP
,
6767 hregPPC_GPR31(mode64
));
6769 /* Case: boring transfer to known address */
6770 if (stmt
->Ist
.Exit
.jk
== Ijk_Boring
6771 || stmt
->Ist
.Exit
.jk
== Ijk_Call
6772 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
6773 if (env
->chainingAllowed
) {
6774 /* .. almost always true .. */
6775 /* Skip the event check at the dst if this is a forwards
6779 ? (((Addr64
)stmt
->Ist
.Exit
.dst
->Ico
.U64
) > (Addr64
)env
->max_ga
)
6780 : (((Addr32
)stmt
->Ist
.Exit
.dst
->Ico
.U32
) > (Addr32
)env
->max_ga
);
6781 if (0) vex_printf("%s", toFastEP
? "Y" : ",");
6782 addInstr(env
, PPCInstr_XDirect(
6783 mode64
? (Addr64
)stmt
->Ist
.Exit
.dst
->Ico
.U64
6784 : (Addr64
)stmt
->Ist
.Exit
.dst
->Ico
.U32
,
6785 amCIA
, cc
, toFastEP
));
6787 /* .. very occasionally .. */
6788 /* We can't use chaining, so ask for an assisted transfer,
6789 as that's the only alternative that is allowable. */
6790 HReg r
= iselWordExpr_R(env
, IRExpr_Const(stmt
->Ist
.Exit
.dst
),
6792 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, cc
, Ijk_Boring
));
6797 /* Case: assisted transfer to arbitrary address */
6798 switch (stmt
->Ist
.Exit
.jk
) {
6799 /* Keep this list in sync with that in iselNext below */
6807 case Ijk_Sys_syscall
:
6808 case Ijk_InvalICache
:
6810 HReg r
= iselWordExpr_R(env
, IRExpr_Const(stmt
->Ist
.Exit
.dst
),
6812 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, cc
,
6813 stmt
->Ist
.Exit
.jk
));
6820 /* Do we ever expect to see any other kind? */
6828 vpanic("iselStmt(ppc)");
6832 /*---------------------------------------------------------*/
6833 /*--- ISEL: Basic block terminators (Nexts) ---*/
6834 /*---------------------------------------------------------*/
6836 static void iselNext ( ISelEnv
* env
,
6837 IRExpr
* next
, IRJumpKind jk
, Int offsIP
,
6838 IREndness IEndianess
)
6840 if (vex_traceflags
& VEX_TRACE_VCODE
) {
6841 vex_printf( "\n-- PUT(%d) = ", offsIP
);
6843 vex_printf( "; exit-");
6848 PPCCondCode always
= mk_PPCCondCode( Pct_ALWAYS
, Pcf_NONE
);
6850 /* Case: boring transfer to known address */
6851 if (next
->tag
== Iex_Const
) {
6852 IRConst
* cdst
= next
->Iex
.Const
.con
;
6853 vassert(cdst
->tag
== (env
->mode64
? Ico_U64
:Ico_U32
));
6854 if (jk
== Ijk_Boring
|| jk
== Ijk_Call
) {
6855 /* Boring transfer to known address */
6856 PPCAMode
* amCIA
= PPCAMode_IR(offsIP
, hregPPC_GPR31(env
->mode64
));
6857 if (env
->chainingAllowed
) {
6858 /* .. almost always true .. */
6859 /* Skip the event check at the dst if this is a forwards
6863 ? (((Addr64
)cdst
->Ico
.U64
) > (Addr64
)env
->max_ga
)
6864 : (((Addr32
)cdst
->Ico
.U32
) > (Addr32
)env
->max_ga
);
6865 if (0) vex_printf("%s", toFastEP
? "X" : ".");
6866 addInstr(env
, PPCInstr_XDirect(
6867 env
->mode64
? (Addr64
)cdst
->Ico
.U64
6868 : (Addr64
)cdst
->Ico
.U32
,
6869 amCIA
, always
, toFastEP
));
6871 /* .. very occasionally .. */
6872 /* We can't use chaining, so ask for an assisted transfer,
6873 as that's the only alternative that is allowable. */
6874 HReg r
= iselWordExpr_R(env
, next
, IEndianess
);
6875 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, always
,
6882 /* Case: call/return (==boring) transfer to any address */
6884 case Ijk_Boring
: case Ijk_Ret
: case Ijk_Call
: {
6885 HReg r
= iselWordExpr_R(env
, next
, IEndianess
);
6886 PPCAMode
* amCIA
= PPCAMode_IR(offsIP
, hregPPC_GPR31(env
->mode64
));
6887 if (env
->chainingAllowed
) {
6888 addInstr(env
, PPCInstr_XIndir(r
, amCIA
, always
));
6890 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, always
,
6899 /* Case: assisted transfer to arbitrary address */
6901 /* Keep this list in sync with that for Ist_Exit above */
6909 case Ijk_Sys_syscall
:
6910 case Ijk_InvalICache
:
6912 HReg r
= iselWordExpr_R(env
, next
, IEndianess
);
6913 PPCAMode
* amCIA
= PPCAMode_IR(offsIP
, hregPPC_GPR31(env
->mode64
));
6914 addInstr(env
, PPCInstr_XAssisted(r
, amCIA
, always
, jk
));
6921 vex_printf( "\n-- PUT(%d) = ", offsIP
);
6923 vex_printf( "; exit-");
6926 vassert(0); // are we expecting any other kind?
6930 /*---------------------------------------------------------*/
6931 /*--- Insn selector top-level ---*/
6932 /*---------------------------------------------------------*/
6934 /* Translate an entire SB to ppc code. */
6935 HInstrArray
* iselSB_PPC ( const IRSB
* bb
,
6937 const VexArchInfo
* archinfo_host
,
6938 const VexAbiInfo
* vbi
,
6939 Int offs_Host_EvC_Counter
,
6940 Int offs_Host_EvC_FailAddr
,
6941 Bool chainingAllowed
,
6947 HReg hregLo
, hregMedLo
, hregMedHi
, hregHi
;
6949 UInt hwcaps_host
= archinfo_host
->hwcaps
;
6950 Bool mode64
= False
;
6951 UInt mask32
, mask64
;
6952 PPCAMode
*amCounter
, *amFailAddr
;
6953 IREndness IEndianess
;
6955 vassert(arch_host
== VexArchPPC32
|| arch_host
== VexArchPPC64
);
6956 mode64
= arch_host
== VexArchPPC64
;
6958 /* do some sanity checks,
6959 * Note: no 32-bit support for ISA 3.0
6961 mask32
= VEX_HWCAPS_PPC32_F
| VEX_HWCAPS_PPC32_V
6962 | VEX_HWCAPS_PPC32_FX
| VEX_HWCAPS_PPC32_GX
| VEX_HWCAPS_PPC32_VX
6963 | VEX_HWCAPS_PPC32_DFP
| VEX_HWCAPS_PPC32_ISA2_07
;
6965 mask64
= VEX_HWCAPS_PPC64_V
| VEX_HWCAPS_PPC64_FX
6966 | VEX_HWCAPS_PPC64_GX
| VEX_HWCAPS_PPC64_VX
| VEX_HWCAPS_PPC64_DFP
6967 | VEX_HWCAPS_PPC64_ISA2_07
| VEX_HWCAPS_PPC64_ISA3_0
;
6970 vassert((hwcaps_host
& mask32
) == 0);
6972 vassert((hwcaps_host
& mask64
) == 0);
6975 /* Check that the host's endianness is as expected. */
6976 vassert((archinfo_host
->endness
== VexEndnessBE
) ||
6977 (archinfo_host
->endness
== VexEndnessLE
));
6979 if (archinfo_host
->endness
== VexEndnessBE
)
6980 IEndianess
= Iend_BE
;
6982 IEndianess
= Iend_LE
;
6984 /* Make up an initial environment to use. */
6985 env
= LibVEX_Alloc_inline(sizeof(ISelEnv
));
6988 /* Are we being ppc32 or ppc64? */
6989 env
->mode64
= mode64
;
6991 /* Set up output code array. */
6992 env
->code
= newHInstrArray();
6994 /* Copy BB's type env. */
6995 env
->type_env
= bb
->tyenv
;
6997 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
6998 * change as we go along.
7000 * vregmap2 and vregmap3 are only used in 32 bit mode
7001 * for supporting I128 in 32-bit mode
7003 env
->n_vregmap
= bb
->tyenv
->types_used
;
7004 env
->vregmapLo
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7005 env
->vregmapMedLo
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7007 env
->vregmapMedHi
= NULL
;
7008 env
->vregmapHi
= NULL
;
7010 env
->vregmapMedHi
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7011 env
->vregmapHi
= LibVEX_Alloc_inline(env
->n_vregmap
* sizeof(HReg
));
7014 /* and finally ... */
7015 env
->chainingAllowed
= chainingAllowed
;
7016 env
->max_ga
= max_ga
;
7017 env
->hwcaps
= hwcaps_host
;
7018 env
->previous_rm
= NULL
;
7021 /* For each IR temporary, allocate a suitably-kinded virtual
7024 for (i
= 0; i
< env
->n_vregmap
; i
++) {
7025 hregLo
= hregMedLo
= hregMedHi
= hregHi
= INVALID_HREG
;
7026 switch (bb
->tyenv
->types
[i
]) {
7032 hregLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7034 hregLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7039 hregLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7041 hregLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7042 hregMedLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7047 hregLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7048 hregMedLo
= mkHReg(True
, HRcInt64
, 0, j
++);
7050 hregLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7051 hregMedLo
= mkHReg(True
, HRcInt32
, 0, j
++);
7052 hregMedHi
= mkHReg(True
, HRcInt32
, 0, j
++);
7053 hregHi
= mkHReg(True
, HRcInt32
, 0, j
++);
7058 hregLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7062 hregLo
= mkHReg(True
, HRcVec128
, 0, j
++);
7066 hregLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7069 hregLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7070 hregMedLo
= mkHReg(True
, HRcFlt64
, 0, j
++);
7073 ppIRType(bb
->tyenv
->types
[i
]);
7074 vpanic("iselBB(ppc): IRTemp type");
7076 env
->vregmapLo
[i
] = hregLo
;
7077 env
->vregmapMedLo
[i
] = hregMedLo
;
7079 env
->vregmapMedHi
[i
] = hregMedHi
;
7080 env
->vregmapHi
[i
] = hregHi
;
7085 /* The very first instruction must be an event check. */
7086 amCounter
= PPCAMode_IR(offs_Host_EvC_Counter
, hregPPC_GPR31(mode64
));
7087 amFailAddr
= PPCAMode_IR(offs_Host_EvC_FailAddr
, hregPPC_GPR31(mode64
));
7088 addInstr(env
, PPCInstr_EvCheck(amCounter
, amFailAddr
));
7090 /* Possibly a block counter increment (for profiling). At this
7091 point we don't know the address of the counter, so just pretend
7092 it is zero. It will have to be patched later, but before this
7093 translation is used, by a call to LibVEX_patchProfCtr. */
7095 addInstr(env
, PPCInstr_ProfInc());
7098 /* Ok, finally we can iterate over the statements. */
7099 for (i
= 0; i
< bb
->stmts_used
; i
++)
7100 iselStmt(env
, bb
->stmts
[i
], IEndianess
);
7102 iselNext(env
, bb
->next
, bb
->jumpkind
, bb
->offsIP
, IEndianess
);
7104 /* record the number of vregs we used. */
7105 env
->code
->n_vregs
= env
->vreg_ctr
;
7110 /*---------------------------------------------------------------*/
7111 /*--- end host_ppc_isel.c ---*/
7112 /*---------------------------------------------------------------*/