Add support for Iop_{Sar,Shr}8 on ppc. --expensive-definedness-checks=yes needs...
[valgrind.git] / VEX / priv / host_ppc_isel.c
blob750cf8d13c6b274a688675fc186d6ab60f4cad63
2 /*---------------------------------------------------------------*/
3 /*--- begin host_ppc_isel.c ---*/
4 /*---------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2004-2017 OpenWorks LLP
11 info@open-works.net
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
26 02110-1301, USA.
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"
38 #include "libvex.h"
40 #include "ir_match.h"
41 #include "main_util.h"
42 #include "main_globals.h"
43 #include "host_generic_regs.h"
44 #include "host_generic_simd64.h"
45 #include "host_ppc_defs.h"
47 /* GPR register class for ppc32/64 */
48 #define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
51 /*---------------------------------------------------------*/
52 /*--- Register Usage Conventions ---*/
53 /*---------------------------------------------------------*/
55 Integer Regs
56 ------------
57 GPR0 Reserved
58 GPR1 Stack Pointer
59 GPR2 not used - TOC pointer
60 GPR3:10 Allocateable
61 GPR11 if mode64: not used - calls by ptr / env ptr for some langs
62 GPR12 if mode64: not used - exceptions / global linkage code
63 GPR13 not used - Thread-specific pointer
64 GPR14:28 Allocateable
65 GPR29 Unused by us (reserved for the dispatcher)
66 GPR30 AltiVec temp spill register
67 GPR31 GuestStatePointer
69 Of Allocateable regs:
70 if (mode64)
71 GPR3:10 Caller-saved regs
72 else
73 GPR3:12 Caller-saved regs
74 GPR14:29 Callee-saved regs
76 GPR3 [Return | Parameter] - carrying reg
77 GPR4:10 Parameter-carrying regs
80 Floating Point Regs
81 -------------------
82 FPR0:31 Allocateable
84 FPR0 Caller-saved - scratch reg
85 if (mode64)
86 FPR1:13 Caller-saved - param & return regs
87 else
88 FPR1:8 Caller-saved - param & return regs
89 FPR9:13 Caller-saved regs
90 FPR14:31 Callee-saved regs
93 Vector Regs (on processors with the VMX feature)
94 -----------
95 VR0-VR1 Volatile scratch registers
96 VR2-VR13 Volatile vector parameters registers
97 VR14-VR19 Volatile scratch registers
98 VR20-VR31 Non-volatile registers
99 VRSAVE Non-volatile 32-bit register
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
112 prior to them.
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 -------------------------------------------------------------
123 fmr[.] if . n n
124 fneg[.] if . n n
125 fabs[.] if . n n
126 fnabs[.] if . n n
128 fadd[.] if . y y
129 fadds[.] if . y y
130 fcfid[.] (Si64->dbl) if . y y
131 fcfidU[.] (Ui64->dbl) if . y y
132 fcfids[.] (Si64->sngl) if . Y Y
133 fcfidus[.] (Ui64->sngl) if . Y Y
134 fcmpo (cmp, result n n n
135 fcmpu to crfD) n n n
136 fctid[.] (dbl->i64) if . ->undef y
137 fctidz[.] (dbl->i64) if . ->undef rounds-to-zero
138 fctiw[.] (dbl->i32) if . ->undef y
139 fctiwz[.] (dbl->i32) if . ->undef rounds-to-zero
140 fdiv[.] if . y y
141 fdivs[.] if . y y
142 fmadd[.] if . y y
143 fmadds[.] if . y y
144 fmsub[.] if . y y
145 fmsubs[.] if . y y
146 fmul[.] if . y y
147 fmuls[.] if . y y
149 (note: for fnm*, rounding happens before final negation)
150 fnmadd[.] if . y y
151 fnmadds[.] if . y y
152 fnmsub[.] if . y y
153 fnmsubs[.] if . y y
155 fre[.] if . y y
156 fres[.] if . y y
158 frsqrte[.] if . y apparently not
160 fsqrt[.] if . y y
161 fsqrts[.] if . y y
162 fsub[.] if . y y
163 fsubs[.] if . y y
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
171 in future)
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
181 main FP insns
183 A single precision store truncates/denormalises the in-register value,
184 but does not round it. This is so that flds followed by fsts is
185 always the identity.
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 /*---------------------------------------------------------*/
218 /*--- ISelEnv ---*/
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,
225 and does not change.
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)
239 of the IRTemp.
240 - vregmapHi is also only for dealing with Ity_I128 temps
241 in 32 bit mode. It holds the most significant bits
242 (127:96 in Intel numbering) of the IRTemp.
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.
272 typedef
273 struct {
274 /* Constant -- are set at the start and do not change. */
275 IRTypeEnv* type_env;
276 // 64-bit mode 32-bit mode
277 HReg* vregmapLo; // Low 64-bits [63:0] Low 32-bits [31:0]
278 HReg* vregmapMedLo; // high 64-bits[127:64] Next 32-bits [63:32]
279 HReg* vregmapMedHi; // unused Next 32-bits [95:64]
280 HReg* vregmapHi; // unused highest 32-bits [127:96]
281 Int n_vregmap;
283 /* 27 Jan 06: Not currently used, but should be */
284 UInt hwcaps;
286 Bool mode64;
288 const VexAbiInfo* vbi; // unused
290 Bool chainingAllowed;
291 Addr64 max_ga;
293 /* These are modified as we go along. */
294 HInstrArray* code;
295 Int vreg_ctr;
297 IRExpr* previous_rm;
299 ISelEnv;
302 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
304 vassert(tmp >= 0);
305 vassert(tmp < env->n_vregmap);
306 return env->vregmapLo[tmp];
309 static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO,
310 ISelEnv* env, IRTemp tmp )
312 vassert(tmp >= 0);
313 vassert(tmp < env->n_vregmap);
314 vassert(! hregIsInvalid(env->vregmapMedLo[tmp]));
315 *vrLO = env->vregmapLo[tmp];
316 *vrHI = env->vregmapMedLo[tmp];
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);
324 vassert(tmp >= 0);
325 vassert(tmp < env->n_vregmap);
326 vassert(! hregIsInvalid(env->vregmapMedLo[tmp]));
327 *vrHi = env->vregmapHi[tmp];
328 *vrMedHi = env->vregmapMedHi[tmp];
329 *vrMedLo = env->vregmapMedLo[tmp];
330 *vrLo = env->vregmapLo[tmp];
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);
338 vex_printf("\n");
342 static HReg newVRegI ( ISelEnv* env )
344 HReg reg
345 = mkHReg(True/*vreg*/, HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
346 env->vreg_ctr++;
347 return reg;
350 static HReg newVRegF ( ISelEnv* env )
352 HReg reg = mkHReg(True/*vreg*/, HRcFlt64, 0/*enc*/, env->vreg_ctr);
353 env->vreg_ctr++;
354 return reg;
357 static HReg newVRegV ( ISelEnv* env )
359 HReg reg = mkHReg(True/*vreg*/, HRcVec128, 0/*enc*/, env->vreg_ctr);
360 env->vreg_ctr++;
361 return reg;
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
378 integer registers.
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,
438 IRType xferTy,
439 IREndness IEndianess );
440 static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, const IRExpr* e,
441 IRType xferTy,
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)));
554 // add 16
555 addInstr(env, PPCInstr_Alu( Palu_ADD, r, r,
556 PPCRH_Imm(True,toUShort(16)) ));
557 // mask to quadword
558 addInstr(env,
559 PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64));
560 addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16)));
561 return r;
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 ));
585 // load as float
586 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
588 add_to_sp( env, 16 ); // Reset SP
589 return fr_dst;
592 /* Load I64 reg to fp reg */
593 static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src )
595 HReg fr_dst = newVRegF(env);
596 PPCAMode *am_addr0;
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) );
604 // store as Ity_I64
605 addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 ));
607 // load as float
608 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
610 add_to_sp( env, 16 ); // Reset SP
611 return fr_dst;
615 /* Given an amode, return one which references 4 bytes further
616 along. */
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;
624 } else {
625 vpanic("advance4(ppc,host)");
627 return am4;
631 /* Given a guest-state array descriptor, an index expression and a
632 bias, generate a PPCAMode pointing at the relevant piece of
633 guest state. */
634 static
635 PPCAMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
636 IRExpr* off, Int bias, IREndness IEndianess )
638 HReg rtmp, roff;
639 Int elemSz = sizeofIRType(descr->elemTy);
640 Int nElems = descr->nElems;
641 Int shift = 0;
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)");
649 switch (elemSz) {
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)
663 andi %tmp, nElems-1
664 sldi %tmp, shift
665 addi %tmp, %tmp, base
666 ... Baseblockptr + %tmp ...
668 roff = iselWordExpr_R(env, off, IEndianess);
669 rtmp = newVRegI(env);
670 addInstr(env, PPCInstr_Alu(
671 Palu_ADD,
672 rtmp, roff,
673 PPCRH_Imm(True/*signed*/, toUShort(bias))));
674 addInstr(env, PPCInstr_Alu(
675 Palu_AND,
676 rtmp, rtmp,
677 PPCRH_Imm(False/*unsigned*/, toUShort(nElems-1))));
678 addInstr(env, PPCInstr_Shft(
679 Pshft_SHL,
680 env->mode64 ? False : True/*F:64-bit, T:32-bit shift*/,
681 rtmp, rtmp,
682 PPCRH_Imm(False/*unsigned*/, toUShort(shift))));
683 addInstr(env, PPCInstr_Alu(
684 Palu_ADD,
685 rtmp, rtmp,
686 PPCRH_Imm(True/*signed*/, toUShort(descr->base))));
687 return
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).
701 static
702 Bool mightRequireFixedRegs ( IRExpr* e )
704 switch (e->tag) {
705 case Iex_RdTmp: case Iex_Const: case Iex_Get:
706 return False;
707 default:
708 return True;
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. */
720 static
721 void doHelperCall ( /*OUT*/UInt* stackAdjustAfterCall,
722 /*OUT*/RetLoc* retloc,
723 ISelEnv* env,
724 IRExpr* guard,
725 IRCallee* cee, IRType retTy, IRExpr** args,
726 IREndness IEndianess)
728 PPCCondCode cc;
729 HReg argregs[PPC_N_REGPARMS];
730 HReg tmpregs[PPC_N_REGPARMS];
731 Bool go_fast;
732 Int n_args, i, argreg;
733 UInt argiregs;
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. */
742 UInt nVECRETs = 0;
743 UInt nGSPTRs = 0;
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
776 argument.
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
790 registers.
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
802 ignore it. */
804 n_args = 0;
805 for (i = 0; args[i]; i++)
806 n_args++;
808 if (n_args > PPC_N_REGPARMS) {
809 vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
810 // PPC_N_REGPARMS
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);
825 argiregs = 0;
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
833 (wow) appear. */
835 go_fast = True;
837 /* We'll need space on the stack for the return value. Avoid
838 possible complications with nested calls by using the slow
839 scheme. */
840 if (retTy == Ity_V128 || retTy == Ity_V256)
841 go_fast = False;
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) {
847 /* unconditional */
848 } else {
849 /* Not manifestly unconditional -- be conservative. */
850 go_fast = False;
854 if (go_fast) {
855 for (i = 0; i < n_args; i++) {
856 IRExpr* arg = args[i];
857 if (UNLIKELY(arg->tag == Iex_GSPTR)) {
858 /* that's OK */
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
863 filtered it out. */
864 vpanic("doHelperCall(PPC): invalid IR");
866 else if (mightRequireFixedRegs(arg)) {
867 go_fast = False;
868 break;
873 /* At this point the scheme to use has been established. Generate
874 code to get the arg values into the argument rregs. */
876 if (go_fast) {
878 /* FAST SCHEME */
879 argreg = 0;
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) ));
889 argreg++;
890 } else {
891 vassert(arg->tag != Iex_VECRET);
892 IRType ty = typeOfIRExpr(env->type_env, arg);
893 vassert(ty == Ity_I32 || ty == Ity_I64);
894 if (!mode64) {
895 if (ty == Ity_I32) {
896 argiregs |= (1 << (argreg+3));
897 addInstr(env,
898 mk_iMOVds_RR( argregs[argreg],
899 iselWordExpr_R(env, arg,
900 IEndianess) ));
901 } else { // Ity_I64 in 32-bit mode
902 HReg rHi, rLo;
903 if ((argreg%2) == 1)
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));
913 } else { // mode64
914 argiregs |= (1 << (argreg+3));
915 addInstr(env, mk_iMOVds_RR( argregs[argreg],
916 iselWordExpr_R(env, arg,
917 IEndianess) ));
919 argreg++;
920 } /* if (arg == IRExprP__BBPR) */
923 /* Fast scheme only applies for unconditional calls. Hence: */
924 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
926 } else {
928 /* SLOW SCHEME; move via temporaries */
929 argreg = 0;
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) {
948 vassert(0); //ATC
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) ));
963 nGSPTRs++;
965 else if (UNLIKELY(arg->tag == Iex_VECRET)) {
966 /* We stashed the address of the return slot earlier, so just
967 retrieve it now. */
968 vassert(!hregIsInvalid(r_vecRetAddr));
969 tmpregs[i] = r_vecRetAddr;
970 nVECRETs++;
972 else {
973 IRType ty = typeOfIRExpr(env->type_env, arg);
974 vassert(ty == Ity_I32 || ty == Ity_I64);
975 if (!mode64) {
976 if (ty == Ity_I32) {
977 tmpregs[argreg] = iselWordExpr_R(env, arg, IEndianess);
978 } else { // Ity_I64 in 32-bit mode
979 HReg rHi, rLo;
980 if ((argreg%2) == 1)
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;
988 } else { // mode64
989 tmpregs[argreg] = iselWordExpr_R(env, arg, IEndianess);
992 argreg++;
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
998 guard is 1:Bit. */
999 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
1000 if (guard) {
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 */
1005 } else {
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
1013 continue;
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);
1026 } else {
1027 vassert(nVECRETs == 0);
1030 vassert(nGSPTRs == 0 || nGSPTRs == 1);
1032 vassert(*stackAdjustAfterCall == 0);
1033 vassert(is_RetLoc_INVALID(*retloc));
1034 switch (retTy) {
1035 case Ity_INVALID:
1036 /* Function doesn't return a value. */
1037 *retloc = mk_RetLoc_simple(RLPri_None);
1038 break;
1039 case Ity_I64:
1040 *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
1041 break;
1042 case Ity_I32: case Ity_I16: case Ity_I8:
1043 *retloc = mk_RetLoc_simple(RLPri_Int);
1044 break;
1045 case Ity_V128:
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;
1050 break;
1051 case Ity_V256:
1052 vassert(0); // ATC
1053 /* Ditto */
1054 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 512);
1055 *stackAdjustAfterCall = 1024;
1056 break;
1057 default:
1058 /* IR can denote other possible return types, but we don't
1059 handle those here. */
1060 vassert(0);
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 */
1077 //static
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
1087 // */
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
1091 // } else {
1092 // fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1093 // }
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
1104 to zero | 001 | 011
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 ) ) );
1134 return r_rmPPC;
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.
1167 static
1168 void _set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode, Bool dfp_rm,
1169 IREndness IEndianess )
1171 HReg fr_src = newVRegF(env);
1172 HReg r_src;
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);
1183 return;
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) );
1195 // gpr -> fpr
1196 if (env->mode64) {
1197 if (dfp_rm) {
1198 HReg r_tmp1 = newVRegI( env );
1199 addInstr( 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 );
1203 } else {
1204 fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
1206 } else {
1207 if (dfp_rm) {
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 );
1211 } else {
1212 fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1216 // Move to FPSCR
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);
1232 static
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)
1240 return False;
1242 vassert(mode->Iex.Const.con->tag == Ico_U32);
1243 vassert(mode->Iex.Const.con->Ico.U32 == 0x8);
1244 return True;
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));
1257 return 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));
1267 return dst;
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 )
1280 HReg r_src;
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)));
1299 addInstr(env,
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) );
1303 return dst;
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)));
1310 addInstr(env,
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) );
1314 return dst;
1316 /* simplest form: -16:15 inclusive */
1317 addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6)));
1318 return dst;
1321 /* no luck; use the Slow way. */
1322 r_src = newVRegI(env);
1323 addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64));
1325 else {
1326 r_src = ri->Pri.Reg;
1330 /* Store r_src multiple times (sz dependent); then load the dest vector. */
1331 HReg r_aligned16;
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 );
1338 Int i;
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
1351 return dst;
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));
1378 return vIsNan;
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
1392 later in the game.
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
1398 if necessary.
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 ... */
1406 # if 0
1407 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1408 # endif
1410 vassert(hregClass(r) == HRcGPR(env->mode64));
1411 vassert(hregIsVirtual(r));
1412 return 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;
1420 MatchInfo mi;
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));
1427 switch (e->tag) {
1429 /* --------- TEMP --------- */
1430 case Iex_RdTmp:
1431 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1433 /* --------- LOAD --------- */
1434 case Iex_Load: {
1435 HReg r_dst;
1436 PPCAMode* am_addr;
1437 if (e->Iex.Load.end != IEndianess)
1438 goto irreducible;
1439 r_dst = newVRegI(env);
1440 am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/,
1441 IEndianess );
1442 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1443 r_dst, am_addr, mode64 ));
1444 return r_dst;
1445 /*NOTREACHED*/
1448 /* --------- BINARY OP --------- */
1449 case Iex_Binop: {
1450 PPCAluOp aluOp;
1451 PPCShftOp shftOp;
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;
1465 default:
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 */
1475 switch (aluOp) {
1476 case Palu_ADD: case Palu_SUB:
1477 ri_srcR = iselWordExpr_RH(env, True/*signed*/,
1478 e->Iex.Binop.arg2, IEndianess);
1479 break;
1480 case Palu_AND: case Palu_OR: case Palu_XOR:
1481 ri_srcR = iselWordExpr_RH(env, False/*signed*/,
1482 e->Iex.Binop.arg2, IEndianess);
1483 break;
1484 default:
1485 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
1487 addInstr(env, PPCInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
1488 return r_dst;
1491 /* a shift? */
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;
1499 default:
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 */
1508 switch (shftOp) {
1509 case Pshft_SHL: case Pshft_SHR: case Pshft_SAR:
1510 if (!mode64)
1511 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2, IEndianess);
1512 else
1513 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2, IEndianess);
1514 break;
1515 default:
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*/,
1526 tmp, r_srcL, amt));
1527 addInstr(env, PPCInstr_Shft(shftOp,
1528 True/*32bit shift*/,
1529 tmp, tmp, amt));
1530 r_srcL = tmp;
1533 /* Only 64 expressions need 64bit shifts,
1534 32bit shifts are fine for all others */
1535 if (ty == Ity_I64) {
1536 vassert(mode64);
1537 addInstr(env, PPCInstr_Shft(shftOp, False/*64bit shift*/,
1538 r_dst, r_srcL, ri_srcR));
1539 } else {
1540 addInstr(env, PPCInstr_Shft(shftOp, True/*32bit shift*/,
1541 r_dst, r_srcL, ri_srcR));
1543 return r_dst;
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);
1555 addInstr( env,
1556 PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivU32E )
1557 || ( e->Iex.Binop.op == Iop_DivS32E ) ) ? True
1558 : False,
1559 syned,
1560 True/*32bit div*/,
1561 r_dst,
1562 r_srcL,
1563 r_srcR ) );
1564 return r_dst;
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);
1573 vassert(mode64);
1574 addInstr( env,
1575 PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivS64E )
1576 || ( e->Iex.Binop.op
1577 == Iop_DivU64E ) ) ? True
1578 : False,
1579 syned,
1580 False/*64bit div*/,
1581 r_dst,
1582 r_srcL,
1583 r_srcR ) );
1584 return r_dst;
1587 /* No? Anyone for a mul? */
1588 if (e->Iex.Binop.op == Iop_Mul32
1589 || e->Iex.Binop.op == Iop_Mul64) {
1590 Bool syned = False;
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));
1597 return r_dst;
1600 /* 32 x 32 -> 64 multiply */
1601 if (mode64
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)));
1620 return r_dst;
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,
1630 IEndianess);
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)));
1636 return dst;
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,
1645 IEndianess);
1646 vassert(mode64);
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)));
1652 return dst;
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)));
1664 return rdst;
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);
1673 vassert(mode64);
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,
1679 PPCRH_Reg(msk) ));
1680 addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst,
1681 PPCRH_Reg(r_Tmp) ));
1682 return r_dst;
1685 if ((e->Iex.Binop.op == Iop_CmpF64) ||
1686 (e->Iex.Binop.op == Iop_CmpD64) ||
1687 (e->Iex.Binop.op == Iop_CmpD128)) {
1688 HReg fr_srcL;
1689 HReg fr_srcL_lo;
1690 HReg fr_srcR;
1691 HReg fr_srcR_lo;
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,
1711 IEndianess);
1712 iselDfp128Expr(&fr_srcR, &fr_srcR_lo, env, e->Iex.Binop.arg2,
1713 IEndianess);
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 --------------------------
1723 UN | 0x1 | 0x45
1724 EQ | 0x2 | 0x40
1725 GT | 0x4 | 0x00
1726 LT | 0x8 | 0x01
1729 // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1730 addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1731 r_ccIR_b0, r_ccPPC,
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*/,
1740 r_ccIR_b2, r_ccPPC,
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*/,
1747 r_ccIR_b6, r_ccPPC,
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)));
1762 return r_ccIR;
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*/
1780 : False,
1781 True/*flt64*/,
1782 ftmp, fsrc));
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. */
1787 if (mode64)
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 );
1794 return idst;
1797 if (e->Iex.Binop.op == Iop_F64toI64S || e->Iex.Binop.op == Iop_F64toI64U ) {
1798 if (mode64) {
1799 HReg r1 = StackFramePtr(env->mode64);
1800 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1801 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2,
1802 IEndianess);
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
1812 : False,
1813 True, ftmp, fsrc));
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 );
1820 return idst;
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 );
1842 return idst;
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,
1855 IEndianess);
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 );
1863 return idst;
1865 break;
1868 /* --------- UNARY OP --------- */
1869 case Iex_Unop: {
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)));
1881 return r_dst;
1884 /* 16Uto32(LDbe:I16(expr32)) */
1886 DECLARE_PATTERN(p_LDbe16_then_16Uto32);
1887 DEFINE_PATTERN(p_LDbe16_then_16Uto32,
1888 unop(Iop_16Uto32,
1889 IRExpr_Load(IEndianess,Ity_I16,bind(0))) );
1890 if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
1891 HReg r_dst = newVRegI(env);
1892 PPCAMode* amode
1893 = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/,
1894 IEndianess );
1895 addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
1896 return r_dst;
1900 switch (op_unop) {
1901 case Iop_8Uto16:
1902 case Iop_8Uto32:
1903 case Iop_8Uto64:
1904 case Iop_16Uto32:
1905 case Iop_16Uto64: {
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)));
1912 return r_dst;
1914 case Iop_32Uto64: {
1915 HReg r_dst = newVRegI(env);
1916 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1917 vassert(mode64);
1918 addInstr(env,
1919 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1920 r_dst, r_src, PPCRH_Imm(False,32)));
1921 addInstr(env,
1922 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1923 r_dst, r_dst, PPCRH_Imm(False,32)));
1924 return r_dst;
1926 case Iop_8Sto16:
1927 case Iop_8Sto32:
1928 case Iop_16Sto32: {
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);
1932 addInstr(env,
1933 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1934 r_dst, r_src, PPCRH_Imm(False,amt)));
1935 addInstr(env,
1936 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1937 r_dst, r_dst, PPCRH_Imm(False,amt)));
1938 return r_dst;
1940 case Iop_8Sto64:
1941 case Iop_16Sto64: {
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);
1945 vassert(mode64);
1946 addInstr(env,
1947 PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1948 r_dst, r_src, PPCRH_Imm(False,amt)));
1949 addInstr(env,
1950 PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1951 r_dst, r_dst, PPCRH_Imm(False,amt)));
1952 return r_dst;
1954 case Iop_32Sto64: {
1955 HReg r_dst = newVRegI(env);
1956 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1957 vassert(mode64);
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. */
1960 addInstr(env,
1961 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1962 r_dst, r_src, PPCRH_Imm(False,0)));
1963 return r_dst;
1965 case Iop_Not8:
1966 case Iop_Not16:
1967 case Iop_Not32:
1968 case Iop_Not64: {
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));
1973 return r_dst;
1975 case Iop_64HIto32: {
1976 if (!mode64) {
1977 HReg rHi, rLo;
1978 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
1979 return rHi; /* and abandon rLo .. poor wee thing :-) */
1980 } else {
1981 HReg r_dst = newVRegI(env);
1982 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1983 addInstr(env,
1984 PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1985 r_dst, r_src, PPCRH_Imm(False,32)));
1986 return r_dst;
1989 case Iop_64to32: {
1990 if (!mode64) {
1991 HReg rHi, rLo;
1992 iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
1993 return rLo; /* similar stupid comment to the above ... */
1994 } else {
1995 /* This is a no-op. */
1996 return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1999 case Iop_64to16: {
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 */
2005 case Iop_16HIto8:
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);
2010 addInstr(env,
2011 PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
2012 r_dst, r_src, PPCRH_Imm(False,shift)));
2013 return r_dst;
2015 case Iop_128HIto64:
2016 if (mode64) {
2017 HReg rHi, rLo;
2018 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
2019 return rHi; /* and abandon rLo .. poor wee thing :-) */
2021 break;
2022 case Iop_128to64:
2023 if (mode64) {
2024 HReg rHi, rLo;
2025 iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
2026 return rLo; /* similar stupid comment to the above ... */
2028 break;
2029 case Iop_1Uto64:
2030 case Iop_1Uto32:
2031 case Iop_1Uto8:
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));
2036 return r_dst;
2038 break;
2039 case Iop_1Sto8:
2040 case Iop_1Sto16:
2041 case Iop_1Sto32: {
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));
2046 addInstr(env,
2047 PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
2048 r_dst, r_dst, PPCRH_Imm(False,31)));
2049 addInstr(env,
2050 PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2051 r_dst, r_dst, PPCRH_Imm(False,31)));
2052 return r_dst;
2054 case Iop_1Sto64:
2055 if (mode64) {
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)));
2064 return r_dst;
2066 break;
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.
2072 HReg r_src, r_dst;
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)
2076 goto irreducible;
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));
2081 return r_dst;
2084 //case Iop_Ctz32:
2085 case Iop_CtzNat32:
2086 //case Iop_Ctz64:
2087 case Iop_CtzNat64:
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;
2093 Int WS = 64;
2094 if (op_unop == Iop_Ctz32 || op_unop == Iop_CtzNat32) {
2095 op_clz = Pun_CLZ32;
2096 WS = 32;
2098 /* Compute ctz(arg) = wordsize - clz(~arg & (arg - 1)), thusly:
2099 t1 = arg - 1
2100 t2 = not arg
2101 t2 = t2 & t1
2102 t2 = clz t2
2103 t1 = WS
2104 t2 = t1 - t2
2105 // result in t2
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)));
2116 return 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.
2123 if (mode64) {
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));
2127 return r_dst;
2129 // We don't expect to be required to handle this in 32-bit mode.
2130 break;
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));
2148 return r_dst;
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
2160 Mask = 00FF00FF
2161 nMask = not Mask
2162 tHi = and r, Mask
2163 tHi = shl tHi, 8
2164 tLo = and r, nMask
2165 tLo = shr tLo, 8
2166 r = or tHi, tLo // now r has order BADC
2167 and repeat for 16 bit chunks ..
2168 Mask = 0000FFFF
2169 nMask = not Mask
2170 tHi = and r, Mask
2171 tHi = shl tHi, 16
2172 tLo = and r, nMask
2173 tLo = shr tLo, 16
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*/,
2190 rtHi, rtHi,
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*/,
2194 rtLo, rtLo,
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*/,
2203 rtHi, rtHi,
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*/,
2207 rtLo, rtLo,
2208 PPCRH_Imm(False/*!signed imm*/, 16)));
2209 addInstr(env, PPCInstr_Alu(Palu_OR, rr, rtHi, PPCRH_Reg(rtLo)));
2210 return rr;
2213 case Iop_Left8:
2214 case Iop_Left16:
2215 case Iop_Left32:
2216 case Iop_Left64: {
2217 HReg r_src, r_dst;
2218 if (op_unop == Iop_Left64 && !mode64)
2219 goto irreducible;
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)));
2224 return r_dst;
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)));
2234 return r_dst;
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)));
2245 return r_dst;
2248 case Iop_V128to32: {
2249 HReg r_aligned16;
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;
2268 else
2269 am_off_word0 = PPCAMode_IR( 12,r_aligned16 );
2271 // store vec, load low word to dst
2272 addInstr(env,
2273 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2274 addInstr(env,
2275 PPCInstr_Load( 4, dst, am_off_word0, mode64 ));
2277 add_to_sp( env, 32 ); // Reset SP
2278 return dst;
2281 case Iop_V128to64:
2282 case Iop_V128HIto64:
2283 if (mode64) {
2284 HReg r_aligned16;
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
2296 addInstr(env,
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;
2301 else
2302 am_off_arg = am_off0;
2303 } else {
2304 if (op_unop == Iop_V128HIto64)
2305 am_off_arg = am_off0;
2306 else
2307 am_off_arg = am_off8;
2309 addInstr(env,
2310 PPCInstr_Load(
2311 8, dst,
2312 am_off_arg,
2313 mode64 ));
2315 add_to_sp( env, 32 ); // Reset SP
2316 return dst;
2318 break;
2319 case Iop_16to8:
2320 case Iop_32to8:
2321 case Iop_32to16:
2322 case Iop_64to8:
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
2328 pattern. */
2329 case Iop_ReinterpF64asI64:
2330 if (mode64) {
2331 PPCAMode *am_addr;
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) );
2338 // store as F64
2339 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2340 fr_src, am_addr ));
2341 // load as Ity_I64
2342 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2344 add_to_sp( env, 16 ); // Reset SP
2345 return r_dst;
2347 break;
2349 /* ReinterpF32asI32(e) */
2350 /* Given an IEEE754 float, produce an I32 with the same bit
2351 pattern. */
2352 case Iop_ReinterpF32asI32: {
2353 /* I believe this generates correct code for both 32- and
2354 64-bit hosts. */
2355 PPCAMode *am_addr;
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) );
2362 // store as F32
2363 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
2364 fr_src, am_addr ));
2365 // load as Ity_I32
2366 addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
2368 add_to_sp( env, 16 ); // Reset SP
2369 return r_dst;
2371 break;
2373 case Iop_ReinterpD64asI64:
2374 if (mode64) {
2375 PPCAMode *am_addr;
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) );
2382 // store as D64
2383 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2384 fr_src, am_addr ));
2385 // load as Ity_I64
2386 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2387 add_to_sp( env, 16 ); // Reset SP
2388 return r_dst;
2390 break;
2392 case Iop_BCDtoDPB: {
2393 /* the following is only valid in 64 bit mode */
2394 if (!mode64) break;
2396 PPCCondCode cc;
2397 UInt argiregs;
2398 HReg argregs[1];
2399 HReg r_dst = newVRegI(env);
2400 Int argreg;
2402 argiregs = 0;
2403 argreg = 0;
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,
2409 IEndianess) ) );
2411 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2412 if (IEndianess == Iend_LE) {
2413 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
2414 argiregs,
2415 mk_RetLoc_simple(RLPri_Int)) );
2416 } else {
2417 HWord* fdescr;
2418 fdescr = (HWord*)h_calc_BCDtoDPB;
2419 addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2420 argiregs,
2421 mk_RetLoc_simple(RLPri_Int)) );
2424 addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2425 return r_dst;
2428 case Iop_DPBtoBCD: {
2429 /* the following is only valid in 64 bit mode */
2430 if (!mode64) break;
2432 PPCCondCode cc;
2433 UInt argiregs;
2434 HReg argregs[1];
2435 HReg r_dst = newVRegI(env);
2436 Int argreg;
2438 argiregs = 0;
2439 argreg = 0;
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,
2445 IEndianess) ) );
2447 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2449 if (IEndianess == Iend_LE) {
2450 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
2451 argiregs,
2452 mk_RetLoc_simple(RLPri_Int) ) );
2453 } else {
2454 HWord* fdescr;
2455 fdescr = (HWord*)h_calc_DPBtoBCD;
2456 addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2457 argiregs,
2458 mk_RetLoc_simple(RLPri_Int) ) );
2461 addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2462 return r_dst;
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;
2474 HReg r_aligned16;
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));
2501 } else {
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));
2514 /* Fetch I64 */
2515 addInstr(env, PPCInstr_Load(8, dst, am_off0, mode64));
2517 add_to_sp( env, 32 ); // Reset SP
2518 return dst;
2521 default:
2522 break;
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 );
2539 return fr_dst;
2541 case Iop_ExtractExpD128: {
2542 HReg fr_dst = newVRegI(env);
2543 HReg r_srcHi;
2544 HReg r_srcLo;
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,
2549 IEndianess);
2550 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
2551 r_srcHi, r_srcLo));
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 );
2557 return fr_dst;
2559 default:
2560 break;
2563 break;
2566 /* --------- GET --------- */
2567 case Iex_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 ));
2575 return r_dst;
2577 break;
2580 case Iex_GetI: {
2581 PPCAMode* src_am
2582 = genGuestArrayOffset( env, e->Iex.GetI.descr,
2583 e->Iex.GetI.ix, e->Iex.GetI.bias,
2584 IEndianess );
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 ));
2589 return r_dst;
2591 if ((!mode64) && ty == Ity_I32) {
2592 addInstr(env, PPCInstr_Load( toUChar(4),
2593 r_dst, src_am, mode64 ));
2594 return r_dst;
2596 break;
2599 /* --------- CCALL --------- */
2600 case Iex_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)))
2606 goto irreducible;
2608 /* Marshal args, do the call, clear stack. */
2609 UInt addToSp = 0;
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,
2613 IEndianess );
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)));
2621 return r_dst;
2624 /* --------- LITERAL --------- */
2625 /* 32/16/8-bit literals */
2626 case Iex_Const: {
2627 Long l;
2628 HReg r_dst = newVRegI(env);
2629 IRConst* con = e->Iex.Const.con;
2630 switch (con->tag) {
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));
2639 return r_dst;
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));
2653 return r_dst;
2655 break;
2658 default:
2659 break;
2660 } /* switch (e->tag) */
2663 /* We get here if no pattern matched. */
2664 irreducible:
2665 ppIRExpr(e);
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 */
2688 return u == v;
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 */
2698 return u == v;
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;
2709 switch (am->tag) {
2710 case Pam_IR:
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) );
2716 case Pam_RR:
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) );
2721 default:
2722 vpanic("sane_AMode: unknown ppc amode tag");
2726 static
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));
2732 return 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);
2741 if (env->mode64) {
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)
2761 : True)
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,
2766 IEndianess) );
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 );
2777 } else {
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,
2790 IEndianess) );
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
2816 need be. */
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 ... */
2823 switch (ri->tag) {
2824 case Prh_Imm:
2825 vassert(ri->Prh.Imm.syned == syned);
2826 if (syned)
2827 vassert(ri->Prh.Imm.imm16 != 0x8000);
2828 return ri;
2829 case Prh_Reg:
2830 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2831 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2832 return ri;
2833 default:
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 )
2842 ULong u;
2843 Long l;
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? */
2852 switch (con->tag) {
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)");
2861 l = (Long)u;
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 ... */
2888 switch (ri->tag) {
2889 case Pri_Imm:
2890 return ri;
2891 case Pri_Reg:
2892 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2893 vassert(hregIsVirtual(ri->Pri.Reg));
2894 return ri;
2895 default:
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 )
2904 Long l;
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;
2912 switch (con->tag) {
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 )
2937 PPCRH* ri;
2938 vassert(!env->mode64);
2939 ri = iselWordExpr_RH5u_wrk(env, e, IEndianess);
2940 /* sanity checks ... */
2941 switch (ri->tag) {
2942 case Prh_Imm:
2943 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2944 vassert(!ri->Prh.Imm.syned);
2945 return ri;
2946 case Prh_Reg:
2947 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2948 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2949 return ri;
2950 default:
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 )
2984 PPCRH* ri;
2985 vassert(env->mode64);
2986 ri = iselWordExpr_RH6u_wrk(env, e, IEndianess);
2987 /* sanity checks ... */
2988 switch (ri->tag) {
2989 case Prh_Imm:
2990 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2991 vassert(!ri->Prh.Imm.syned);
2992 return ri;
2993 case Prh_Reg:
2994 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2995 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2996 return ri;
2997 default:
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 )
3039 vassert(e);
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 );
3052 /* Not1(...) */
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);
3057 return cond;
3060 /* --- patterns rooted at: 32to1 or 64to1 --- */
3062 /* 32to1, 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 --- */
3077 /* CmpNEZ8(x) */
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 --- */
3093 /* CmpNEZ32(x) */
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* --- */
3104 /* Cmp*32*(x,y) */
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*/,
3117 7/*cr*/, r1, ri2));
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 --- */
3132 /* CmpNEZ64 */
3133 if (e->tag == Iex_Unop
3134 && e->Iex.Unop.op == Iop_CmpNEZ64) {
3135 if (!env->mode64) {
3136 HReg hi, lo;
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 );
3143 } else { // mode64
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* --- */
3153 /* Cmp*64*(x,y) */
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*/,
3167 7/*cr*/, r1, ri2));
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 --- */
3180 /* CmpNE8(x,0) */
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 );
3195 /* var */
3196 if (e->tag == Iex_RdTmp) {
3197 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp);
3198 HReg src_masked = newVRegI(env);
3199 addInstr(env,
3200 PPCInstr_Alu(Palu_AND, src_masked,
3201 r_src, PPCRH_Imm(False,1)));
3202 addInstr(env,
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);
3209 ppIRExpr(e);
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
3222 caller. */
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);
3229 # if 0
3230 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3231 # endif
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;
3244 vassert(e);
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);
3250 return;
3253 /* 128-bit GET */
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));
3263 *rHi = tHi;
3264 *rLo = tLo;
3265 return;
3268 /* --------- BINARY ops --------- */
3269 if (e->tag == Iex_Binop) {
3270 switch (e->Iex.Binop.op) {
3271 /* 64 x 64 -> 128 multiply */
3272 case Iop_MullU64:
3273 case Iop_MullS64: {
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));
3285 *rHi = tHi;
3286 *rLo = tLo;
3287 return;
3290 /* 64HLto128(e1,e2) */
3291 case Iop_64HLto128:
3292 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3293 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3294 return;
3295 default:
3296 break;
3298 } /* if (e->tag == Iex_Binop) */
3301 /* --------- UNARY ops --------- */
3302 if (e->tag == Iex_Unop) {
3303 switch (e->Iex.Unop.op) {
3304 default:
3305 break;
3307 } /* if (e->tag == Iex_Unop) */
3309 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
3310 ppIRExpr(e);
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);
3326 # if 0
3327 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3328 # endif
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 )
3344 vassert(e);
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);
3350 return;
3353 if (e->tag == Iex_Binop) {
3355 IROp op_binop = e->Iex.Binop.op;
3356 switch (op_binop) {
3357 case Iop_64HLto128:
3358 iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess);
3359 iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess);
3360 return;
3361 default:
3362 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3363 op_binop);
3364 break;
3368 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
3369 return;
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
3376 caller. */
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);
3384 # if 0
3385 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3386 # endif
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 )
3398 vassert(e);
3399 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
3401 /* 64-bit load */
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*/) );
3413 *rHi = tHi;
3414 *rLo = tLo;
3415 return;
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*/));
3428 *rHi = tHi;
3429 *rLo = tLo;
3430 return;
3433 /* read 64-bit IRTemp */
3434 if (e->tag == Iex_RdTmp) {
3435 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3436 return;
3439 /* 64-bit GET */
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*/ ));
3448 *rHi = tHi;
3449 *rLo = tLo;
3450 return;
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. */
3465 UInt addToSp = 0;
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,
3469 IEndianess );
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)));
3478 *rHi = r_dst;
3479 *rLo = r_dst;
3480 return;
3483 /* 64-bit ITE */
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)));
3495 *rHi = tHi;
3496 *rLo = tLo;
3497 return;
3500 /* --------- BINARY ops --------- */
3501 if (e->tag == Iex_Binop) {
3502 IROp op_binop = e->Iex.Binop.op;
3503 switch (op_binop) {
3504 /* 32 x 32 -> 64 multiply */
3505 case Iop_MullU32:
3506 case Iop_MullS32: {
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,
3511 IEndianess);
3512 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2,
3513 IEndianess);
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));
3520 *rHi = tHi;
3521 *rLo = tLo;
3522 return;
3525 /* Or64/And64/Xor64 */
3526 case Iop_Or64:
3527 case Iop_And64:
3528 case Iop_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)));
3538 *rHi = tHi;
3539 *rLo = tLo;
3540 return;
3543 /* Add64 */
3544 case Iop_Add64: {
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*/,
3551 tLo, xLo, yLo));
3552 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
3553 tHi, xHi, yHi));
3554 *rHi = tHi;
3555 *rLo = tLo;
3556 return;
3559 /* 32HLto64(e1,e2) */
3560 case Iop_32HLto64:
3561 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3562 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3563 return;
3565 /* F64toI64[S|U] */
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,
3573 IEndianess);
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,
3583 True, ftmp, fsrc));
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 );
3591 *rHi = tHi;
3592 *rLo = tLo;
3593 return;
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 );
3613 *rHi = tHi;
3614 *rLo = tLo;
3615 return;
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,
3629 IEndianess);
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 );
3638 *rHi = tHi;
3639 *rLo = tLo;
3640 return;
3642 default:
3643 break;
3645 } /* if (e->tag == Iex_Binop) */
3648 /* --------- UNARY ops --------- */
3649 if (e->tag == Iex_Unop) {
3650 switch (e->Iex.Unop.op) {
3652 /* CmpwNEZ64(e) */
3653 case Iop_CmpwNEZ64: {
3654 HReg argHi, argLo;
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)));
3665 *rHi = tmp2;
3666 *rLo = tmp2; /* yes, really tmp2 */
3667 return;
3670 /* Left64 */
3671 case Iop_Left64: {
3672 HReg argHi, argLo;
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)));
3687 *rHi = resHi;
3688 *rLo = resLo;
3689 return;
3692 /* 32Sto64(e) */
3693 case Iop_32Sto64: {
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)));
3698 *rHi = tHi;
3699 *rLo = src;
3700 return;
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 );
3718 *rHi = tHi;
3719 *rLo = tLo;
3720 return;
3722 case Iop_ExtractExpD128: {
3723 HReg r_srcHi;
3724 HReg r_srcLo;
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,
3733 r_srcHi, r_srcLo));
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 );
3741 *rHi = tHi;
3742 *rLo = tLo;
3743 return;
3746 /* 32Uto64(e) */
3747 case Iop_32Uto64: {
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*/));
3751 *rHi = tHi;
3752 *rLo = tLo;
3753 return;
3756 case Iop_128to64: {
3757 /* Narrow, return the low 64-bit half as a 32-bit
3758 * register pair */
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);
3766 *rHi = r_MedLo;
3767 *rLo = r_Lo;
3768 return;
3771 case Iop_128HIto64: {
3772 /* Narrow, return the high 64-bit half as a 32-bit
3773 * register pair */
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);
3781 *rHi = r_Hi;
3782 *rLo = r_MedHi;
3783 return;
3786 /* V128{HI}to64 */
3787 case Iop_V128HIto64:
3788 case Iop_V128to64: {
3789 HReg r_aligned16;
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 );
3803 // store as Vec128
3804 addInstr(env,
3805 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
3807 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3808 addInstr(env,
3809 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
3810 addInstr(env,
3811 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
3813 add_to_sp( env, 32 ); // Reset SP
3814 *rHi = tHi;
3815 *rLo = tLo;
3816 return;
3819 /* could do better than this, but for now ... */
3820 case Iop_1Sto64: {
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));
3830 *rHi = tHi;
3831 *rLo = tLo;
3832 return;
3835 case Iop_Not64: {
3836 HReg xLo, xHi;
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));
3842 *rHi = tmpHi;
3843 *rLo = tmpLo;
3844 return;
3847 /* ReinterpF64asI64(e) */
3848 /* Given an IEEE754 double, produce an I64 with the same bit
3849 pattern. */
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*/) );
3860 // store as F64
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*/ ));
3869 *rHi = r_dstHi;
3870 *rLo = r_dstLo;
3872 add_to_sp( env, 16 ); // Reset SP
3873 return;
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*/) );
3887 // store as D64
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*/ ));
3896 *rHi = r_dstHi;
3897 *rLo = r_dstLo;
3899 add_to_sp( env, 16 ); // Reset SP
3901 return;
3904 case Iop_BCDtoDPB: {
3905 PPCCondCode cc;
3906 UInt argiregs;
3907 HReg argregs[2];
3908 Int argreg;
3909 HReg tLo = newVRegI(env);
3910 HReg tHi = newVRegI(env);
3911 HReg tmpHi;
3912 HReg tmpLo;
3913 Bool mode64 = env->mode64;
3915 argregs[0] = hregPPC_GPR3(mode64);
3916 argregs[1] = hregPPC_GPR4(mode64);
3918 argiregs = 0;
3919 argreg = 0;
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,
3933 argiregs,
3934 mk_RetLoc_simple(RLPri_2Int) ) );
3935 } else {
3936 Addr64 target;
3937 target = mode64 ? (Addr)h_calc_BCDtoDPB :
3938 toUInt( (Addr)h_calc_BCDtoDPB );
3939 addInstr( env, PPCInstr_Call( cc, target,
3940 argiregs,
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] ) );
3947 *rHi = tHi;
3948 *rLo = tLo;
3949 return;
3952 case Iop_DPBtoBCD: {
3953 PPCCondCode cc;
3954 UInt argiregs;
3955 HReg argregs[2];
3956 Int argreg;
3957 HReg tLo = newVRegI(env);
3958 HReg tHi = newVRegI(env);
3959 HReg tmpHi;
3960 HReg tmpLo;
3961 Bool mode64 = env->mode64;
3963 argregs[0] = hregPPC_GPR3(mode64);
3964 argregs[1] = hregPPC_GPR4(mode64);
3966 argiregs = 0;
3967 argreg = 0;
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,
3981 argiregs,
3982 mk_RetLoc_simple(RLPri_2Int) ) );
3983 } else {
3984 Addr64 target;
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]));
3994 *rHi = tHi;
3995 *rLo = tLo;
3996 return;
3999 default:
4000 break;
4002 } /* if (e->tag == Iex_Unop) */
4004 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
4005 ppIRExpr(e);
4006 vpanic("iselInt64Expr(ppc)");
4010 /*---------------------------------------------------------*/
4011 /*--- ISEL: Floating point expressions (32 bit) ---*/
4012 /*---------------------------------------------------------*/
4014 /* Nothing interesting here; really just wrappers for
4015 64-bit stuff. */
4017 static HReg iselFltExpr ( ISelEnv* env, const IRExpr* e, IREndness IEndianess )
4019 HReg r = iselFltExpr_wrk( env, e, IEndianess );
4020 # if 0
4021 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4022 # endif
4023 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
4024 vassert(hregIsVirtual(r));
4025 return 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) {
4042 PPCAMode* am_addr;
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*/,
4046 IEndianess);
4047 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4048 return r_dst;
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 ));
4056 return r_dst;
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
4064 time, as in
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
4074 entirety of
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
4081 truncation).
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,
4095 fsrc, zero_r1 ));
4096 // and reload. Good huh?! (sigh)
4097 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
4098 fdst, zero_r1 ));
4099 add_to_sp( env, 16 );
4100 return fdst;
4103 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
4104 if (mode64) {
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*/,
4118 False, False,
4119 fdst, fdst));
4121 add_to_sp( env, 16 );
4123 ///* Restore default FPU rounding. */
4124 //set_FPU_rounding_default( env );
4125 return fdst;
4126 } else {
4127 /* 32-bit mode */
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*/,
4145 False, False,
4146 fdst, fdst));
4148 add_to_sp( env, 16 );
4150 ///* Restore default FPU rounding. */
4151 //set_FPU_rounding_default( env );
4152 return fdst;
4157 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
4158 ppIRExpr(e);
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
4177 (with at least
4178 one 1 bit)
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 );
4193 # if 0
4194 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4195 # endif
4196 vassert(hregClass(r) == HRcFlt64);
4197 vassert(hregIsVirtual(r));
4198 return 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);
4207 vassert(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;
4228 else
4229 vpanic("iselDblExpr(ppc): const");
4231 if (!mode64) {
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 );
4237 } else { // mode64
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);
4247 PPCAMode* am_addr;
4248 vassert(e->Iex.Load.ty == Ity_F64);
4249 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/,
4250 IEndianess);
4251 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4252 return r_dst;
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 ));
4261 return r_dst;
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;
4272 default: break;
4274 if (fpop != Pfp_INVALID) {
4275 HReg r_dst = newVRegF(env);
4276 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.details->arg2,
4277 IEndianess);
4278 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.details->arg3,
4279 IEndianess);
4280 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4,
4281 IEndianess);
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));
4285 return r_dst;
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;
4301 default: 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));
4309 return r_dst;
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;
4317 default: 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));
4324 return fr_dst;
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;
4341 } else {
4342 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4343 fpop = Pfp_FPQTOD;
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));
4356 else
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 );
4362 return fr_dst;
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 );
4371 return r_dst;
4374 if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
4375 if (mode64) {
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*/,
4391 fdst, fdst));
4393 add_to_sp( env, 16 );
4395 ///* Restore default FPU rounding. */
4396 //set_FPU_rounding_default( env );
4397 return fdst;
4398 } else {
4399 /* 32-bit mode */
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,
4407 IEndianess);
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*/,
4420 fdst, fdst));
4422 add_to_sp( env, 16 );
4424 ///* Restore default FPU rounding. */
4425 //set_FPU_rounding_default( env );
4426 return fdst;
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;
4442 default: 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));
4448 return fr_dst;
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. */
4458 HReg r_aligned16;
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;
4476 else
4477 am_off_arg = am_off0;
4478 } else {
4479 if (e->Iex.Binop.op == Iop_F128HItoF64)
4480 am_off_arg = am_off0;
4481 else
4482 am_off_arg = am_off8;
4484 addInstr(env,
4485 PPCInstr_FpLdSt( True /*load*/,
4486 8, fdst,
4487 am_off_arg ));
4488 add_to_sp( env, 32 ); // Reset SP
4489 return fdst;
4491 case Iop_ReinterpI64asF64: {
4492 /* Given an I64, produce an IEEE754 double with the same
4493 bit pattern. */
4494 if (!mode64) {
4495 HReg r_srcHi, r_srcLo;
4496 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4497 IEndianess);
4498 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4499 } else {
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);
4512 PPCAMode *am_addr;
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
4525 return fr_dst;
4529 /* this is a no-op */
4530 HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
4531 return res;
4533 default:
4534 break;
4538 /* --------- MULTIPLEX --------- */
4539 if (e->tag == Iex_ITE) { // VFD
4540 if (ty == Ity_F64
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 ));
4548 return fr_dst;
4552 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
4553 ppIRExpr(e);
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) );
4562 return 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 );
4572 vassert( 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 ) );
4581 return r_dst;
4584 /* --------- LOAD --------- */
4585 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4586 PPCAMode* am_addr;
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*/,
4590 IEndianess);
4591 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4592 return r_dst;
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));
4602 return fr_dst;
4606 ppIRExpr( e );
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));
4615 return 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);
4626 vassert(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);
4639 addInstr(env,
4640 PPCInstr_AvLdSt( True/*load*/, 16, dst,
4641 PPCAMode_IR( e->Iex.Get.offset,
4642 GuestStatePtr(mode64) )));
4643 return dst;
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;
4657 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));
4661 return r_dst;
4664 case Iop_F64toF128: {
4665 fpop = Pfp_FPDTOQ;
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));
4678 return r_dst;
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;
4686 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;
4691 HReg r_aligned16;
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));
4713 return r_dst;
4716 default:
4717 break;
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;
4730 HReg r_aligned16;
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,
4748 dst, am_offlo));
4750 add_to_sp( env, 16 ); // Reset SP
4751 return dst;
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,
4762 r_src, rm));
4763 return dst;
4765 case Iop_RndF128:
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,
4774 r_src, rm));
4775 return dst;
4777 case Iop_SqrtF128:
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;
4781 goto do_Bin_F128;
4782 } else {
4783 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4784 fpop = Pfp_FPSQRTQ;
4785 goto do_Bin_F128;
4787 case Iop_F128toF32:
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;
4791 goto do_Bin_F128;
4792 } else {
4793 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4794 fpop = Pfp_FPQTOW;
4795 goto do_Bin_F128;
4797 do_Bin_F128: {
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));
4801 return r_dst;
4804 default:
4805 break;
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) {
4813 case Iop_AddF128:
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;
4817 } else {
4818 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4819 fpop = Pfp_FPADDQ; goto do_Tri_F128;
4821 case Iop_SubF128:
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;
4825 } else {
4826 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4827 fpop = Pfp_FPSUBQ; goto do_Tri_F128;
4829 case Iop_MulF128:
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;
4833 } else {
4834 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4835 fpop = Pfp_FPMULQ; goto do_Tri_F128;
4837 case Iop_DivF128:
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;
4841 } else {
4842 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4843 fpop = Pfp_FPDIVQ; goto do_Tri_F128;
4845 case Iop_MAddF128:
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;
4849 } else {
4850 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4851 fpop = Pfp_FPMULADDQ; goto do_Tri_F128;
4854 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));
4860 return r_dst;
4863 default:
4864 break;
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;
4872 switch (qop->op) {
4873 case Iop_MAddF128:
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;
4877 } else {
4878 set_FPU_rounding_mode( env, qop->arg1, IEndianess );
4879 fpop = Pfp_FPMULADDQ; goto do_Quad_F128;
4881 case Iop_MSubF128:
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;
4885 } else {
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;
4893 } else {
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;
4901 } else {
4902 set_FPU_rounding_mode( env, qop->arg1, IEndianess );
4903 fpop = Pfp_FPNEGMULSUBQ; goto do_Quad_F128;
4906 do_Quad_F128: {
4907 HReg r_dst = iselFp128Expr(env, qop->arg3,
4908 IEndianess);
4909 HReg r_srcL = iselFp128Expr(env, qop->arg2,
4910 IEndianess);
4911 HReg r_srcR = iselFp128Expr(env, qop->arg4,
4912 IEndianess);
4914 addInstr(env, PPCInstr_Fp128Trinary(fpop, r_dst, r_srcL, r_srcR));
4915 return r_dst;
4918 default:
4919 break;
4921 } /* if (e->tag == Iex_Qop) */
4923 ppIRExpr( e );
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) );
4932 return 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;
4943 vassert( e );
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 ) );
4956 return r_dst;
4959 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4960 PPCAMode* am_addr;
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*/,
4964 IEndianess);
4965 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4966 return r_dst;
4969 /* --------- OPS --------- */
4970 if (e->tag == Iex_Qop) {
4971 HReg r_dst = newVRegF( env );
4972 return r_dst;
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
4980 bit pattern. */
4981 if (!mode64) {
4982 HReg r_srcHi, r_srcLo;
4983 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4984 IEndianess);
4985 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4986 } else {
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));
4994 return fr_dst;
4996 case Iop_D128HItoD64:
4997 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4998 IEndianess );
4999 return r_dstHi;
5000 case Iop_D128LOtoD64:
5001 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
5002 IEndianess );
5003 return r_dstLo;
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,
5009 fr_srcR));
5010 return fr_dst;
5012 default:
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;
5027 default: 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,
5035 IEndianess);
5036 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
5037 return fr_dst;
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));
5050 return fr_dst;
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));
5056 return fr_dst;
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
5066 if (mode64) {
5067 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5069 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5070 } else {
5071 HReg tmpHi, tmpLo;
5072 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5074 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2,
5075 IEndianess);
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 );
5083 return fr_dst;
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;
5090 default: 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));
5100 return fr_dst;
5103 switch (e->Iex.Binop.op) {
5104 case Iop_InsertExpD64:
5105 fpop = Pfp_DIEX;
5106 break;
5107 default: break;
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 );
5115 if (env->mode64) {
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*/));
5120 } else {
5121 // put the I64 register pair into a floating point reg
5122 HReg tmpHi;
5123 HReg tmpLo;
5124 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5126 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1,
5127 IEndianess);
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,
5133 fr_srcR));
5134 add_to_sp( env, 16 );
5135 return fr_dst;
5139 if (e->tag == Iex_Triop) {
5140 IRTriop *triop = e->Iex.Triop.details;
5141 PPCFpOp fpop = Pfp_INVALID;
5143 switch (triop->op) {
5144 case Iop_AddD64:
5145 fpop = Pfp_DFPADD;
5146 break;
5147 case Iop_SubD64:
5148 fpop = Pfp_DFPSUB;
5149 break;
5150 case Iop_MulD64:
5151 fpop = Pfp_DFPMUL;
5152 break;
5153 case Iop_DivD64:
5154 fpop = Pfp_DFPDIV;
5155 break;
5156 default:
5157 break;
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 ) );
5166 return r_dst;
5169 switch (triop->op) {
5170 case Iop_QuantizeD64: fpop = Pfp_DQUA; break;
5171 case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
5172 default: 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,
5180 rmc));
5181 return r_dst;
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 );
5193 if (mode64)
5194 addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
5195 else
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));
5203 return r_dst;
5207 ppIRExpr( e );
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)
5223 vassert( e );
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 );
5229 return;
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
5241 if (env->mode64) {
5242 HReg tmp = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5243 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5244 } else {
5245 HReg tmpHi, tmpLo;
5246 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5248 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
5249 IEndianess);
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,
5256 fr_src));
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,
5267 r_src, r_src));
5269 *rHi = r_dstHi;
5270 *rLo = r_dstLo;
5271 return;
5274 /* --------- OPS --------- */
5275 if (e->tag == Iex_Binop) {
5276 HReg r_srcHi;
5277 HReg r_srcLo;
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 );
5283 *rHi = r_srcHi;
5284 *rLo = r_srcLo;
5285 return;
5286 break;
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,
5293 IEndianess);
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.
5299 *rHi = fr_dst;
5300 *rLo = fr_dst;
5301 return;
5303 case Iop_ShlD128:
5304 case Iop_ShrD128: {
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,
5311 IEndianess);
5313 if (e->Iex.Binop.op == Iop_ShrD128)
5314 fpop = Pfp_DSCRIQ;
5316 addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo,
5317 r_srcHi, r_srcLo, shift));
5319 *rHi = fr_dst_hi;
5320 *rLo = fr_dst_lo;
5321 return;
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,
5330 IEndianess);
5332 addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo,
5333 r_srcHi, r_srcLo, r_rmc));
5334 *rHi = r_dstHi;
5335 *rLo = r_dstLo;
5336 return;
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,
5347 IEndianess);
5349 /* Move I64 to float register to issue instruction */
5350 if (env->mode64) {
5351 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5352 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5353 } else {
5354 HReg tmpHi, tmpLo;
5355 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5357 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
5358 IEndianess);
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,
5365 r_dstHi, r_dstLo,
5366 r_srcL, r_srcHi, r_srcLo));
5367 *rHi = r_dstHi;
5368 *rLo = r_dstLo;
5369 return;
5371 default:
5372 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
5373 (Int)e->Iex.Binop.op );
5374 break;
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) {
5385 case Iop_AddD128:
5386 fpop = Pfp_DFPADDQ;
5387 break;
5388 case Iop_SubD128:
5389 fpop = Pfp_DFPSUBQ;
5390 break;
5391 case Iop_MulD128:
5392 fpop = Pfp_DFPMULQ;
5393 break;
5394 case Iop_DivD128:
5395 fpop = Pfp_DFPDIVQ;
5396 break;
5397 default:
5398 break;
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 );
5409 addInstr( env,
5410 PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
5411 r_srcRHi, r_srcRLo ) );
5412 *rHi = r_dstHi;
5413 *rLo = r_dstLo;
5414 return;
5416 switch (triop->op) {
5417 case Iop_QuantizeD128: fpop = Pfp_DQUAQ; break;
5418 case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
5419 default: 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));
5433 *rHi = r_dstHi;
5434 *rLo = r_dstLo;
5435 return;
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
5452 * bottom 8-bits.
5454 sub_from_sp( env, 16 );
5456 if (env->mode64)
5457 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
5458 else
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));
5473 *rHi = r_dstHi;
5474 *rLo = r_dstLo;
5475 return;
5479 ppIRExpr( e );
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 );
5491 # if 0
5492 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
5493 # endif
5494 vassert(hregClass(r) == HRcVec128);
5495 vassert(hregIsVirtual(r));
5496 return 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);
5507 vassert(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);
5518 addInstr(env,
5519 PPCInstr_AvLdSt( True/*load*/, 16, dst,
5520 PPCAMode_IR( e->Iex.Get.offset,
5521 GuestStatePtr(mode64) )));
5522 return dst;
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
5530 * unaligned load.
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);
5543 HReg rB;
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 );
5549 // lvx Vhi, 0, Rb
5550 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi,
5551 PPCAMode_IR(0, rB)) );
5553 if (IEndianess == Iend_LE)
5554 // lvsr Vp, 0, Rb
5555 addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp,
5556 PPCAMode_IR(0, rB)) );
5557 else
5558 // lvsl Vp, 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 ));
5573 else
5574 // vperm Vt, Vhi, Vlo, Vp
5575 addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp ));
5577 return v_dst;
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));
5592 return dst;
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));
5604 return dst;
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;
5613 HReg r_aligned16;
5615 vassert(mode64);
5616 /* need to put I64 src into upper 64-bits of vector register,
5617 use stack */
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 ));
5629 } else {
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
5640 return dst;
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;
5649 HReg r_aligned16;
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 ));
5670 } else {
5671 addInstr(env, PPCInstr_Load( 8, dst, am_off0, mode64 ));
5674 add_to_sp( env, 32 ); // Reset SP
5675 return dst;
5678 case Iop_NotV128: {
5679 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5680 HReg dst = newVRegV(env);
5681 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
5682 return dst;
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));
5692 return 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));
5702 return 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));
5712 return 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));
5722 return 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;
5735 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));
5740 return dst;
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 );
5757 /* Store zeros */
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 ));
5762 else
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 ));
5770 else
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 ));
5776 else
5777 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
5779 add_to_sp( env, 32 ); // Reset SP
5780 return dst;
5783 case Iop_Dup8x16:
5784 case Iop_Dup16x8:
5785 case Iop_Dup32x4:
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));
5793 return dst;
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;
5805 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));
5810 return dst;
5813 /* BCD Iops */
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 ) );
5819 return dst;
5822 case Iop_MulI128by10: op = Pav_MulI128by10; goto do_MulI128;
5823 case Iop_MulI128by10Carry: op = Pav_MulI128by10Carry; goto do_MulI128;
5824 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));
5828 return dst;
5831 default:
5832 break;
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: {
5840 if (!mode64) {
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
5867 return dst;
5868 } else {
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);
5872 HReg r_aligned16;
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 ));
5886 } else {
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
5894 return dst;
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;
5903 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));
5909 return dst;
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,
5925 isNanL, isNanR));
5927 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
5928 argL, argR));
5929 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
5930 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5931 return 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;
5937 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));
5942 return dst;
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;
5969 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));
5974 return dst;
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;
6004 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));
6009 return dst;
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;
6042 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));
6047 return dst;
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;
6069 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));
6074 return dst;
6077 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
6078 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
6079 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));
6084 return dst;
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;
6090 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));
6095 return dst;
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;
6101 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));
6106 return dst;
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;
6112 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));
6117 return dst;
6120 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
6121 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
6122 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));
6128 return dst;
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));
6136 return dst;
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;
6143 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));
6148 return dst;
6151 case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128;
6152 case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128;
6153 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));
6158 return dst;
6161 /* BCD Iops */
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,
6169 ps ) );
6170 return dst;
6173 case Iop_MulI128by10E: op = Pav_MulI128by10E; goto do_MulI128E;
6174 case Iop_MulI128by10ECarry: op = Pav_MulI128by10ECarry; goto do_MulI128E;
6175 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));
6180 return dst;
6183 case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
6184 case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
6185 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));
6190 return dst;
6193 default:
6194 break;
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;
6204 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));
6217 return dst;
6220 default:
6221 break;
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,
6238 env->hwcaps));
6239 ppIRExpr(e);
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 -- ");
6253 ppIRStmt(stmt);
6254 vex_printf("\n");
6257 switch (stmt->tag) {
6259 /* --------- STORE --------- */
6260 case Ist_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)
6266 goto stmt_fail;
6267 if (!mode64 && (tya != Ity_I32))
6268 goto stmt_fail;
6269 if (mode64 && (tya != Ity_I64))
6270 goto stmt_fail;
6272 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
6273 (mode64 && (tyd == Ity_I64))) {
6274 PPCAMode* am_addr
6275 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6276 IEndianess);
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 ));
6280 return;
6282 if (tyd == Ity_F64) {
6283 PPCAMode* am_addr
6284 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6285 IEndianess);
6286 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess);
6287 addInstr(env,
6288 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
6289 return;
6291 if (tyd == Ity_F32) {
6292 PPCAMode* am_addr
6293 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6294 IEndianess);
6295 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess);
6296 addInstr(env,
6297 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
6298 return;
6300 if (tyd == Ity_D64) {
6301 PPCAMode* am_addr
6302 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6303 IEndianess);
6304 HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess);
6305 addInstr(env,
6306 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
6307 return;
6309 if (tyd == Ity_D32) {
6310 PPCAMode* am_addr
6311 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6312 IEndianess);
6313 HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess);
6314 addInstr(env,
6315 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
6316 return;
6318 if (tyd == Ity_V128) {
6319 PPCAMode* am_addr
6320 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6321 IEndianess);
6322 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess);
6323 addInstr(env,
6324 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
6325 return;
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. */
6331 HReg rHi32, rLo32;
6332 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess);
6333 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data,
6334 IEndianess );
6335 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
6336 PPCAMode_IR( 0, r_addr ),
6337 rHi32,
6338 False/*32-bit insn please*/) );
6339 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
6340 PPCAMode_IR( 4, r_addr ),
6341 rLo32,
6342 False/*32-bit insn please*/) );
6343 return;
6345 break;
6348 /* --------- PUT --------- */
6349 case Ist_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 ));
6358 return;
6360 if (!mode64 && ty == Ity_I64) {
6361 HReg rHi, rLo;
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 ));
6368 return;
6370 if (ty == Ity_I128) {
6371 HReg rHi, rLo;
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 ));
6379 return;
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) );
6388 addInstr(env,
6389 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
6390 return;
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) );
6398 addInstr(env,
6399 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
6400 return;
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,
6407 fr_src, am_addr ));
6408 return;
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 ) );
6417 return;
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 ) );
6424 return;
6426 break;
6429 /* --------- Indexed PUT --------- */
6430 case Ist_PutI: {
6431 IRPutI *puti = stmt->Ist.PutI.details;
6433 PPCAMode* dst_am
6434 = genGuestArrayOffset(
6435 env, puti->descr,
6436 puti->ix, puti->bias,
6437 IEndianess );
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 ));
6443 return;
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 ));
6449 return;
6451 break;
6454 /* --------- TMP --------- */
6455 case Ist_WrTmp: {
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 ));
6463 return;
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,
6469 IEndianess);
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) );
6473 return;
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,
6478 IEndianess);
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) );
6482 return;
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) );
6499 return;
6501 if (ty == Ity_I1) {
6502 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data,
6503 IEndianess);
6504 HReg r_dst = lookupIRTemp(env, tmp);
6505 addInstr(env, PPCInstr_Set(cond, r_dst));
6506 return;
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));
6512 return;
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));
6518 return;
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));
6524 return;
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));
6530 return;
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));
6536 return;
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 ) );
6542 return;
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,
6549 IEndianess );
6550 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
6551 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
6552 return;
6554 break;
6557 /* --------- Load Linked or Store Conditional --------- */
6558 case Ist_LLSC: {
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)
6564 goto stmt_fail;
6565 if (!mode64 && (tyAddr != Ity_I32))
6566 goto stmt_fail;
6567 if (mode64 && (tyAddr != Ity_I64))
6568 goto stmt_fail;
6570 if (stmt->Ist.LLSC.storedata == NULL) {
6571 /* LL */
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 ));
6576 return;
6578 if (tyRes == Ity_I16) {
6579 addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 ));
6580 return;
6582 if (tyRes == Ity_I32) {
6583 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
6584 return;
6586 if (tyRes == Ity_I64 && mode64) {
6587 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
6588 return;
6590 /* fallthru */;
6591 } else {
6592 /* SC */
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,
6596 IEndianess);
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)) {
6603 int size = 0;
6605 if (tyData == Ity_I64)
6606 size = 8;
6607 else if (tyData == Ity_I32)
6608 size = 4;
6609 else if (tyData == Ity_I16)
6610 size = 2;
6611 else if (tyData == Ity_I8)
6612 size = 1;
6614 addInstr(env, PPCInstr_StoreC( size,
6615 r_a, r_src, mode64 ));
6616 addInstr(env, PPCInstr_MfCR( r_tmp ));
6617 addInstr(env, PPCInstr_Shft(
6618 Pshft_SHR,
6619 env->mode64 ? False : True
6620 /*F:64-bit, T:32-bit shift*/,
6621 r_tmp, r_tmp,
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(
6628 Palu_AND,
6629 r_res, r_tmp,
6630 PPCRH_Imm(False/*signed*/, 1)));
6631 return;
6633 /* fallthru */
6635 goto stmt_fail;
6636 /*NOTREACHED*/
6639 /* --------- Call to DIRTY helper --------- */
6640 case Ist_Dirty: {
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
6651 decision. */
6652 Bool retty_ok = False;
6653 switch (retty) {
6654 case Ity_INVALID: /* function doesn't return anything */
6655 case Ity_V128:
6656 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
6657 retty_ok = True; break;
6658 default:
6659 break;
6661 if (!retty_ok)
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. */
6667 UInt addToSp = 0;
6668 RetLoc rloc = mk_RetLoc_INVALID();
6669 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args,
6670 IEndianess );
6671 vassert(is_sane_RetLoc(rloc));
6673 /* Now figure out what to do with the returned value, if any. */
6674 switch (retty) {
6675 case Ity_INVALID: {
6676 /* No return value. Nothing to do. */
6677 vassert(d->tmp == IRTemp_INVALID);
6678 vassert(rloc.pri == RLPri_None);
6679 vassert(addToSp == 0);
6680 return;
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);
6689 return;
6691 case Ity_I64:
6692 if (mode64) {
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);
6699 } else {
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);
6710 return;
6711 case Ity_V128: {
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
6715 doHelperCall. */
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);
6722 return;
6724 default:
6725 /*NOTREACHED*/
6726 vassert(0);
6730 /* --------- MEM FENCE --------- */
6731 case Ist_MBE:
6732 switch (stmt->Ist.MBE.event) {
6733 case Imbe_Fence:
6734 addInstr(env, PPCInstr_MFence());
6735 return;
6736 default:
6737 break;
6739 break;
6741 /* --------- INSTR MARK --------- */
6742 /* Doesn't generate any executable code ... */
6743 case Ist_IMark:
6744 return;
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. */
6749 case Ist_AbiHint:
6750 return;
6752 /* --------- NO-OP --------- */
6753 /* Fairly self-explanatory, wouldn't you say? */
6754 case Ist_NoOp:
6755 return;
6757 /* --------- EXIT --------- */
6758 case Ist_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
6776 edge. */
6777 Bool toFastEP
6778 = mode64
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));
6786 } else {
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),
6791 IEndianess);
6792 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring));
6794 return;
6797 /* Case: assisted transfer to arbitrary address */
6798 switch (stmt->Ist.Exit.jk) {
6799 /* Keep this list in sync with that in iselNext below */
6800 case Ijk_ClientReq:
6801 case Ijk_EmFail:
6802 case Ijk_EmWarn:
6803 case Ijk_NoDecode:
6804 case Ijk_NoRedir:
6805 case Ijk_SigBUS:
6806 case Ijk_SigTRAP:
6807 case Ijk_Sys_syscall:
6808 case Ijk_InvalICache:
6810 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
6811 IEndianess);
6812 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc,
6813 stmt->Ist.Exit.jk));
6814 return;
6816 default:
6817 break;
6820 /* Do we ever expect to see any other kind? */
6821 goto stmt_fail;
6824 default: break;
6826 stmt_fail:
6827 ppIRStmt(stmt);
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);
6842 ppIRExpr( next );
6843 vex_printf( "; exit-");
6844 ppIRJumpKind(jk);
6845 vex_printf( "\n");
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
6860 edge. */
6861 Bool toFastEP
6862 = env->mode64
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));
6870 } else {
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,
6876 Ijk_Boring));
6878 return;
6882 /* Case: call/return (==boring) transfer to any address */
6883 switch (jk) {
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));
6889 } else {
6890 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6891 Ijk_Boring));
6893 return;
6895 default:
6896 break;
6899 /* Case: assisted transfer to arbitrary address */
6900 switch (jk) {
6901 /* Keep this list in sync with that for Ist_Exit above */
6902 case Ijk_ClientReq:
6903 case Ijk_EmFail:
6904 case Ijk_EmWarn:
6905 case Ijk_NoDecode:
6906 case Ijk_NoRedir:
6907 case Ijk_SigBUS:
6908 case Ijk_SigTRAP:
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));
6915 return;
6917 default:
6918 break;
6921 vex_printf( "\n-- PUT(%d) = ", offsIP);
6922 ppIRExpr( next );
6923 vex_printf( "; exit-");
6924 ppIRJumpKind(jk);
6925 vex_printf( "\n");
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,
6936 VexArch arch_host,
6937 const VexArchInfo* archinfo_host,
6938 const VexAbiInfo* vbi,
6939 Int offs_Host_EvC_Counter,
6940 Int offs_Host_EvC_FailAddr,
6941 Bool chainingAllowed,
6942 Bool addProfInc,
6943 Addr max_ga)
6946 Int i, j;
6947 HReg hregLo, hregMedLo, hregMedHi, hregHi;
6948 ISelEnv* env;
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;
6969 if (mode64) {
6970 vassert((hwcaps_host & mask32) == 0);
6971 } else {
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;
6981 else
6982 IEndianess = Iend_LE;
6984 /* Make up an initial environment to use. */
6985 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
6986 env->vreg_ctr = 0;
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));
7006 if (mode64) {
7007 env->vregmapMedHi = NULL;
7008 env->vregmapHi = NULL;
7009 } else {
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;
7019 env->vbi = vbi;
7021 /* For each IR temporary, allocate a suitably-kinded virtual
7022 register. */
7023 j = 0;
7024 for (i = 0; i < env->n_vregmap; i++) {
7025 hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
7026 switch (bb->tyenv->types[i]) {
7027 case Ity_I1:
7028 case Ity_I8:
7029 case Ity_I16:
7030 case Ity_I32:
7031 if (mode64) {
7032 hregLo = mkHReg(True, HRcInt64, 0, j++);
7033 } else {
7034 hregLo = mkHReg(True, HRcInt32, 0, j++);
7036 break;
7037 case Ity_I64:
7038 if (mode64) {
7039 hregLo = mkHReg(True, HRcInt64, 0, j++);
7040 } else {
7041 hregLo = mkHReg(True, HRcInt32, 0, j++);
7042 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
7044 break;
7045 case Ity_I128:
7046 if (mode64) {
7047 hregLo = mkHReg(True, HRcInt64, 0, j++);
7048 hregMedLo = mkHReg(True, HRcInt64, 0, j++);
7049 } else {
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++);
7055 break;
7056 case Ity_F32:
7057 case Ity_F64:
7058 hregLo = mkHReg(True, HRcFlt64, 0, j++);
7059 break;
7060 case Ity_F128:
7061 case Ity_V128:
7062 hregLo = mkHReg(True, HRcVec128, 0, j++);
7063 break;
7064 case Ity_D32:
7065 case Ity_D64:
7066 hregLo = mkHReg(True, HRcFlt64, 0, j++);
7067 break;
7068 case Ity_D128:
7069 hregLo = mkHReg(True, HRcFlt64, 0, j++);
7070 hregMedLo = mkHReg(True, HRcFlt64, 0, j++);
7071 break;
7072 default:
7073 ppIRType(bb->tyenv->types[i]);
7074 vpanic("iselBB(ppc): IRTemp type");
7076 env->vregmapLo[i] = hregLo;
7077 env->vregmapMedLo[i] = hregMedLo;
7078 if (!mode64) {
7079 env->vregmapMedHi[i] = hregMedHi;
7080 env->vregmapHi[i] = hregHi;
7083 env->vreg_ctr = j;
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. */
7094 if (addProfInc) {
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;
7106 return env->code;
7110 /*---------------------------------------------------------------*/
7111 /*--- end host_ppc_isel.c ---*/
7112 /*---------------------------------------------------------------*/