Implement ppc64 ldbrx as 64-bit load and Iop_Reverse8sIn64_x1.
[valgrind.git] / VEX / priv / host_ppc_isel.c
blob4fc3eb54e75dd2348f05993e9e22c95ec5daded2
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_Reverse8sIn64_x1: {
2214 /* See Iop_Reverse8sIn32_x1, but extended to 64bit.
2215 Can only be used in 64bit mode. */
2216 vassert (mode64);
2218 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2219 HReg rr = newVRegI(env);
2220 HReg rMask = newVRegI(env);
2221 HReg rnMask = newVRegI(env);
2222 HReg rtHi = newVRegI(env);
2223 HReg rtLo = newVRegI(env);
2225 // Copy r_src since we need to modify it
2226 addInstr(env, mk_iMOVds_RR(rr, r_src));
2228 // r = (r & 0x00FF00FF00FF00FF) << 8 | (r & 0xFF00FF00FF00FF00) >> 8
2229 addInstr(env, PPCInstr_LI(rMask, 0x00FF00FF00FF00FFULL,
2230 True/* 64bit imm*/));
2231 addInstr(env, PPCInstr_Unary(Pun_NOT, rnMask, rMask));
2232 addInstr(env, PPCInstr_Alu(Palu_AND, rtHi, rr, PPCRH_Reg(rMask)));
2233 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64 bit shift*/,
2234 rtHi, rtHi,
2235 PPCRH_Imm(False/*!signed imm*/, 8)));
2236 addInstr(env, PPCInstr_Alu(Palu_AND, rtLo, rr, PPCRH_Reg(rnMask)));
2237 addInstr(env, PPCInstr_Shft(Pshft_SHR, False/*64 bit shift*/,
2238 rtLo, rtLo,
2239 PPCRH_Imm(False/*!signed imm*/, 8)));
2240 addInstr(env, PPCInstr_Alu(Palu_OR, rr, rtHi, PPCRH_Reg(rtLo)));
2242 // r = (r & 0x0000FFFF0000FFFF) << 16 | (r & 0xFFFF0000FFFF0000) >> 16
2243 addInstr(env, PPCInstr_LI(rMask, 0x0000FFFF0000FFFFULL,
2244 True/* !64bit imm*/));
2245 addInstr(env, PPCInstr_Unary(Pun_NOT, rnMask, rMask));
2246 addInstr(env, PPCInstr_Alu(Palu_AND, rtHi, rr, PPCRH_Reg(rMask)));
2247 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64 bit shift*/,
2248 rtHi, rtHi,
2249 PPCRH_Imm(False/*!signed imm*/, 16)));
2250 addInstr(env, PPCInstr_Alu(Palu_AND, rtLo, rr, PPCRH_Reg(rnMask)));
2251 addInstr(env, PPCInstr_Shft(Pshft_SHR, False/*64 bit shift*/,
2252 rtLo, rtLo,
2253 PPCRH_Imm(False/*!signed imm*/, 16)));
2254 addInstr(env, PPCInstr_Alu(Palu_OR, rr, rtHi, PPCRH_Reg(rtLo)));
2256 // r = (r & 0x00000000FFFFFFFF) << 32 | (r & 0xFFFFFFFF00000000) >> 32
2257 /* We don't need to mask anymore, just two more shifts and an or. */
2258 addInstr(env, mk_iMOVds_RR(rtLo, rr));
2259 addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64 bit shift*/,
2260 rtLo, rtLo,
2261 PPCRH_Imm(False/*!signed imm*/, 32)));
2262 addInstr(env, PPCInstr_Shft(Pshft_SHR, False/*64 bit shift*/,
2263 rr, rr,
2264 PPCRH_Imm(False/*!signed imm*/, 32)));
2265 addInstr(env, PPCInstr_Alu(Palu_OR, rr, rr, PPCRH_Reg(rtLo)));
2267 return rr;
2270 case Iop_Left8:
2271 case Iop_Left16:
2272 case Iop_Left32:
2273 case Iop_Left64: {
2274 HReg r_src, r_dst;
2275 if (op_unop == Iop_Left64 && !mode64)
2276 goto irreducible;
2277 r_dst = newVRegI(env);
2278 r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2279 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2280 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2281 return r_dst;
2284 case Iop_CmpwNEZ32: {
2285 HReg r_dst = newVRegI(env);
2286 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2287 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2288 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2289 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2290 r_dst, r_dst, PPCRH_Imm(False, 31)));
2291 return r_dst;
2294 case Iop_CmpwNEZ64: {
2295 HReg r_dst = newVRegI(env);
2296 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2297 if (!mode64) goto irreducible;
2298 addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2299 addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2300 addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
2301 r_dst, r_dst, PPCRH_Imm(False, 63)));
2302 return r_dst;
2305 case Iop_V128to32: {
2306 HReg r_aligned16;
2307 HReg dst = newVRegI(env);
2308 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2309 PPCAMode *am_off0, *am_off_word0;
2310 sub_from_sp( env, 32 ); // Move SP down 32 bytes
2312 // get a quadword aligned address within our stack space
2313 r_aligned16 = get_sp_aligned16( env );
2314 am_off0 = PPCAMode_IR( 0, r_aligned16 );
2316 /* Note that the store below (done via PPCInstr_AvLdSt) uses
2317 * stvx, which stores the vector in proper LE format,
2318 * with byte zero (far right byte of the register in LE format)
2319 * stored at the lowest memory address. Therefore, to obtain
2320 * integer word zero, we need to use that lowest memory address
2321 * as the base for the load.
2323 if (IEndianess == Iend_LE)
2324 am_off_word0 = am_off0;
2325 else
2326 am_off_word0 = PPCAMode_IR( 12,r_aligned16 );
2328 // store vec, load low word to dst
2329 addInstr(env,
2330 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2331 addInstr(env,
2332 PPCInstr_Load( 4, dst, am_off_word0, mode64 ));
2334 add_to_sp( env, 32 ); // Reset SP
2335 return dst;
2338 case Iop_V128to64:
2339 case Iop_V128HIto64:
2340 if (mode64) {
2341 HReg r_aligned16;
2342 HReg dst = newVRegI(env);
2343 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2344 PPCAMode *am_off0, *am_off8, *am_off_arg;
2345 sub_from_sp( env, 32 ); // Move SP down 32 bytes
2347 // get a quadword aligned address within our stack space
2348 r_aligned16 = get_sp_aligned16( env );
2349 am_off0 = PPCAMode_IR( 0, r_aligned16 );
2350 am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
2352 // store vec, load low word or high to dst
2353 addInstr(env,
2354 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2355 if (IEndianess == Iend_LE) {
2356 if (op_unop == Iop_V128HIto64)
2357 am_off_arg = am_off8;
2358 else
2359 am_off_arg = am_off0;
2360 } else {
2361 if (op_unop == Iop_V128HIto64)
2362 am_off_arg = am_off0;
2363 else
2364 am_off_arg = am_off8;
2366 addInstr(env,
2367 PPCInstr_Load(
2368 8, dst,
2369 am_off_arg,
2370 mode64 ));
2372 add_to_sp( env, 32 ); // Reset SP
2373 return dst;
2375 break;
2376 case Iop_16to8:
2377 case Iop_32to8:
2378 case Iop_32to16:
2379 case Iop_64to8:
2380 /* These are no-ops. */
2381 return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2383 /* ReinterpF64asI64(e) */
2384 /* Given an IEEE754 double, produce an I64 with the same bit
2385 pattern. */
2386 case Iop_ReinterpF64asI64:
2387 if (mode64) {
2388 PPCAMode *am_addr;
2389 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
2390 HReg r_dst = newVRegI(env);
2392 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2393 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2395 // store as F64
2396 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2397 fr_src, am_addr ));
2398 // load as Ity_I64
2399 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2401 add_to_sp( env, 16 ); // Reset SP
2402 return r_dst;
2404 break;
2406 /* ReinterpF32asI32(e) */
2407 /* Given an IEEE754 float, produce an I32 with the same bit
2408 pattern. */
2409 case Iop_ReinterpF32asI32: {
2410 /* I believe this generates correct code for both 32- and
2411 64-bit hosts. */
2412 PPCAMode *am_addr;
2413 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
2414 HReg r_dst = newVRegI(env);
2416 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2417 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2419 // store as F32
2420 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
2421 fr_src, am_addr ));
2422 // load as Ity_I32
2423 addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
2425 add_to_sp( env, 16 ); // Reset SP
2426 return r_dst;
2428 break;
2430 case Iop_ReinterpD64asI64:
2431 if (mode64) {
2432 PPCAMode *am_addr;
2433 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
2434 HReg r_dst = newVRegI(env);
2436 sub_from_sp( env, 16 ); // Move SP down 16 bytes
2437 am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2439 // store as D64
2440 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2441 fr_src, am_addr ));
2442 // load as Ity_I64
2443 addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2444 add_to_sp( env, 16 ); // Reset SP
2445 return r_dst;
2447 break;
2449 case Iop_BCDtoDPB: {
2450 /* the following is only valid in 64 bit mode */
2451 if (!mode64) break;
2453 PPCCondCode cc;
2454 UInt argiregs;
2455 HReg argregs[1];
2456 HReg r_dst = newVRegI(env);
2457 Int argreg;
2459 argiregs = 0;
2460 argreg = 0;
2461 argregs[0] = hregPPC_GPR3(mode64);
2463 argiregs |= (1 << (argreg+3));
2464 addInstr(env, mk_iMOVds_RR( argregs[argreg++],
2465 iselWordExpr_R(env, e->Iex.Unop.arg,
2466 IEndianess) ) );
2468 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2469 if (IEndianess == Iend_LE) {
2470 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
2471 argiregs,
2472 mk_RetLoc_simple(RLPri_Int)) );
2473 } else {
2474 HWord* fdescr;
2475 fdescr = (HWord*)h_calc_BCDtoDPB;
2476 addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2477 argiregs,
2478 mk_RetLoc_simple(RLPri_Int)) );
2481 addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2482 return r_dst;
2485 case Iop_DPBtoBCD: {
2486 /* the following is only valid in 64 bit mode */
2487 if (!mode64) break;
2489 PPCCondCode cc;
2490 UInt argiregs;
2491 HReg argregs[1];
2492 HReg r_dst = newVRegI(env);
2493 Int argreg;
2495 argiregs = 0;
2496 argreg = 0;
2497 argregs[0] = hregPPC_GPR3(mode64);
2499 argiregs |= (1 << (argreg+3));
2500 addInstr(env, mk_iMOVds_RR( argregs[argreg++],
2501 iselWordExpr_R(env, e->Iex.Unop.arg,
2502 IEndianess) ) );
2504 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2506 if (IEndianess == Iend_LE) {
2507 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
2508 argiregs,
2509 mk_RetLoc_simple(RLPri_Int) ) );
2510 } else {
2511 HWord* fdescr;
2512 fdescr = (HWord*)h_calc_DPBtoBCD;
2513 addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2514 argiregs,
2515 mk_RetLoc_simple(RLPri_Int) ) );
2518 addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2519 return r_dst;
2521 case Iop_F32toF16x4: {
2522 HReg vdst = newVRegV(env); /* V128 */
2523 HReg dst = newVRegI(env); /* I64*/
2524 HReg r0 = newVRegI(env); /* I16*/
2525 HReg r1 = newVRegI(env); /* I16*/
2526 HReg r2 = newVRegI(env); /* I16*/
2527 HReg r3 = newVRegI(env); /* I16*/
2528 HReg vsrc = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2529 PPCAMode *am_off0, *am_off2, *am_off4, *am_off6, *am_off8;
2530 PPCAMode *am_off10, *am_off12, *am_off14;
2531 HReg r_aligned16;
2533 sub_from_sp( env, 32 ); // Move SP down
2535 /* issue instruction */
2536 addInstr(env, PPCInstr_AvUnary(Pav_F32toF16x4, vdst, vsrc));
2538 /* Get a quadword aligned address within our stack space */
2539 r_aligned16 = get_sp_aligned16( env );
2540 am_off0 = PPCAMode_IR( 0, r_aligned16 );
2541 am_off2 = PPCAMode_IR( 2, r_aligned16 );
2542 am_off4 = PPCAMode_IR( 4, r_aligned16 );
2543 am_off6 = PPCAMode_IR( 6, r_aligned16 );
2544 am_off8 = PPCAMode_IR( 8, r_aligned16 );
2545 am_off10 = PPCAMode_IR( 10, r_aligned16 );
2546 am_off12 = PPCAMode_IR( 12, r_aligned16 );
2547 am_off14 = PPCAMode_IR( 14, r_aligned16 );
2549 /* Store v128 result to stack. */
2550 addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, vdst, am_off0));
2552 /* fetch four I16 from V128, store into contiguous I64 via stack, */
2553 if (IEndianess == Iend_LE) {
2554 addInstr(env, PPCInstr_Load( 2, r3, am_off12, mode64));
2555 addInstr(env, PPCInstr_Load( 2, r2, am_off8, mode64));
2556 addInstr(env, PPCInstr_Load( 2, r1, am_off4, mode64));
2557 addInstr(env, PPCInstr_Load( 2, r0, am_off0, mode64));
2558 } else {
2559 addInstr(env, PPCInstr_Load( 2, r0, am_off14, mode64));
2560 addInstr(env, PPCInstr_Load( 2, r1, am_off10, mode64));
2561 addInstr(env, PPCInstr_Load( 2, r2, am_off6, mode64));
2562 addInstr(env, PPCInstr_Load( 2, r3, am_off2, mode64));
2565 /* store in contiguous 64-bit values */
2566 addInstr(env, PPCInstr_Store( 2, am_off6, r3, mode64));
2567 addInstr(env, PPCInstr_Store( 2, am_off4, r2, mode64));
2568 addInstr(env, PPCInstr_Store( 2, am_off2, r1, mode64));
2569 addInstr(env, PPCInstr_Store( 2, am_off0, r0, mode64));
2571 /* Fetch I64 */
2572 addInstr(env, PPCInstr_Load(8, dst, am_off0, mode64));
2574 add_to_sp( env, 32 ); // Reset SP
2575 return dst;
2578 default:
2579 break;
2582 switch (e->Iex.Unop.op) {
2583 case Iop_ExtractExpD64: {
2585 HReg fr_dst = newVRegI(env);
2586 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
2587 HReg tmp = newVRegF(env);
2588 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
2589 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
2591 // put the D64 result into a integer register
2592 sub_from_sp( env, 16 );
2593 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
2594 addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
2595 add_to_sp( env, 16 );
2596 return fr_dst;
2598 case Iop_ExtractExpD128: {
2599 HReg fr_dst = newVRegI(env);
2600 HReg r_srcHi;
2601 HReg r_srcLo;
2602 HReg tmp = newVRegF(env);
2603 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
2605 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
2606 IEndianess);
2607 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
2608 r_srcHi, r_srcLo));
2610 sub_from_sp( env, 16 );
2611 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
2612 addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
2613 add_to_sp( env, 16 );
2614 return fr_dst;
2616 default:
2617 break;
2620 break;
2623 /* --------- GET --------- */
2624 case Iex_Get: {
2625 if (ty == Ity_I8 || ty == Ity_I16 ||
2626 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
2627 HReg r_dst = newVRegI(env);
2628 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2629 GuestStatePtr(mode64) );
2630 addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
2631 r_dst, am_addr, mode64 ));
2632 return r_dst;
2634 break;
2637 case Iex_GetI: {
2638 PPCAMode* src_am
2639 = genGuestArrayOffset( env, e->Iex.GetI.descr,
2640 e->Iex.GetI.ix, e->Iex.GetI.bias,
2641 IEndianess );
2642 HReg r_dst = newVRegI(env);
2643 if (mode64 && ty == Ity_I64) {
2644 addInstr(env, PPCInstr_Load( toUChar(8),
2645 r_dst, src_am, mode64 ));
2646 return r_dst;
2648 if ((!mode64) && ty == Ity_I32) {
2649 addInstr(env, PPCInstr_Load( toUChar(4),
2650 r_dst, src_am, mode64 ));
2651 return r_dst;
2653 break;
2656 /* --------- CCALL --------- */
2657 case Iex_CCall: {
2658 vassert(ty == e->Iex.CCall.retty); /* well-formedness of IR */
2660 /* be very restrictive for now. Only 32/64-bit ints allowed for
2661 args, and 32 bits or host machine word for return type. */
2662 if (!(ty == Ity_I32 || (mode64 && ty == Ity_I64)))
2663 goto irreducible;
2665 /* Marshal args, do the call, clear stack. */
2666 UInt addToSp = 0;
2667 RetLoc rloc = mk_RetLoc_INVALID();
2668 doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
2669 e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args,
2670 IEndianess );
2671 vassert(is_sane_RetLoc(rloc));
2672 vassert(rloc.pri == RLPri_Int);
2673 vassert(addToSp == 0);
2675 /* GPR3 now holds the destination address from Pin_Goto */
2676 HReg r_dst = newVRegI(env);
2677 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
2678 return r_dst;
2681 /* --------- LITERAL --------- */
2682 /* 32/16/8-bit literals */
2683 case Iex_Const: {
2684 Long l;
2685 HReg r_dst = newVRegI(env);
2686 IRConst* con = e->Iex.Const.con;
2687 switch (con->tag) {
2688 case Ico_U64: if (!mode64) goto irreducible;
2689 l = (Long) con->Ico.U64; break;
2690 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
2691 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2692 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
2693 default: vpanic("iselIntExpr_R.const(ppc)");
2695 addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64));
2696 return r_dst;
2699 /* --------- MULTIPLEX --------- */
2700 case Iex_ITE: { // VFD
2701 if ((ty == Ity_I8 || ty == Ity_I16 ||
2702 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) &&
2703 typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
2704 PPCRI* r1 = iselWordExpr_RI(env, e->Iex.ITE.iftrue, IEndianess);
2705 HReg r0 = iselWordExpr_R(env, e->Iex.ITE.iffalse, IEndianess);
2706 HReg r_dst = newVRegI(env);
2707 addInstr(env, mk_iMOVds_RR(r_dst,r0));
2708 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
2709 addInstr(env, PPCInstr_CMov(cc, r_dst, r1));
2710 return r_dst;
2712 break;
2715 default:
2716 break;
2717 } /* switch (e->tag) */
2720 /* We get here if no pattern matched. */
2721 irreducible:
2722 ppIRExpr(e);
2723 vpanic("iselIntExpr_R(ppc): cannot reduce tree");
2727 /*---------------------------------------------------------*/
2728 /*--- ISEL: Integer expression auxiliaries ---*/
2729 /*---------------------------------------------------------*/
2731 /* --------------------- AMODEs --------------------- */
2733 /* Return an AMode which computes the value of the specified
2734 expression, possibly also adding insns to the code list as a
2735 result. The expression may only be a word-size one.
2738 static Bool uInt_fits_in_16_bits ( UInt u )
2740 /* Is u the same as the sign-extend of its lower 16 bits? */
2741 UInt v = u & 0xFFFF;
2743 v = (Int)(v << 16) >> 16; /* sign extend */
2745 return u == v;
2748 static Bool uLong_fits_in_16_bits ( ULong u )
2750 /* Is u the same as the sign-extend of its lower 16 bits? */
2751 ULong v = u & 0xFFFFULL;
2753 v = (Long)(v << 48) >> 48; /* sign extend */
2755 return u == v;
2758 static Bool uLong_is_4_aligned ( ULong u )
2760 return toBool((u & 3ULL) == 0);
2763 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2765 Bool mode64 = env->mode64;
2766 switch (am->tag) {
2767 case Pam_IR:
2768 /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2769 somehow, but I think it's OK. */
2770 return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2771 hregIsVirtual(am->Pam.IR.base) &&
2772 uInt_fits_in_16_bits(am->Pam.IR.index) );
2773 case Pam_RR:
2774 return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2775 hregIsVirtual(am->Pam.RR.base) &&
2776 hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2777 hregIsVirtual(am->Pam.RR.index) );
2778 default:
2779 vpanic("sane_AMode: unknown ppc amode tag");
2783 static
2784 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, const IRExpr* e, IRType xferTy,
2785 IREndness IEndianess )
2787 PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy, IEndianess);
2788 vassert(sane_AMode(env, am));
2789 return am;
2792 /* DO NOT CALL THIS DIRECTLY ! */
2793 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, const IRExpr* e,
2794 IRType xferTy, IREndness IEndianess )
2796 IRType ty = typeOfIRExpr(env->type_env,e);
2798 if (env->mode64) {
2800 /* If the data load/store type is I32 or I64, this amode might
2801 be destined for use in ld/ldu/lwa/st/stu. In which case
2802 insist that if it comes out as an _IR, the immediate must
2803 have its bottom two bits be zero. This does assume that for
2804 any other type (I8/I16/I128/F32/F64/V128) the amode will not
2805 be parked in any such instruction. But that seems a
2806 reasonable assumption. */
2807 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2809 vassert(ty == Ity_I64);
2811 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2812 if (e->tag == Iex_Binop
2813 && e->Iex.Binop.op == Iop_Add64
2814 && e->Iex.Binop.arg2->tag == Iex_Const
2815 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2816 && (aligned4imm ? uLong_is_4_aligned(e->Iex.Binop.arg2
2817 ->Iex.Const.con->Ico.U64)
2818 : True)
2819 && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2820 ->Iex.Const.con->Ico.U64)) {
2821 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2822 iselWordExpr_R(env, e->Iex.Binop.arg1,
2823 IEndianess) );
2826 /* Add64(expr,expr) */
2827 if (e->tag == Iex_Binop
2828 && e->Iex.Binop.op == Iop_Add64) {
2829 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2830 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2831 return PPCAMode_RR( r_idx, r_base );
2834 } else {
2836 vassert(ty == Ity_I32);
2838 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2839 if (e->tag == Iex_Binop
2840 && e->Iex.Binop.op == Iop_Add32
2841 && e->Iex.Binop.arg2->tag == Iex_Const
2842 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2843 && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2844 ->Iex.Const.con->Ico.U32)) {
2845 return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2846 iselWordExpr_R(env, e->Iex.Binop.arg1,
2847 IEndianess) );
2850 /* Add32(expr,expr) */
2851 if (e->tag == Iex_Binop
2852 && e->Iex.Binop.op == Iop_Add32) {
2853 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2854 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2855 return PPCAMode_RR( r_idx, r_base );
2860 /* Doesn't match anything in particular. Generate it into
2861 a register and use that. */
2862 return PPCAMode_IR( 0, iselWordExpr_R(env,e,IEndianess) );
2866 /* --------------------- RH --------------------- */
2868 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2869 (reg-or-halfword-immediate). It's important to specify whether the
2870 immediate is to be regarded as signed or not. If yes, this will
2871 never return -32768 as an immediate; this guaranteed that all
2872 signed immediates that are return can have their sign inverted if
2873 need be. */
2875 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, const IRExpr* e,
2876 IREndness IEndianess )
2878 PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e, IEndianess);
2879 /* sanity checks ... */
2880 switch (ri->tag) {
2881 case Prh_Imm:
2882 vassert(ri->Prh.Imm.syned == syned);
2883 if (syned)
2884 vassert(ri->Prh.Imm.imm16 != 0x8000);
2885 return ri;
2886 case Prh_Reg:
2887 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2888 vassert(hregIsVirtual(ri->Prh.Reg.reg));
2889 return ri;
2890 default:
2891 vpanic("iselIntExpr_RH: unknown ppc RH tag");
2895 /* DO NOT CALL THIS DIRECTLY ! */
2896 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, const IRExpr* e,
2897 IREndness IEndianess )
2899 ULong u;
2900 Long l;
2901 IRType ty = typeOfIRExpr(env->type_env,e);
2902 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2903 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2905 /* special case: immediate */
2906 if (e->tag == Iex_Const) {
2907 IRConst* con = e->Iex.Const.con;
2908 /* What value are we aiming to generate? */
2909 switch (con->tag) {
2910 /* Note: Not sign-extending - we carry 'syned' around */
2911 case Ico_U64: vassert(env->mode64);
2912 u = con->Ico.U64; break;
2913 case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2914 case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2915 case Ico_U8: u = 0x000000FF & con->Ico.U8; break;
2916 default: vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2918 l = (Long)u;
2919 /* Now figure out if it's representable. */
2920 if (!syned && u <= 65535) {
2921 return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2923 if (syned && l >= -32767 && l <= 32767) {
2924 return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2926 /* no luck; use the Slow Way. */
2929 /* default case: calculate into a register and return that */
2930 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2934 /* --------------------- RIs --------------------- */
2936 /* Calculate an expression into an PPCRI operand. As with
2937 iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2938 in 64-bit mode, 64 bits. */
2940 static PPCRI* iselWordExpr_RI ( ISelEnv* env, const IRExpr* e,
2941 IREndness IEndianess )
2943 PPCRI* ri = iselWordExpr_RI_wrk(env, e, IEndianess);
2944 /* sanity checks ... */
2945 switch (ri->tag) {
2946 case Pri_Imm:
2947 return ri;
2948 case Pri_Reg:
2949 vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2950 vassert(hregIsVirtual(ri->Pri.Reg));
2951 return ri;
2952 default:
2953 vpanic("iselIntExpr_RI: unknown ppc RI tag");
2957 /* DO NOT CALL THIS DIRECTLY ! */
2958 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, const IRExpr* e,
2959 IREndness IEndianess )
2961 Long l;
2962 IRType ty = typeOfIRExpr(env->type_env,e);
2963 vassert(ty == Ity_I8 || ty == Ity_I16 ||
2964 ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2966 /* special case: immediate */
2967 if (e->tag == Iex_Const) {
2968 IRConst* con = e->Iex.Const.con;
2969 switch (con->tag) {
2970 case Ico_U64: vassert(env->mode64);
2971 l = (Long) con->Ico.U64; break;
2972 case Ico_U32: l = (Long)(Int) con->Ico.U32; break;
2973 case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2974 case Ico_U8: l = (Long)(Int)(Char )con->Ico.U8; break;
2975 default: vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2977 return PPCRI_Imm((ULong)l);
2980 /* default case: calculate into a register and return that */
2981 return PPCRI_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2985 /* --------------------- RH5u --------------------- */
2987 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2988 being an immediate in the range 1 .. 31 inclusive. Used for doing
2989 shift amounts. Only used in 32-bit mode. */
2991 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, const IRExpr* e,
2992 IREndness IEndianess )
2994 PPCRH* ri;
2995 vassert(!env->mode64);
2996 ri = iselWordExpr_RH5u_wrk(env, e, IEndianess);
2997 /* sanity checks ... */
2998 switch (ri->tag) {
2999 case Prh_Imm:
3000 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
3001 vassert(!ri->Prh.Imm.syned);
3002 return ri;
3003 case Prh_Reg:
3004 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
3005 vassert(hregIsVirtual(ri->Prh.Reg.reg));
3006 return ri;
3007 default:
3008 vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
3012 /* DO NOT CALL THIS DIRECTLY ! */
3013 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, const IRExpr* e,
3014 IREndness IEndianess )
3016 IRType ty = typeOfIRExpr(env->type_env,e);
3017 vassert(ty == Ity_I8);
3019 /* special case: immediate */
3020 if (e->tag == Iex_Const
3021 && e->Iex.Const.con->tag == Ico_U8
3022 && e->Iex.Const.con->Ico.U8 >= 1
3023 && e->Iex.Const.con->Ico.U8 <= 31) {
3024 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
3027 /* default case: calculate into a register and return that */
3028 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
3032 /* --------------------- RH6u --------------------- */
3034 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
3035 being an immediate in the range 1 .. 63 inclusive. Used for doing
3036 shift amounts. Only used in 64-bit mode. */
3038 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, const IRExpr* e,
3039 IREndness IEndianess )
3041 PPCRH* ri;
3042 vassert(env->mode64);
3043 ri = iselWordExpr_RH6u_wrk(env, e, IEndianess);
3044 /* sanity checks ... */
3045 switch (ri->tag) {
3046 case Prh_Imm:
3047 vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
3048 vassert(!ri->Prh.Imm.syned);
3049 return ri;
3050 case Prh_Reg:
3051 vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
3052 vassert(hregIsVirtual(ri->Prh.Reg.reg));
3053 return ri;
3054 default:
3055 vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
3059 /* DO NOT CALL THIS DIRECTLY ! */
3060 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, const IRExpr* e,
3061 IREndness IEndianess )
3063 IRType ty = typeOfIRExpr(env->type_env,e);
3064 vassert(ty == Ity_I8);
3066 /* special case: immediate */
3067 if (e->tag == Iex_Const
3068 && e->Iex.Const.con->tag == Ico_U8
3069 && e->Iex.Const.con->Ico.U8 >= 1
3070 && e->Iex.Const.con->Ico.U8 <= 63) {
3071 return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
3074 /* default case: calculate into a register and return that */
3075 return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
3079 /* --------------------- CONDCODE --------------------- */
3081 /* Generate code to evaluated a bit-typed expression, returning the
3082 condition code which would correspond when the expression would
3083 notionally have returned 1. */
3085 static PPCCondCode iselCondCode ( ISelEnv* env, const IRExpr* e,
3086 IREndness IEndianess )
3088 /* Uh, there's nothing we can sanity check here, unfortunately. */
3089 return iselCondCode_wrk(env,e, IEndianess);
3092 /* DO NOT CALL THIS DIRECTLY ! */
3093 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, const IRExpr* e,
3094 IREndness IEndianess )
3096 vassert(e);
3097 vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
3099 /* Constant 1:Bit */
3100 if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
3101 // Make a compare that will always be true:
3102 HReg r_zero = newVRegI(env);
3103 addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
3104 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3105 7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
3106 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3109 /* Not1(...) */
3110 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
3111 /* Generate code for the arg, and negate the test condition */
3112 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
3113 cond.test = invertCondTest(cond.test);
3114 return cond;
3117 /* --- patterns rooted at: 32to1 or 64to1 --- */
3119 /* 32to1, 64to1 */
3120 if (e->tag == Iex_Unop &&
3121 (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
3122 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3123 HReg tmp = newVRegI(env);
3124 /* could do better, probably -- andi. */
3125 addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
3126 src, PPCRH_Imm(False,1)));
3127 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3128 7/*cr*/, tmp, PPCRH_Imm(False,1)));
3129 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3132 /* --- patterns rooted at: CmpNEZ8 --- */
3134 /* CmpNEZ8(x) */
3135 /* Note this cloned as CmpNE8(x,0) below. */
3136 /* could do better -- andi. */
3137 if (e->tag == Iex_Unop
3138 && e->Iex.Unop.op == Iop_CmpNEZ8) {
3139 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3140 HReg tmp = newVRegI(env);
3141 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
3142 PPCRH_Imm(False,0xFF)));
3143 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3144 7/*cr*/, tmp, PPCRH_Imm(False,0)));
3145 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3148 /* --- patterns rooted at: CmpNEZ32 --- */
3150 /* CmpNEZ32(x) */
3151 if (e->tag == Iex_Unop
3152 && e->Iex.Unop.op == Iop_CmpNEZ32) {
3153 HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3154 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3155 7/*cr*/, r1, PPCRH_Imm(False,0)));
3156 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3159 /* --- patterns rooted at: Cmp*32* --- */
3161 /* Cmp*32*(x,y) */
3162 if (e->tag == Iex_Binop
3163 && (e->Iex.Binop.op == Iop_CmpEQ32
3164 || e->Iex.Binop.op == Iop_CmpNE32
3165 || e->Iex.Binop.op == Iop_CmpLT32S
3166 || e->Iex.Binop.op == Iop_CmpLT32U
3167 || e->Iex.Binop.op == Iop_CmpLE32S
3168 || e->Iex.Binop.op == Iop_CmpLE32U)) {
3169 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
3170 e->Iex.Binop.op == Iop_CmpLE32S);
3171 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3172 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
3173 addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
3174 7/*cr*/, r1, ri2));
3176 switch (e->Iex.Binop.op) {
3177 case Iop_CmpEQ32: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3178 case Iop_CmpNE32: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3179 case Iop_CmpLT32U: case Iop_CmpLT32S:
3180 return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
3181 case Iop_CmpLE32U: case Iop_CmpLE32S:
3182 return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
3183 default: vpanic("iselCondCode(ppc): CmpXX32");
3187 /* --- patterns rooted at: CmpNEZ64 --- */
3189 /* CmpNEZ64 */
3190 if (e->tag == Iex_Unop
3191 && e->Iex.Unop.op == Iop_CmpNEZ64) {
3192 if (!env->mode64) {
3193 HReg hi, lo;
3194 HReg tmp = newVRegI(env);
3195 iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg, IEndianess );
3196 addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
3197 addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
3198 7/*cr*/, tmp,PPCRH_Imm(False,0)));
3199 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3200 } else { // mode64
3201 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3202 addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
3203 7/*cr*/, r_src,PPCRH_Imm(False,0)));
3204 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3208 /* --- patterns rooted at: Cmp*64* --- */
3210 /* Cmp*64*(x,y) */
3211 if (e->tag == Iex_Binop
3212 && (e->Iex.Binop.op == Iop_CmpEQ64
3213 || e->Iex.Binop.op == Iop_CmpNE64
3214 || e->Iex.Binop.op == Iop_CmpLT64S
3215 || e->Iex.Binop.op == Iop_CmpLT64U
3216 || e->Iex.Binop.op == Iop_CmpLE64S
3217 || e->Iex.Binop.op == Iop_CmpLE64U)) {
3218 Bool syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
3219 e->Iex.Binop.op == Iop_CmpLE64S);
3220 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3221 PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
3222 vassert(env->mode64);
3223 addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
3224 7/*cr*/, r1, ri2));
3226 switch (e->Iex.Binop.op) {
3227 case Iop_CmpEQ64: return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3228 case Iop_CmpNE64: return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3229 case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
3230 case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
3231 default: vpanic("iselCondCode(ppc): CmpXX64");
3235 /* --- patterns rooted at: CmpNE8 --- */
3237 /* CmpNE8(x,0) */
3238 /* Note this is a direct copy of CmpNEZ8 above. */
3239 /* could do better -- andi. */
3240 if (e->tag == Iex_Binop
3241 && e->Iex.Binop.op == Iop_CmpNE8
3242 && isZeroU8(e->Iex.Binop.arg2)) {
3243 HReg arg = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3244 HReg tmp = newVRegI(env);
3245 addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
3246 PPCRH_Imm(False,0xFF)));
3247 addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3248 7/*cr*/, tmp, PPCRH_Imm(False,0)));
3249 return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
3252 /* var */
3253 if (e->tag == Iex_RdTmp) {
3254 HReg r_src = lookupIRTemp(env, e->Iex.RdTmp.tmp);
3255 HReg src_masked = newVRegI(env);
3256 addInstr(env,
3257 PPCInstr_Alu(Palu_AND, src_masked,
3258 r_src, PPCRH_Imm(False,1)));
3259 addInstr(env,
3260 PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3261 7/*cr*/, src_masked, PPCRH_Imm(False,1)));
3262 return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3265 vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
3266 ppIRExpr(e);
3267 vpanic("iselCondCode(ppc)");
3271 /*---------------------------------------------------------*/
3272 /*--- ISEL: Integer expressions (128 bit) ---*/
3273 /*---------------------------------------------------------*/
3275 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3276 which is returned as the first two parameters. As with
3277 iselWordExpr_R, these may be either real or virtual regs; in any
3278 case they must not be changed by subsequent code emitted by the
3279 caller. */
3281 static void iselInt128Expr ( HReg* rHi, HReg* rLo, ISelEnv* env,
3282 const IRExpr* e, IREndness IEndianess )
3284 vassert(env->mode64);
3285 iselInt128Expr_wrk(rHi, rLo, env, e, IEndianess);
3286 # if 0
3287 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3288 # endif
3289 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
3290 vassert(hregIsVirtual(*rHi));
3291 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
3292 vassert(hregIsVirtual(*rLo));
3295 /* DO NOT CALL THIS DIRECTLY ! */
3296 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env,
3297 const IRExpr* e, IREndness IEndianess )
3299 Bool mode64 = env->mode64;
3301 vassert(e);
3302 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3304 /* read 128-bit IRTemp */
3305 if (e->tag == Iex_RdTmp) {
3306 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3307 return;
3310 /* 128-bit GET */
3311 if (e->tag == Iex_Get) {
3312 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3313 GuestStatePtr(mode64) );
3314 PPCAMode* am_addr4 = advance4(env, am_addr);
3315 HReg tLo = newVRegI(env);
3316 HReg tHi = newVRegI(env);
3318 addInstr(env, PPCInstr_Load( 8, tHi, am_addr, mode64));
3319 addInstr(env, PPCInstr_Load( 8, tLo, am_addr4, mode64));
3320 *rHi = tHi;
3321 *rLo = tLo;
3322 return;
3325 /* --------- BINARY ops --------- */
3326 if (e->tag == Iex_Binop) {
3327 switch (e->Iex.Binop.op) {
3328 /* 64 x 64 -> 128 multiply */
3329 case Iop_MullU64:
3330 case Iop_MullS64: {
3331 HReg tLo = newVRegI(env);
3332 HReg tHi = newVRegI(env);
3333 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
3334 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3335 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3336 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3337 False/*lo64*/, False/*64bit mul*/,
3338 tLo, r_srcL, r_srcR));
3339 addInstr(env, PPCInstr_MulL(syned,
3340 True/*hi64*/, False/*64bit mul*/,
3341 tHi, r_srcL, r_srcR));
3342 *rHi = tHi;
3343 *rLo = tLo;
3344 return;
3347 /* 64HLto128(e1,e2) */
3348 case Iop_64HLto128:
3349 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3350 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3351 return;
3352 default:
3353 break;
3355 } /* if (e->tag == Iex_Binop) */
3358 /* --------- UNARY ops --------- */
3359 if (e->tag == Iex_Unop) {
3360 switch (e->Iex.Unop.op) {
3361 default:
3362 break;
3364 } /* if (e->tag == Iex_Unop) */
3366 vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
3367 ppIRExpr(e);
3368 vpanic("iselInt128Expr(ppc64)");
3372 /*---------------------------------------------------------*/
3373 /*--- ISEL: Integer expressions (64 bit) ---*/
3374 /*---------------------------------------------------------*/
3376 /* 32-bit mode ONLY: compute a 128-bit value into a register quad */
3377 static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo,
3378 HReg* rLo, ISelEnv* env, const IRExpr* e,
3379 IREndness IEndianess )
3381 vassert(!env->mode64);
3382 iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e, IEndianess);
3383 # if 0
3384 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3385 # endif
3386 vassert(hregClass(*rHi) == HRcInt32);
3387 vassert(hregIsVirtual(*rHi));
3388 vassert(hregClass(*rMedHi) == HRcInt32);
3389 vassert(hregIsVirtual(*rMedHi));
3390 vassert(hregClass(*rMedLo) == HRcInt32);
3391 vassert(hregIsVirtual(*rMedLo));
3392 vassert(hregClass(*rLo) == HRcInt32);
3393 vassert(hregIsVirtual(*rLo));
3396 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
3397 HReg* rMedLo, HReg* rLo,
3398 ISelEnv* env, const IRExpr* e,
3399 IREndness IEndianess )
3401 vassert(e);
3402 vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3404 /* read 128-bit IRTemp */
3405 if (e->tag == Iex_RdTmp) {
3406 lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp);
3407 return;
3410 if (e->tag == Iex_Binop) {
3412 IROp op_binop = e->Iex.Binop.op;
3413 switch (op_binop) {
3414 case Iop_64HLto128:
3415 iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess);
3416 iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess);
3417 return;
3418 default:
3419 vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3420 op_binop);
3421 break;
3425 vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
3426 return;
3429 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3430 which is returned as the first two parameters. As with
3431 iselIntExpr_R, these may be either real or virtual regs; in any
3432 case they must not be changed by subsequent code emitted by the
3433 caller. */
3435 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
3436 ISelEnv* env, const IRExpr* e,
3437 IREndness IEndianess )
3439 vassert(!env->mode64);
3440 iselInt64Expr_wrk(rHi, rLo, env, e, IEndianess);
3441 # if 0
3442 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3443 # endif
3444 vassert(hregClass(*rHi) == HRcInt32);
3445 vassert(hregIsVirtual(*rHi));
3446 vassert(hregClass(*rLo) == HRcInt32);
3447 vassert(hregIsVirtual(*rLo));
3450 /* DO NOT CALL THIS DIRECTLY ! */
3451 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
3452 ISelEnv* env, const IRExpr* e,
3453 IREndness IEndianess )
3455 vassert(e);
3456 vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
3458 /* 64-bit load */
3459 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3460 HReg tLo = newVRegI(env);
3461 HReg tHi = newVRegI(env);
3462 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr, IEndianess);
3463 vassert(!env->mode64);
3464 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3465 tHi, PPCAMode_IR( 0, r_addr ),
3466 False/*32-bit insn please*/) );
3467 addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3468 tLo, PPCAMode_IR( 4, r_addr ),
3469 False/*32-bit insn please*/) );
3470 *rHi = tHi;
3471 *rLo = tLo;
3472 return;
3475 /* 64-bit literal */
3476 if (e->tag == Iex_Const) {
3477 ULong w64 = e->Iex.Const.con->Ico.U64;
3478 UInt wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
3479 UInt wLo = ((UInt)w64) & 0xFFFFFFFF;
3480 HReg tLo = newVRegI(env);
3481 HReg tHi = newVRegI(env);
3482 vassert(e->Iex.Const.con->tag == Ico_U64);
3483 addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
3484 addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
3485 *rHi = tHi;
3486 *rLo = tLo;
3487 return;
3490 /* read 64-bit IRTemp */
3491 if (e->tag == Iex_RdTmp) {
3492 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3493 return;
3496 /* 64-bit GET */
3497 if (e->tag == Iex_Get) {
3498 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3499 GuestStatePtr(False/*mode32*/) );
3500 PPCAMode* am_addr4 = advance4(env, am_addr);
3501 HReg tLo = newVRegI(env);
3502 HReg tHi = newVRegI(env);
3503 addInstr(env, PPCInstr_Load( 4, tHi, am_addr, False/*mode32*/ ));
3504 addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
3505 *rHi = tHi;
3506 *rLo = tLo;
3507 return;
3510 /* --------- CCALL --------- */
3511 if(e->tag == Iex_CCall) {
3512 IRType ty = typeOfIRExpr(env->type_env,e);
3513 Bool mode64 = env->mode64;
3515 vassert(ty == e->Iex.CCall.retty); /* well-formedness of IR */
3517 /* be very restrictive for now. Only 32-bit ints allowed for
3518 args, and 32 bits or host machine word for return type. */
3519 vassert(!(ty == Ity_I32 || (mode64 && ty == Ity_I64)));
3521 /* Marshal args, do the call, clear stack. */
3522 UInt addToSp = 0;
3523 RetLoc rloc = mk_RetLoc_INVALID();
3524 doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
3525 e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args,
3526 IEndianess );
3527 vassert(is_sane_RetLoc(rloc));
3529 vassert(rloc.pri == RLPri_2Int);
3530 vassert(addToSp == 0);
3532 /* GPR3 now holds the destination address from Pin_Goto */
3533 HReg r_dst = newVRegI(env);
3534 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
3535 *rHi = r_dst;
3536 *rLo = r_dst;
3537 return;
3540 /* 64-bit ITE */
3541 if (e->tag == Iex_ITE) { // VFD
3542 HReg e0Lo, e0Hi, eXLo, eXHi;
3543 iselInt64Expr(&eXHi, &eXLo, env, e->Iex.ITE.iftrue, IEndianess);
3544 iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse, IEndianess);
3545 HReg tLo = newVRegI(env);
3546 HReg tHi = newVRegI(env);
3547 addInstr(env, mk_iMOVds_RR(tHi,e0Hi));
3548 addInstr(env, mk_iMOVds_RR(tLo,e0Lo));
3549 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
3550 addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(eXHi)));
3551 addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(eXLo)));
3552 *rHi = tHi;
3553 *rLo = tLo;
3554 return;
3557 /* --------- BINARY ops --------- */
3558 if (e->tag == Iex_Binop) {
3559 IROp op_binop = e->Iex.Binop.op;
3560 switch (op_binop) {
3561 /* 32 x 32 -> 64 multiply */
3562 case Iop_MullU32:
3563 case Iop_MullS32: {
3564 HReg tLo = newVRegI(env);
3565 HReg tHi = newVRegI(env);
3566 Bool syned = toBool(op_binop == Iop_MullS32);
3567 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1,
3568 IEndianess);
3569 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2,
3570 IEndianess);
3571 addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3572 False/*lo32*/, True/*32bit mul*/,
3573 tLo, r_srcL, r_srcR));
3574 addInstr(env, PPCInstr_MulL(syned,
3575 True/*hi32*/, True/*32bit mul*/,
3576 tHi, r_srcL, r_srcR));
3577 *rHi = tHi;
3578 *rLo = tLo;
3579 return;
3582 /* Or64/And64/Xor64 */
3583 case Iop_Or64:
3584 case Iop_And64:
3585 case Iop_Xor64: {
3586 HReg xLo, xHi, yLo, yHi;
3587 HReg tLo = newVRegI(env);
3588 HReg tHi = newVRegI(env);
3589 PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
3590 (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
3591 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3592 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3593 addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
3594 addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
3595 *rHi = tHi;
3596 *rLo = tLo;
3597 return;
3600 /* Add64 */
3601 case Iop_Add64: {
3602 HReg xLo, xHi, yLo, yHi;
3603 HReg tLo = newVRegI(env);
3604 HReg tHi = newVRegI(env);
3605 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3606 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3607 addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
3608 tLo, xLo, yLo));
3609 addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
3610 tHi, xHi, yHi));
3611 *rHi = tHi;
3612 *rLo = tLo;
3613 return;
3616 /* 32HLto64(e1,e2) */
3617 case Iop_32HLto64:
3618 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3619 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3620 return;
3622 /* F64toI64[S|U] */
3623 case Iop_F64toI64S: case Iop_F64toI64U: {
3624 HReg tLo = newVRegI(env);
3625 HReg tHi = newVRegI(env);
3626 HReg r1 = StackFramePtr(env->mode64);
3627 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3628 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3629 HReg fsrc = iselDblExpr(env, e->Iex.Binop.arg2,
3630 IEndianess);
3631 HReg ftmp = newVRegF(env);
3633 vassert(!env->mode64);
3634 /* Set host rounding mode */
3635 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3637 sub_from_sp( env, 16 );
3638 addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
3639 (op_binop == Iop_F64toI64S) ? True : False,
3640 True, ftmp, fsrc));
3641 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3642 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3643 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3644 add_to_sp( env, 16 );
3646 ///* Restore default FPU rounding. */
3647 //set_FPU_rounding_default( env );
3648 *rHi = tHi;
3649 *rLo = tLo;
3650 return;
3652 case Iop_D64toI64S: {
3653 HReg tLo = newVRegI(env);
3654 HReg tHi = newVRegI(env);
3655 HReg r1 = StackFramePtr(env->mode64);
3656 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3657 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3658 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
3659 HReg tmp = newVRegF(env);
3661 vassert(!env->mode64);
3662 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3663 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src));
3665 sub_from_sp( env, 16 );
3666 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3667 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3668 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3669 add_to_sp( env, 16 );
3670 *rHi = tHi;
3671 *rLo = tLo;
3672 return;
3674 case Iop_D128toI64S: {
3675 PPCFpOp fpop = Pfp_DCTFIXQ;
3676 HReg r_srcHi = newVRegF(env);
3677 HReg r_srcLo = newVRegF(env);
3678 HReg tLo = newVRegI(env);
3679 HReg tHi = newVRegI(env);
3680 HReg ftmp = newVRegF(env);
3681 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3682 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3684 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3685 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
3686 IEndianess);
3687 addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
3689 // put the D64 result into an integer register pair
3690 sub_from_sp( env, 16 );
3691 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3692 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3693 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3694 add_to_sp( env, 16 );
3695 *rHi = tHi;
3696 *rLo = tLo;
3697 return;
3699 default:
3700 break;
3702 } /* if (e->tag == Iex_Binop) */
3705 /* --------- UNARY ops --------- */
3706 if (e->tag == Iex_Unop) {
3707 switch (e->Iex.Unop.op) {
3709 /* CmpwNEZ64(e) */
3710 case Iop_CmpwNEZ64: {
3711 HReg argHi, argLo;
3712 HReg tmp1 = newVRegI(env);
3713 HReg tmp2 = newVRegI(env);
3714 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3715 /* tmp1 = argHi | argLo */
3716 addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
3717 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3718 addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
3719 addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
3720 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3721 tmp2, tmp2, PPCRH_Imm(False, 31)));
3722 *rHi = tmp2;
3723 *rLo = tmp2; /* yes, really tmp2 */
3724 return;
3727 /* Left64 */
3728 case Iop_Left64: {
3729 HReg argHi, argLo;
3730 HReg zero32 = newVRegI(env);
3731 HReg resHi = newVRegI(env);
3732 HReg resLo = newVRegI(env);
3733 iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3734 vassert(env->mode64 == False);
3735 addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
3736 /* resHi:resLo = - argHi:argLo */
3737 addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
3738 resLo, zero32, argLo ));
3739 addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
3740 resHi, zero32, argHi ));
3741 /* resHi:resLo |= srcHi:srcLo */
3742 addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
3743 addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
3744 *rHi = resHi;
3745 *rLo = resLo;
3746 return;
3749 /* 32Sto64(e) */
3750 case Iop_32Sto64: {
3751 HReg tHi = newVRegI(env);
3752 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3753 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3754 tHi, src, PPCRH_Imm(False,31)));
3755 *rHi = tHi;
3756 *rLo = src;
3757 return;
3759 case Iop_ExtractExpD64: {
3760 HReg tmp = newVRegF(env);
3761 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3762 HReg tLo = newVRegI(env);
3763 HReg tHi = newVRegI(env);
3764 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3765 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3767 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
3769 // put the D64 result into a integer register pair
3770 sub_from_sp( env, 16 );
3771 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3772 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3773 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3774 add_to_sp( env, 16 );
3775 *rHi = tHi;
3776 *rLo = tLo;
3777 return;
3779 case Iop_ExtractExpD128: {
3780 HReg r_srcHi;
3781 HReg r_srcLo;
3782 HReg tmp = newVRegF(env);
3783 HReg tLo = newVRegI(env);
3784 HReg tHi = newVRegI(env);
3785 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3786 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3788 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, IEndianess);
3789 addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
3790 r_srcHi, r_srcLo));
3792 // put the D64 result into a integer register pair
3793 sub_from_sp( env, 16 );
3794 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3795 addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3796 addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3797 add_to_sp( env, 16 );
3798 *rHi = tHi;
3799 *rLo = tLo;
3800 return;
3803 /* 32Uto64(e) */
3804 case Iop_32Uto64: {
3805 HReg tHi = newVRegI(env);
3806 HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3807 addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
3808 *rHi = tHi;
3809 *rLo = tLo;
3810 return;
3813 case Iop_128to64: {
3814 /* Narrow, return the low 64-bit half as a 32-bit
3815 * register pair */
3816 HReg r_Hi = INVALID_HREG;
3817 HReg r_MedHi = INVALID_HREG;
3818 HReg r_MedLo = INVALID_HREG;
3819 HReg r_Lo = INVALID_HREG;
3821 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3822 env, e->Iex.Unop.arg, IEndianess);
3823 *rHi = r_MedLo;
3824 *rLo = r_Lo;
3825 return;
3828 case Iop_128HIto64: {
3829 /* Narrow, return the high 64-bit half as a 32-bit
3830 * register pair */
3831 HReg r_Hi = INVALID_HREG;
3832 HReg r_MedHi = INVALID_HREG;
3833 HReg r_MedLo = INVALID_HREG;
3834 HReg r_Lo = INVALID_HREG;
3836 iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3837 env, e->Iex.Unop.arg, IEndianess);
3838 *rHi = r_Hi;
3839 *rLo = r_MedHi;
3840 return;
3843 /* V128{HI}to64 */
3844 case Iop_V128HIto64:
3845 case Iop_V128to64: {
3846 HReg r_aligned16;
3847 Int off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
3848 HReg tLo = newVRegI(env);
3849 HReg tHi = newVRegI(env);
3850 HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
3851 PPCAMode *am_off0, *am_offLO, *am_offHI;
3852 sub_from_sp( env, 32 ); // Move SP down 32 bytes
3854 // get a quadword aligned address within our stack space
3855 r_aligned16 = get_sp_aligned16( env );
3856 am_off0 = PPCAMode_IR( 0, r_aligned16 );
3857 am_offHI = PPCAMode_IR( off, r_aligned16 );
3858 am_offLO = PPCAMode_IR( off+4, r_aligned16 );
3860 // store as Vec128
3861 addInstr(env,
3862 PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
3864 // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3865 addInstr(env,
3866 PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
3867 addInstr(env,
3868 PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
3870 add_to_sp( env, 32 ); // Reset SP
3871 *rHi = tHi;
3872 *rLo = tLo;
3873 return;
3876 /* could do better than this, but for now ... */
3877 case Iop_1Sto64: {
3878 HReg tLo = newVRegI(env);
3879 HReg tHi = newVRegI(env);
3880 PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
3881 addInstr(env, PPCInstr_Set(cond,tLo));
3882 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
3883 tLo, tLo, PPCRH_Imm(False,31)));
3884 addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3885 tLo, tLo, PPCRH_Imm(False,31)));
3886 addInstr(env, mk_iMOVds_RR(tHi, tLo));
3887 *rHi = tHi;
3888 *rLo = tLo;
3889 return;
3892 case Iop_Not64: {
3893 HReg xLo, xHi;
3894 HReg tmpLo = newVRegI(env);
3895 HReg tmpHi = newVRegI(env);
3896 iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg, IEndianess);
3897 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
3898 addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
3899 *rHi = tmpHi;
3900 *rLo = tmpLo;
3901 return;
3904 /* ReinterpF64asI64(e) */
3905 /* Given an IEEE754 double, produce an I64 with the same bit
3906 pattern. */
3907 case Iop_ReinterpF64asI64: {
3908 PPCAMode *am_addr0, *am_addr1;
3909 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3910 HReg r_dstLo = newVRegI(env);
3911 HReg r_dstHi = newVRegI(env);
3913 sub_from_sp( env, 16 ); // Move SP down 16 bytes
3914 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3915 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3917 // store as F64
3918 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3919 fr_src, am_addr0 ));
3921 // load hi,lo as Ity_I32's
3922 addInstr(env, PPCInstr_Load( 4, r_dstHi,
3923 am_addr0, False/*mode32*/ ));
3924 addInstr(env, PPCInstr_Load( 4, r_dstLo,
3925 am_addr1, False/*mode32*/ ));
3926 *rHi = r_dstHi;
3927 *rLo = r_dstLo;
3929 add_to_sp( env, 16 ); // Reset SP
3930 return;
3933 case Iop_ReinterpD64asI64: {
3934 HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3935 PPCAMode *am_addr0, *am_addr1;
3936 HReg r_dstLo = newVRegI(env);
3937 HReg r_dstHi = newVRegI(env);
3940 sub_from_sp( env, 16 ); // Move SP down 16 bytes
3941 am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3942 am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3944 // store as D64
3945 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3946 fr_src, am_addr0 ));
3948 // load hi,lo as Ity_I32's
3949 addInstr(env, PPCInstr_Load( 4, r_dstHi,
3950 am_addr0, False/*mode32*/ ));
3951 addInstr(env, PPCInstr_Load( 4, r_dstLo,
3952 am_addr1, False/*mode32*/ ));
3953 *rHi = r_dstHi;
3954 *rLo = r_dstLo;
3956 add_to_sp( env, 16 ); // Reset SP
3958 return;
3961 case Iop_BCDtoDPB: {
3962 PPCCondCode cc;
3963 UInt argiregs;
3964 HReg argregs[2];
3965 Int argreg;
3966 HReg tLo = newVRegI(env);
3967 HReg tHi = newVRegI(env);
3968 HReg tmpHi;
3969 HReg tmpLo;
3970 Bool mode64 = env->mode64;
3972 argregs[0] = hregPPC_GPR3(mode64);
3973 argregs[1] = hregPPC_GPR4(mode64);
3975 argiregs = 0;
3976 argreg = 0;
3978 iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess );
3980 argiregs |= ( 1 << (argreg+3 ) );
3981 addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
3983 argiregs |= ( 1 << (argreg+3 ) );
3984 addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
3986 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3988 if (IEndianess == Iend_LE) {
3989 addInstr( env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
3990 argiregs,
3991 mk_RetLoc_simple(RLPri_2Int) ) );
3992 } else {
3993 Addr64 target;
3994 target = mode64 ? (Addr)h_calc_BCDtoDPB :
3995 toUInt( (Addr)h_calc_BCDtoDPB );
3996 addInstr( env, PPCInstr_Call( cc, target,
3997 argiregs,
3998 mk_RetLoc_simple(RLPri_2Int) ) );
4001 addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
4002 addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
4004 *rHi = tHi;
4005 *rLo = tLo;
4006 return;
4009 case Iop_DPBtoBCD: {
4010 PPCCondCode cc;
4011 UInt argiregs;
4012 HReg argregs[2];
4013 Int argreg;
4014 HReg tLo = newVRegI(env);
4015 HReg tHi = newVRegI(env);
4016 HReg tmpHi;
4017 HReg tmpLo;
4018 Bool mode64 = env->mode64;
4020 argregs[0] = hregPPC_GPR3(mode64);
4021 argregs[1] = hregPPC_GPR4(mode64);
4023 argiregs = 0;
4024 argreg = 0;
4026 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess);
4028 argiregs |= (1 << (argreg+3));
4029 addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
4031 argiregs |= (1 << (argreg+3));
4032 addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
4034 cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
4036 if (IEndianess == Iend_LE) {
4037 addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
4038 argiregs,
4039 mk_RetLoc_simple(RLPri_2Int) ) );
4040 } else {
4041 Addr64 target;
4042 target = mode64 ? (Addr)h_calc_DPBtoBCD :
4043 toUInt( (Addr)h_calc_DPBtoBCD );
4044 addInstr(env, PPCInstr_Call( cc, target, argiregs,
4045 mk_RetLoc_simple(RLPri_2Int) ) );
4048 addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
4049 addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
4051 *rHi = tHi;
4052 *rLo = tLo;
4053 return;
4056 default:
4057 break;
4059 } /* if (e->tag == Iex_Unop) */
4061 vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
4062 ppIRExpr(e);
4063 vpanic("iselInt64Expr(ppc)");
4067 /*---------------------------------------------------------*/
4068 /*--- ISEL: Floating point expressions (32 bit) ---*/
4069 /*---------------------------------------------------------*/
4071 /* Nothing interesting here; really just wrappers for
4072 64-bit stuff. */
4074 static HReg iselFltExpr ( ISelEnv* env, const IRExpr* e, IREndness IEndianess )
4076 HReg r = iselFltExpr_wrk( env, e, IEndianess );
4077 # if 0
4078 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4079 # endif
4080 vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
4081 vassert(hregIsVirtual(r));
4082 return r;
4085 /* DO NOT CALL THIS DIRECTLY */
4086 static HReg iselFltExpr_wrk ( ISelEnv* env, const IRExpr* e,
4087 IREndness IEndianess )
4089 Bool mode64 = env->mode64;
4091 IRType ty = typeOfIRExpr(env->type_env,e);
4092 vassert(ty == Ity_F32);
4094 if (e->tag == Iex_RdTmp) {
4095 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4098 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4099 PPCAMode* am_addr;
4100 HReg r_dst = newVRegF(env);
4101 vassert(e->Iex.Load.ty == Ity_F32);
4102 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/,
4103 IEndianess);
4104 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4105 return r_dst;
4108 if (e->tag == Iex_Get) {
4109 HReg r_dst = newVRegF(env);
4110 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4111 GuestStatePtr(env->mode64) );
4112 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
4113 return r_dst;
4116 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
4117 /* This is quite subtle. The only way to do the relevant
4118 truncation is to do a single-precision store and then a
4119 double precision load to get it back into a register. The
4120 problem is, if the data is then written to memory a second
4121 time, as in
4123 STbe(...) = TruncF64asF32(...)
4125 then will the second truncation further alter the value? The
4126 answer is no: flds (as generated here) followed by fsts
4127 (generated for the STbe) is the identity function on 32-bit
4128 floats, so we are safe.
4130 Another upshot of this is that if iselStmt can see the
4131 entirety of
4133 STbe(...) = TruncF64asF32(arg)
4135 then it can short circuit having to deal with TruncF64asF32
4136 individually; instead just compute arg into a 64-bit FP
4137 register and do 'fsts' (since that itself does the
4138 truncation).
4140 We generate pretty poor code here (should be ok both for
4141 32-bit and 64-bit mode); but it is expected that for the most
4142 part the latter optimisation will apply and hence this code
4143 will not often be used.
4145 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4146 HReg fdst = newVRegF(env);
4147 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4149 sub_from_sp( env, 16 );
4150 // store as F32, hence truncating
4151 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
4152 fsrc, zero_r1 ));
4153 // and reload. Good huh?! (sigh)
4154 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
4155 fdst, zero_r1 ));
4156 add_to_sp( env, 16 );
4157 return fdst;
4160 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
4161 if (mode64) {
4162 HReg fdst = newVRegF(env);
4163 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4164 HReg r1 = StackFramePtr(env->mode64);
4165 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4167 /* Set host rounding mode */
4168 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4170 sub_from_sp( env, 16 );
4172 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
4173 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4174 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4175 False, False,
4176 fdst, fdst));
4178 add_to_sp( env, 16 );
4180 ///* Restore default FPU rounding. */
4181 //set_FPU_rounding_default( env );
4182 return fdst;
4183 } else {
4184 /* 32-bit mode */
4185 HReg fdst = newVRegF(env);
4186 HReg isrcHi, isrcLo;
4187 HReg r1 = StackFramePtr(env->mode64);
4188 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4189 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
4191 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, IEndianess);
4193 /* Set host rounding mode */
4194 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4196 sub_from_sp( env, 16 );
4198 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
4199 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
4200 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4201 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4202 False, False,
4203 fdst, fdst));
4205 add_to_sp( env, 16 );
4207 ///* Restore default FPU rounding. */
4208 //set_FPU_rounding_default( env );
4209 return fdst;
4214 vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
4215 ppIRExpr(e);
4216 vpanic("iselFltExpr_wrk(ppc)");
4220 /*---------------------------------------------------------*/
4221 /*--- ISEL: Floating point expressions (64 bit) ---*/
4222 /*---------------------------------------------------------*/
4224 /* Compute a 64-bit floating point value into a register, the identity
4225 of which is returned. As with iselIntExpr_R, the reg may be either
4226 real or virtual; in any case it must not be changed by subsequent
4227 code emitted by the caller. */
4229 /* IEEE 754 formats. From http://www.freesoft.org/CIE/RFC/1832/32.htm:
4231 Type S (1 bit) E (11 bits) F (52 bits)
4232 ---- --------- ----------- -----------
4233 signalling NaN u 2047 (max) .0uuuuu---u
4234 (with at least
4235 one 1 bit)
4236 quiet NaN u 2047 (max) .1uuuuu---u
4238 negative infinity 1 2047 (max) .000000---0
4240 positive infinity 0 2047 (max) .000000---0
4242 negative zero 1 0 .000000---0
4244 positive zero 0 0 .000000---0
4247 static HReg iselDblExpr ( ISelEnv* env, const IRExpr* e, IREndness IEndianess )
4249 HReg r = iselDblExpr_wrk( env, e, IEndianess );
4250 # if 0
4251 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4252 # endif
4253 vassert(hregClass(r) == HRcFlt64);
4254 vassert(hregIsVirtual(r));
4255 return r;
4258 /* DO NOT CALL THIS DIRECTLY */
4259 static HReg iselDblExpr_wrk ( ISelEnv* env, const IRExpr* e,
4260 IREndness IEndianess )
4262 Bool mode64 = env->mode64;
4263 IRType ty = typeOfIRExpr(env->type_env,e);
4264 vassert(e);
4265 vassert(ty == Ity_F64);
4267 if (e->tag == Iex_RdTmp) {
4268 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4271 /* --------- LITERAL --------- */
4272 if (e->tag == Iex_Const) {
4273 union { UInt u32x2[2]; ULong u64; Double f64; } u;
4274 vassert(sizeof(u) == 8);
4275 vassert(sizeof(u.u64) == 8);
4276 vassert(sizeof(u.f64) == 8);
4277 vassert(sizeof(u.u32x2) == 8);
4279 if (e->Iex.Const.con->tag == Ico_F64) {
4280 u.f64 = e->Iex.Const.con->Ico.F64;
4282 else if (e->Iex.Const.con->tag == Ico_F64i) {
4283 u.u64 = e->Iex.Const.con->Ico.F64i;
4285 else
4286 vpanic("iselDblExpr(ppc): const");
4288 if (!mode64) {
4289 HReg r_srcHi = newVRegI(env);
4290 HReg r_srcLo = newVRegI(env);
4291 addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
4292 addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
4293 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4294 } else { // mode64
4295 HReg r_src = newVRegI(env);
4296 addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
4297 return mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
4301 /* --------- LOAD --------- */
4302 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4303 HReg r_dst = newVRegF(env);
4304 PPCAMode* am_addr;
4305 vassert(e->Iex.Load.ty == Ity_F64);
4306 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/,
4307 IEndianess);
4308 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4309 return r_dst;
4312 /* --------- GET --------- */
4313 if (e->tag == Iex_Get) {
4314 HReg r_dst = newVRegF(env);
4315 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4316 GuestStatePtr(mode64) );
4317 addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
4318 return r_dst;
4321 /* --------- OPS --------- */
4322 if (e->tag == Iex_Qop) {
4323 PPCFpOp fpop = Pfp_INVALID;
4324 switch (e->Iex.Qop.details->op) {
4325 case Iop_MAddF64: fpop = Pfp_MADDD; break;
4326 case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
4327 case Iop_MSubF64: fpop = Pfp_MSUBD; break;
4328 case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
4329 default: break;
4331 if (fpop != Pfp_INVALID) {
4332 HReg r_dst = newVRegF(env);
4333 HReg r_srcML = iselDblExpr(env, e->Iex.Qop.details->arg2,
4334 IEndianess);
4335 HReg r_srcMR = iselDblExpr(env, e->Iex.Qop.details->arg3,
4336 IEndianess);
4337 HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4,
4338 IEndianess);
4339 set_FPU_rounding_mode( env, e->Iex.Qop.details->arg1, IEndianess );
4340 addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
4341 r_srcML, r_srcMR, r_srcAcc));
4342 return r_dst;
4346 if (e->tag == Iex_Triop) {
4347 IRTriop *triop = e->Iex.Triop.details;
4348 PPCFpOp fpop = Pfp_INVALID;
4349 switch (triop->op) {
4350 case Iop_AddF64: fpop = Pfp_ADDD; break;
4351 case Iop_SubF64: fpop = Pfp_SUBD; break;
4352 case Iop_MulF64: fpop = Pfp_MULD; break;
4353 case Iop_DivF64: fpop = Pfp_DIVD; break;
4354 case Iop_AddF64r32: fpop = Pfp_ADDS; break;
4355 case Iop_SubF64r32: fpop = Pfp_SUBS; break;
4356 case Iop_MulF64r32: fpop = Pfp_MULS; break;
4357 case Iop_DivF64r32: fpop = Pfp_DIVS; break;
4358 default: break;
4360 if (fpop != Pfp_INVALID) {
4361 HReg r_dst = newVRegF(env);
4362 HReg r_srcL = iselDblExpr(env, triop->arg2, IEndianess);
4363 HReg r_srcR = iselDblExpr(env, triop->arg3, IEndianess);
4364 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4365 addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
4366 return r_dst;
4370 if (e->tag == Iex_Binop) {
4371 PPCFpOp fpop = Pfp_INVALID;
4372 switch (e->Iex.Binop.op) {
4373 case Iop_SqrtF64: fpop = Pfp_SQRT; break;
4374 default: break;
4376 if (fpop == Pfp_SQRT) {
4377 HReg fr_dst = newVRegF(env);
4378 HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4379 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4380 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4381 return fr_dst;
4385 if (e->tag == Iex_Binop) {
4387 if (e->Iex.Binop.op == Iop_F128toF64) {
4388 HReg fr_dst = newVRegF(env);
4389 HReg fr_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
4390 HReg tmp = newVRegV(env);
4391 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4392 PPCAMode* eight_r1 = PPCAMode_IR( 8, StackFramePtr(env->mode64) );
4393 PPCFpOp fpop = Pfp_INVALID;
4395 if (FPU_rounding_mode_isOdd(e->Iex.Binop.arg1)) {
4396 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4397 fpop = Pfp_FPQTODRNDODD;
4398 } else {
4399 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4400 fpop = Pfp_FPQTOD;
4403 addInstr(env, PPCInstr_Fp128Unary(fpop, tmp, fr_src));
4405 /* result is in a 128-bit vector register, move to 64-bit reg to
4406 * match the Iop specification. The result will get moved back
4407 * to a 128-bit register and stored once the value is returned.
4409 sub_from_sp( env, 16 );
4410 addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, tmp, zero_r1));
4411 if (IEndianess == Iend_LE)
4412 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, eight_r1));
4413 else
4414 /* High 64-bits stored at lower address */
4415 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, zero_r1));
4417 add_to_sp( env, 16 );
4419 return fr_dst;
4422 if (e->Iex.Binop.op == Iop_RoundF64toF32) {
4423 HReg r_dst = newVRegF(env);
4424 HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4425 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4426 addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
4427 //set_FPU_rounding_default( env );
4428 return r_dst;
4431 if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
4432 if (mode64) {
4433 HReg fdst = newVRegF(env);
4434 HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4435 HReg r1 = StackFramePtr(env->mode64);
4436 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4438 /* Set host rounding mode */
4439 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4441 sub_from_sp( env, 16 );
4443 addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
4444 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4445 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4446 e->Iex.Binop.op == Iop_I64StoF64,
4447 True/*fdst is 64 bit*/,
4448 fdst, fdst));
4450 add_to_sp( env, 16 );
4452 ///* Restore default FPU rounding. */
4453 //set_FPU_rounding_default( env );
4454 return fdst;
4455 } else {
4456 /* 32-bit mode */
4457 HReg fdst = newVRegF(env);
4458 HReg isrcHi, isrcLo;
4459 HReg r1 = StackFramePtr(env->mode64);
4460 PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4461 PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
4463 iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2,
4464 IEndianess);
4466 /* Set host rounding mode */
4467 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4469 sub_from_sp( env, 16 );
4471 addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
4472 addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
4473 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4474 addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4475 e->Iex.Binop.op == Iop_I64StoF64,
4476 True/*fdst is 64 bit*/,
4477 fdst, fdst));
4479 add_to_sp( env, 16 );
4481 ///* Restore default FPU rounding. */
4482 //set_FPU_rounding_default( env );
4483 return fdst;
4489 if (e->tag == Iex_Unop) {
4490 PPCFpOp fpop = Pfp_INVALID;
4491 switch (e->Iex.Unop.op) {
4492 case Iop_NegF64: fpop = Pfp_NEG; break;
4493 case Iop_AbsF64: fpop = Pfp_ABS; break;
4494 case Iop_RSqrtEst5GoodF64: fpop = Pfp_RSQRTE; break;
4495 case Iop_RoundF64toF64_NegINF: fpop = Pfp_FRIM; break;
4496 case Iop_RoundF64toF64_PosINF: fpop = Pfp_FRIP; break;
4497 case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
4498 case Iop_RoundF64toF64_ZERO: fpop = Pfp_FRIZ; break;
4499 default: break;
4501 if (fpop != Pfp_INVALID) {
4502 HReg fr_dst = newVRegF(env);
4503 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4504 addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4505 return fr_dst;
4509 if (e->tag == Iex_Unop) {
4510 switch (e->Iex.Unop.op) {
4511 case Iop_F128HItoF64:
4512 case Iop_F128LOtoF64:
4514 /* put upper/lower 64-bits of F128 into an F64. */
4515 HReg r_aligned16;
4516 HReg fdst = newVRegF(env);
4517 HReg fsrc = iselFp128Expr(env, e->Iex.Unop.arg, IEndianess);
4518 PPCAMode *am_off0, *am_off8, *am_off_arg;
4519 sub_from_sp( env, 32 ); // Move SP down 32 bytes
4521 // get a quadword aligned address within our stack space
4522 r_aligned16 = get_sp_aligned16( env );
4523 am_off0 = PPCAMode_IR( 0, r_aligned16 );
4524 am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
4526 /* store 128-bit floating point value to memory, load low word
4527 * or high to 64-bit destination floating point register
4529 addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, fsrc, am_off0));
4530 if (IEndianess == Iend_LE) {
4531 if (e->Iex.Binop.op == Iop_F128HItoF64)
4532 am_off_arg = am_off8;
4533 else
4534 am_off_arg = am_off0;
4535 } else {
4536 if (e->Iex.Binop.op == Iop_F128HItoF64)
4537 am_off_arg = am_off0;
4538 else
4539 am_off_arg = am_off8;
4541 addInstr(env,
4542 PPCInstr_FpLdSt( True /*load*/,
4543 8, fdst,
4544 am_off_arg ));
4545 add_to_sp( env, 32 ); // Reset SP
4546 return fdst;
4548 case Iop_ReinterpI64asF64: {
4549 /* Given an I64, produce an IEEE754 double with the same
4550 bit pattern. */
4551 if (!mode64) {
4552 HReg r_srcHi, r_srcLo;
4553 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4554 IEndianess);
4555 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4556 } else {
4557 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4558 return mk_LoadR64toFPR( env, r_src );
4562 case Iop_F32toF64: {
4563 if (e->Iex.Unop.arg->tag == Iex_Unop &&
4564 e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) {
4565 e = e->Iex.Unop.arg;
4567 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4568 HReg fr_dst = newVRegF(env);
4569 PPCAMode *am_addr;
4571 sub_from_sp( env, 16 ); // Move SP down 16 bytes
4572 am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4574 // store src as Ity_I32's
4575 addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 ));
4577 // load single precision float, but the end results loads into a
4578 // 64-bit FP register -- i.e., F64.
4579 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr));
4581 add_to_sp( env, 16 ); // Reset SP
4582 return fr_dst;
4586 /* this is a no-op */
4587 HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
4588 return res;
4590 default:
4591 break;
4595 /* --------- MULTIPLEX --------- */
4596 if (e->tag == Iex_ITE) { // VFD
4597 if (ty == Ity_F64
4598 && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
4599 HReg fr1 = iselDblExpr(env, e->Iex.ITE.iftrue, IEndianess);
4600 HReg fr0 = iselDblExpr(env, e->Iex.ITE.iffalse, IEndianess);
4601 HReg fr_dst = newVRegF(env);
4602 addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, fr0 ));
4603 PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
4604 addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr1 ));
4605 return fr_dst;
4609 vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
4610 ppIRExpr(e);
4611 vpanic("iselDblExpr_wrk(ppc)");
4614 static HReg iselDfp32Expr(ISelEnv* env, const IRExpr* e, IREndness IEndianess)
4616 HReg r = iselDfp32Expr_wrk( env, e, IEndianess );
4617 vassert(hregClass(r) == HRcFlt64);
4618 vassert( hregIsVirtual(r) );
4619 return r;
4622 /* DO NOT CALL THIS DIRECTLY */
4623 static HReg iselDfp32Expr_wrk(ISelEnv* env, const IRExpr* e,
4624 IREndness IEndianess)
4626 Bool mode64 = env->mode64;
4627 IRType ty = typeOfIRExpr( env->type_env, e );
4629 vassert( e );
4630 vassert( ty == Ity_D32 );
4632 /* --------- GET --------- */
4633 if (e->tag == Iex_Get) {
4634 HReg r_dst = newVRegF( env );
4635 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4636 GuestStatePtr(mode64) );
4637 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4638 return r_dst;
4641 /* --------- LOAD --------- */
4642 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4643 PPCAMode* am_addr;
4644 HReg r_dst = newVRegF(env);
4645 vassert(e->Iex.Load.ty == Ity_D32);
4646 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D32/*xfer*/,
4647 IEndianess);
4648 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4649 return r_dst;
4652 /* --------- OPS --------- */
4653 if (e->tag == Iex_Binop) {
4654 if (e->Iex.Binop.op == Iop_D64toD32) {
4655 HReg fr_dst = newVRegF(env);
4656 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4657 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4658 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DRSP, fr_dst, fr_src));
4659 return fr_dst;
4663 ppIRExpr( e );
4664 vpanic( "iselDfp32Expr_wrk(ppc)" );
4667 static HReg iselFp128Expr( ISelEnv* env, const IRExpr* e, IREndness IEndianess )
4669 HReg r = iselFp128Expr_wrk( env, e, IEndianess );
4670 vassert(hregClass(r) == HRcVec128);
4671 vassert(hregIsVirtual(r));
4672 return r;
4675 /* DO NOT CALL THIS DIRECTLY */
4676 static HReg iselFp128Expr_wrk( ISelEnv* env, const IRExpr* e,
4677 IREndness IEndianess)
4679 Bool mode64 = env->mode64;
4680 PPCFpOp fpop = Pfp_INVALID;
4681 IRType ty = typeOfIRExpr(env->type_env,e);
4683 vassert(e);
4684 vassert( ty == Ity_F128 );
4686 /* read 128-bit IRTemp */
4687 if (e->tag == Iex_RdTmp) {
4688 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4691 if (e->tag == Iex_Get) {
4692 /* Guest state vectors are 16byte aligned,
4693 so don't need to worry here */
4694 HReg dst = newVRegV(env);
4696 addInstr(env,
4697 PPCInstr_AvLdSt( True/*load*/, 16, dst,
4698 PPCAMode_IR( e->Iex.Get.offset,
4699 GuestStatePtr(mode64) )));
4700 return dst;
4703 if (e->tag == Iex_Unop) {
4704 switch (e->Iex.Unop.op) {
4705 case Iop_TruncF128toI64S:
4706 fpop = Pfp_TRUNCFPQTOISD; goto do_Un_F128;
4707 case Iop_TruncF128toI32S:
4708 fpop = Pfp_TRUNCFPQTOISW; goto do_Un_F128;
4709 case Iop_TruncF128toI64U:
4710 fpop = Pfp_TRUNCFPQTOIUD; goto do_Un_F128;
4711 case Iop_TruncF128toI32U:
4712 fpop = Pfp_TRUNCFPQTOIUW; goto do_Un_F128;
4714 do_Un_F128: {
4715 HReg r_dst = newVRegV(env);
4716 HReg r_src = iselFp128Expr(env, e->Iex.Unop.arg, IEndianess);
4717 addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, r_src));
4718 return r_dst;
4721 case Iop_F64toF128: {
4722 fpop = Pfp_FPDTOQ;
4723 HReg r_dst = newVRegV(env);
4724 HReg r_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4725 HReg v128tmp = newVRegV(env);
4726 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4728 /* value is in 64-bit float reg, need to move to 128-bit vector reg */
4729 sub_from_sp( env, 16 );
4730 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, r_src, zero_r1));
4731 addInstr(env, PPCInstr_AvLdSt(True/*load*/, 16, v128tmp, zero_r1));
4732 add_to_sp( env, 16 );
4734 addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, v128tmp));
4735 return r_dst;
4738 case Iop_I64StoF128:
4739 fpop = Pfp_IDSTOQ; goto do_Un_int_F128;
4740 case Iop_I64UtoF128:
4741 fpop = Pfp_IDUTOQ; goto do_Un_int_F128;
4743 do_Un_int_F128: {
4744 HReg r_dst = newVRegV(env);
4745 HReg tmp = newVRegV(env);
4746 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4747 PPCAMode *am_offhi, *am_offlo;
4748 HReg r_aligned16;
4750 /* source is in a 64-bit integer reg, move to 128-bit float reg
4751 * do this via the stack (easy, convenient, etc).
4753 sub_from_sp( env, 32 ); // Move SP down
4755 /* Get a quadword aligned address within our stack space */
4756 r_aligned16 = get_sp_aligned16( env );
4758 am_offlo = PPCAMode_IR( 0, r_aligned16 );
4759 am_offhi = PPCAMode_IR( 8, r_aligned16 );
4761 /* Inst only uses the upper 64-bit of the source */
4762 addInstr(env, PPCInstr_Load(8, r_src, am_offhi, mode64));
4764 /* Fetch result back from stack. */
4765 addInstr(env, PPCInstr_AvLdSt(True/*load*/, 16, tmp, am_offlo));
4767 add_to_sp( env, 32 ); // Reset SP
4769 addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, tmp));
4770 return r_dst;
4773 default:
4774 break;
4775 } /* switch (e->Iex.Unop.op) */
4776 } /* if (e->tag == Iex_Unop) */
4778 if (e->tag == Iex_Binop) {
4779 switch (e->Iex.Binop.op) {
4781 case Iop_F64HLtoF128:
4783 HReg dst = newVRegV(env);
4784 HReg r_src_hi = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
4785 HReg r_src_lo = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4786 PPCAMode *am_offhi, *am_offlo;
4787 HReg r_aligned16;
4789 /* do this via the stack (easy, convenient, etc) */
4790 sub_from_sp( env, 16 ); // Move SP down
4792 /* Get a quadword aligned address within our stack space */
4793 r_aligned16 = get_sp_aligned16( env );
4795 am_offlo = PPCAMode_IR( 0, r_aligned16 );
4796 am_offhi = PPCAMode_IR( 8, r_aligned16 );
4798 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8,
4799 r_src_lo, am_offlo));
4800 addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8,
4801 r_src_hi, am_offhi));
4803 /* Fetch result back from stack. */
4804 addInstr(env, PPCInstr_AvLdSt(True/*load*/, 16,
4805 dst, am_offlo));
4807 add_to_sp( env, 16 ); // Reset SP
4808 return dst;
4810 case Iop_F128toI128S:
4812 HReg dst = newVRegV(env);
4813 HReg r_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
4814 PPCRI* rm = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4815 /* Note: rm is a set of three bit fields that specify the
4816 * rounding mode and which of the two instructions to issue.
4818 addInstr(env, PPCInstr_AvBinaryInt(Pav_F128toI128S, dst,
4819 r_src, rm));
4820 return dst;
4822 case Iop_RndF128:
4824 HReg dst = newVRegV(env);
4825 HReg r_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
4826 PPCRI* rm = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4827 /* Note: rm is a set of three bit fields that specify the
4828 * rounding mode and which of the two instructions to issue.
4830 addInstr(env, PPCInstr_AvBinaryInt(Pav_ROUNDFPQ, dst,
4831 r_src, rm));
4832 return dst;
4834 case Iop_SqrtF128:
4835 if (FPU_rounding_mode_isOdd(e->Iex.Binop.arg1)) {
4836 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4837 fpop = Pfp_FPSQRTQRNDODD;
4838 goto do_Bin_F128;
4839 } else {
4840 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4841 fpop = Pfp_FPSQRTQ;
4842 goto do_Bin_F128;
4844 case Iop_F128toF32:
4845 if (FPU_rounding_mode_isOdd(e->Iex.Binop.arg1)) {
4846 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4847 fpop = Pfp_FPQTOWRNDODD;
4848 goto do_Bin_F128;
4849 } else {
4850 set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4851 fpop = Pfp_FPQTOW;
4852 goto do_Bin_F128;
4854 do_Bin_F128: {
4855 HReg r_dst = newVRegV(env);
4856 HReg r_src = iselFp128Expr(env, e->Iex.Binop.arg2, IEndianess);
4857 addInstr(env, PPCInstr_Fp128Unary(fpop, r_dst, r_src));
4858 return r_dst;
4861 default:
4862 break;
4863 } /* switch (e->Iex.Binop.op) */
4864 } /* if (e->tag == Iex_Binop) */
4866 if (e->tag == Iex_Triop) {
4867 IRTriop *triop = e->Iex.Triop.details;
4869 switch (triop->op) {
4870 case Iop_AddF128:
4871 if (FPU_rounding_mode_isOdd(triop->arg1)) {
4872 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4873 fpop = Pfp_FPADDQRNDODD; goto do_Tri_F128;
4874 } else {
4875 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4876 fpop = Pfp_FPADDQ; goto do_Tri_F128;
4878 case Iop_SubF128:
4879 if (FPU_rounding_mode_isOdd(triop->arg1)) {
4880 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4881 fpop = Pfp_FPSUBQRNDODD; goto do_Tri_F128;
4882 } else {
4883 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4884 fpop = Pfp_FPSUBQ; goto do_Tri_F128;
4886 case Iop_MulF128:
4887 if (FPU_rounding_mode_isOdd(triop->arg1)) {
4888 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4889 fpop = Pfp_FPMULQRNDODD; goto do_Tri_F128;
4890 } else {
4891 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4892 fpop = Pfp_FPMULQ; goto do_Tri_F128;
4894 case Iop_DivF128:
4895 if (FPU_rounding_mode_isOdd(triop->arg1)) {
4896 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4897 fpop = Pfp_FPDIVQRNDODD; goto do_Tri_F128;
4898 } else {
4899 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4900 fpop = Pfp_FPDIVQ; goto do_Tri_F128;
4902 case Iop_MAddF128:
4903 if (FPU_rounding_mode_isOdd(triop->arg1)) {
4904 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4905 fpop = Pfp_FPMULADDQRNDODD; goto do_Tri_F128;
4906 } else {
4907 set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4908 fpop = Pfp_FPMULADDQ; goto do_Tri_F128;
4911 do_Tri_F128: {
4912 HReg r_dst = newVRegV(env);
4913 HReg r_srcL = iselFp128Expr(env, triop->arg2, IEndianess);
4914 HReg r_srcR = iselFp128Expr(env, triop->arg3, IEndianess);
4916 addInstr(env, PPCInstr_Fp128Binary(fpop, r_dst, r_srcL, r_srcR));
4917 return r_dst;
4920 default:
4921 break;
4922 } /* switch (e->Iex.Triop.op) */
4924 } /* if (e->tag == Iex_Trinop) */
4926 if (e->tag == Iex_Qop) {
4927 IRQop *qop = e->Iex.Qop.details;
4929 switch (qop->op) {
4930 case Iop_MAddF128:
4931 if (FPU_rounding_mode_isOdd(qop->arg1)) {
4932 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4933 fpop = Pfp_FPMULADDQRNDODD; goto do_Quad_F128;
4934 } else {
4935 set_FPU_rounding_mode( env, qop->arg1, IEndianess );
4936 fpop = Pfp_FPMULADDQ; goto do_Quad_F128;
4938 case Iop_MSubF128:
4939 if (FPU_rounding_mode_isOdd(qop->arg1)) {
4940 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4941 fpop = Pfp_FPMULSUBQRNDODD; goto do_Quad_F128;
4942 } else {
4943 set_FPU_rounding_mode( env, qop->arg1, IEndianess );
4944 fpop = Pfp_FPMULSUBQ; goto do_Quad_F128;
4946 case Iop_NegMAddF128:
4947 if (FPU_rounding_mode_isOdd(qop->arg1)) {
4948 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4949 fpop = Pfp_FPNEGMULADDQRNDODD; goto do_Quad_F128;
4950 } else {
4951 set_FPU_rounding_mode( env, qop->arg1, IEndianess );
4952 fpop = Pfp_FPNEGMULADDQ; goto do_Quad_F128;
4954 case Iop_NegMSubF128:
4955 if (FPU_rounding_mode_isOdd(qop->arg1)) {
4956 /* use rounding mode specified by RN. Issue inst with R0 = 0 */
4957 fpop = Pfp_FPNEGMULSUBQRNDODD; goto do_Quad_F128;
4958 } else {
4959 set_FPU_rounding_mode( env, qop->arg1, IEndianess );
4960 fpop = Pfp_FPNEGMULSUBQ; goto do_Quad_F128;
4963 do_Quad_F128: {
4964 HReg r_dst = iselFp128Expr(env, qop->arg3,
4965 IEndianess);
4966 HReg r_srcL = iselFp128Expr(env, qop->arg2,
4967 IEndianess);
4968 HReg r_srcR = iselFp128Expr(env, qop->arg4,
4969 IEndianess);
4971 addInstr(env, PPCInstr_Fp128Trinary(fpop, r_dst, r_srcL, r_srcR));
4972 return r_dst;
4975 default:
4976 break;
4978 } /* if (e->tag == Iex_Qop) */
4980 ppIRExpr( e );
4981 vpanic( "iselFp128Expr(ppc64)" );
4984 static HReg iselDfp64Expr(ISelEnv* env, const IRExpr* e, IREndness IEndianess)
4986 HReg r = iselDfp64Expr_wrk( env, e, IEndianess );
4987 vassert(hregClass(r) == HRcFlt64);
4988 vassert( hregIsVirtual(r) );
4989 return r;
4992 /* DO NOT CALL THIS DIRECTLY */
4993 static HReg iselDfp64Expr_wrk(ISelEnv* env, const IRExpr* e,
4994 IREndness IEndianess)
4996 Bool mode64 = env->mode64;
4997 IRType ty = typeOfIRExpr( env->type_env, e );
4998 HReg r_dstHi, r_dstLo;
5000 vassert( e );
5001 vassert( ty == Ity_D64 );
5003 if (e->tag == Iex_RdTmp) {
5004 return lookupIRTemp( env, e->Iex.RdTmp.tmp );
5007 /* --------- GET --------- */
5008 if (e->tag == Iex_Get) {
5009 HReg r_dst = newVRegF( env );
5010 PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
5011 GuestStatePtr(mode64) );
5012 addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
5013 return r_dst;
5016 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
5017 PPCAMode* am_addr;
5018 HReg r_dst = newVRegF(env);
5019 vassert(e->Iex.Load.ty == Ity_D64);
5020 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D64/*xfer*/,
5021 IEndianess);
5022 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
5023 return r_dst;
5026 /* --------- OPS --------- */
5027 if (e->tag == Iex_Qop) {
5028 HReg r_dst = newVRegF( env );
5029 return r_dst;
5032 if (e->tag == Iex_Unop) {
5033 HReg fr_dst = newVRegF(env);
5034 switch (e->Iex.Unop.op) {
5035 case Iop_ReinterpI64asD64: {
5036 /* Given an I64, produce an IEEE754 DFP with the same
5037 bit pattern. */
5038 if (!mode64) {
5039 HReg r_srcHi, r_srcLo;
5040 iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
5041 IEndianess);
5042 return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
5043 } else {
5044 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5045 return mk_LoadR64toFPR( env, r_src );
5048 case Iop_D32toD64: {
5049 HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg, IEndianess);
5050 addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src));
5051 return fr_dst;
5053 case Iop_D128HItoD64:
5054 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
5055 IEndianess );
5056 return r_dstHi;
5057 case Iop_D128LOtoD64:
5058 iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
5059 IEndianess );
5060 return r_dstLo;
5061 case Iop_InsertExpD64: {
5062 HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
5063 HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
5065 addInstr(env, PPCInstr_Dfp64Binary(Pfp_DIEX, fr_dst, fr_srcL,
5066 fr_srcR));
5067 return fr_dst;
5069 default:
5070 vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
5071 (Int)e->Iex.Unop.op );
5075 if (e->tag == Iex_Binop) {
5076 PPCFpOp fpop = Pfp_INVALID;
5077 HReg fr_dst = newVRegF(env);
5079 switch (e->Iex.Binop.op) {
5080 case Iop_D128toD64: fpop = Pfp_DRDPQ; break;
5081 case Iop_D64toD32: fpop = Pfp_DRSP; break;
5082 case Iop_I64StoD64: fpop = Pfp_DCFFIX; break;
5083 case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break;
5084 default: break;
5086 if (fpop == Pfp_DRDPQ) {
5087 HReg r_srcHi = newVRegF(env);
5088 HReg r_srcLo = newVRegF(env);
5090 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
5091 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
5092 IEndianess);
5093 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
5094 return fr_dst;
5096 } else if (fpop == Pfp_DRINTN) {
5097 HReg fr_src = newVRegF(env);
5098 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
5100 /* NOTE, this IOP takes a DFP value and rounds to the
5101 * neares floating point integer value, i.e. fractional part
5102 * is zero. The result is a decimal floating point number.
5103 * the INT in the name is a bit misleading.
5105 fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
5106 addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc));
5107 return fr_dst;
5109 } else if (fpop == Pfp_DRSP) {
5110 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
5111 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
5112 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
5113 return fr_dst;
5115 } else if (fpop == Pfp_DCFFIX) {
5116 HReg fr_src = newVRegF(env);
5117 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
5119 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
5120 sub_from_sp( env, 16 );
5122 // put the I64 value into a floating point register
5123 if (mode64) {
5124 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5126 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5127 } else {
5128 HReg tmpHi, tmpLo;
5129 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5131 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2,
5132 IEndianess);
5133 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
5134 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
5137 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
5138 addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
5139 add_to_sp( env, 16 );
5140 return fr_dst;
5143 switch (e->Iex.Binop.op) {
5144 /* shift instructions D64, I32 -> D64 */
5145 case Iop_ShlD64: fpop = Pfp_DSCLI; break;
5146 case Iop_ShrD64: fpop = Pfp_DSCRI; break;
5147 default: break;
5149 if (fpop != Pfp_INVALID) {
5150 HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
5151 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
5153 /* shift value must be an immediate value */
5154 vassert(shift->tag == Pri_Imm);
5156 addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift));
5157 return fr_dst;
5160 switch (e->Iex.Binop.op) {
5161 case Iop_InsertExpD64:
5162 fpop = Pfp_DIEX;
5163 break;
5164 default: break;
5166 if (fpop != Pfp_INVALID) {
5167 HReg fr_srcL = newVRegF(env);
5168 HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
5169 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
5170 sub_from_sp( env, 16 );
5172 if (env->mode64) {
5173 // put the I64 value into a floating point reg
5174 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5176 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5177 } else {
5178 // put the I64 register pair into a floating point reg
5179 HReg tmpHi;
5180 HReg tmpLo;
5181 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5183 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1,
5184 IEndianess);
5185 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/));
5186 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/));
5188 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1));
5189 addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL,
5190 fr_srcR));
5191 add_to_sp( env, 16 );
5192 return fr_dst;
5196 if (e->tag == Iex_Triop) {
5197 IRTriop *triop = e->Iex.Triop.details;
5198 PPCFpOp fpop = Pfp_INVALID;
5200 switch (triop->op) {
5201 case Iop_AddD64:
5202 fpop = Pfp_DFPADD;
5203 break;
5204 case Iop_SubD64:
5205 fpop = Pfp_DFPSUB;
5206 break;
5207 case Iop_MulD64:
5208 fpop = Pfp_DFPMUL;
5209 break;
5210 case Iop_DivD64:
5211 fpop = Pfp_DFPDIV;
5212 break;
5213 default:
5214 break;
5216 if (fpop != Pfp_INVALID) {
5217 HReg r_dst = newVRegF( env );
5218 HReg r_srcL = iselDfp64Expr( env, triop->arg2, IEndianess );
5219 HReg r_srcR = iselDfp64Expr( env, triop->arg3, IEndianess );
5221 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
5222 addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) );
5223 return r_dst;
5226 switch (triop->op) {
5227 case Iop_QuantizeD64: fpop = Pfp_DQUA; break;
5228 case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
5229 default: break;
5231 if (fpop == Pfp_DQUA) {
5232 HReg r_dst = newVRegF(env);
5233 HReg r_srcL = iselDfp64Expr(env, triop->arg2, IEndianess);
5234 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
5235 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
5236 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR,
5237 rmc));
5238 return r_dst;
5240 } else if (fpop == Pfp_RRDTR) {
5241 HReg r_dst = newVRegF(env);
5242 HReg r_srcL = newVRegF(env);
5243 HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
5244 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
5245 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
5246 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
5248 /* Move I8 to float register to issue instruction */
5249 sub_from_sp( env, 16 );
5250 if (mode64)
5251 addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
5252 else
5253 addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/));
5255 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
5256 add_to_sp( env, 16 );
5258 // will set TE and RMC when issuing instruction
5259 addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
5260 return r_dst;
5264 ppIRExpr( e );
5265 vpanic( "iselDfp64Expr_wrk(ppc)" );
5268 static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, const IRExpr* e,
5269 IREndness IEndianess)
5271 iselDfp128Expr_wrk( rHi, rLo, env, e, IEndianess );
5272 vassert( hregIsVirtual(*rHi) );
5273 vassert( hregIsVirtual(*rLo) );
5276 /* DO NOT CALL THIS DIRECTLY */
5277 static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env,
5278 const IRExpr* e, IREndness IEndianess)
5280 vassert( e );
5281 vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 );
5283 /* read 128-bit IRTemp */
5284 if (e->tag == Iex_RdTmp) {
5285 lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
5286 return;
5289 if (e->tag == Iex_Unop) {
5290 HReg r_dstHi = newVRegF(env);
5291 HReg r_dstLo = newVRegF(env);
5293 if (e->Iex.Unop.op == Iop_I64StoD128) {
5294 HReg fr_src = newVRegF(env);
5295 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
5297 // put the I64 value into a floating point reg
5298 if (env->mode64) {
5299 HReg tmp = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5300 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5301 } else {
5302 HReg tmpHi, tmpLo;
5303 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5305 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
5306 IEndianess);
5307 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
5308 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
5311 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
5312 addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo,
5313 fr_src));
5316 if (e->Iex.Unop.op == Iop_D64toD128) {
5317 HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
5319 /* Source is 64bit, result is 128 bit. High 64bit source arg,
5320 * is ignored by the instruction. Set high arg to r_src just
5321 * to meet the vassert tests.
5323 addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo,
5324 r_src, r_src));
5326 *rHi = r_dstHi;
5327 *rLo = r_dstLo;
5328 return;
5331 /* --------- OPS --------- */
5332 if (e->tag == Iex_Binop) {
5333 HReg r_srcHi;
5334 HReg r_srcLo;
5336 switch (e->Iex.Binop.op) {
5337 case Iop_D64HLtoD128:
5338 r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1, IEndianess );
5339 r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2, IEndianess );
5340 *rHi = r_srcHi;
5341 *rLo = r_srcLo;
5342 return;
5343 break;
5344 case Iop_D128toD64: {
5345 PPCFpOp fpop = Pfp_DRDPQ;
5346 HReg fr_dst = newVRegF(env);
5348 set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
5349 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
5350 IEndianess);
5351 addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
5353 /* Need to meet the interface spec but the result is
5354 * just 64-bits so send the result back in both halfs.
5356 *rHi = fr_dst;
5357 *rLo = fr_dst;
5358 return;
5360 case Iop_ShlD128:
5361 case Iop_ShrD128: {
5362 HReg fr_dst_hi = newVRegF(env);
5363 HReg fr_dst_lo = newVRegF(env);
5364 PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
5365 PPCFpOp fpop = Pfp_DSCLIQ; /* fix later if necessary */
5367 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1,
5368 IEndianess);
5370 if (e->Iex.Binop.op == Iop_ShrD128)
5371 fpop = Pfp_DSCRIQ;
5373 addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo,
5374 r_srcHi, r_srcLo, shift));
5376 *rHi = fr_dst_hi;
5377 *rLo = fr_dst_lo;
5378 return;
5380 case Iop_RoundD128toInt: {
5381 HReg r_dstHi = newVRegF(env);
5382 HReg r_dstLo = newVRegF(env);
5383 PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
5385 // will set R and RMC when issuing instruction
5386 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
5387 IEndianess);
5389 addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo,
5390 r_srcHi, r_srcLo, r_rmc));
5391 *rHi = r_dstHi;
5392 *rLo = r_dstLo;
5393 return;
5395 case Iop_InsertExpD128: {
5396 HReg r_dstHi = newVRegF(env);
5397 HReg r_dstLo = newVRegF(env);
5398 HReg r_srcL = newVRegF(env);
5399 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
5400 r_srcHi = newVRegF(env);
5401 r_srcLo = newVRegF(env);
5403 iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
5404 IEndianess);
5406 /* Move I64 to float register to issue instruction */
5407 if (env->mode64) {
5408 HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5409 addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
5410 } else {
5411 HReg tmpHi, tmpLo;
5412 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5414 iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
5415 IEndianess);
5416 addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
5417 addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
5420 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
5421 addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ,
5422 r_dstHi, r_dstLo,
5423 r_srcL, r_srcHi, r_srcLo));
5424 *rHi = r_dstHi;
5425 *rLo = r_dstLo;
5426 return;
5428 default:
5429 vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
5430 (Int)e->Iex.Binop.op );
5431 break;
5435 if (e->tag == Iex_Triop) {
5436 IRTriop *triop = e->Iex.Triop.details;
5437 PPCFpOp fpop = Pfp_INVALID;
5438 HReg r_dstHi = newVRegF(env);
5439 HReg r_dstLo = newVRegF(env);
5441 switch (triop->op) {
5442 case Iop_AddD128:
5443 fpop = Pfp_DFPADDQ;
5444 break;
5445 case Iop_SubD128:
5446 fpop = Pfp_DFPSUBQ;
5447 break;
5448 case Iop_MulD128:
5449 fpop = Pfp_DFPMULQ;
5450 break;
5451 case Iop_DivD128:
5452 fpop = Pfp_DFPDIVQ;
5453 break;
5454 default:
5455 break;
5458 if (fpop != Pfp_INVALID) {
5459 HReg r_srcRHi = newVRegV( env );
5460 HReg r_srcRLo = newVRegV( env );
5462 /* dst will be used to pass in the left operand and get the result. */
5463 iselDfp128Expr( &r_dstHi, &r_dstLo, env, triop->arg2, IEndianess );
5464 iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, triop->arg3, IEndianess );
5465 set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
5466 addInstr( env,
5467 PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
5468 r_srcRHi, r_srcRLo ) );
5469 *rHi = r_dstHi;
5470 *rLo = r_dstLo;
5471 return;
5473 switch (triop->op) {
5474 case Iop_QuantizeD128: fpop = Pfp_DQUAQ; break;
5475 case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
5476 default: break;
5478 if (fpop == Pfp_DQUAQ) {
5479 HReg r_srcHi = newVRegF(env);
5480 HReg r_srcLo = newVRegF(env);
5481 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
5483 /* dst will be used to pass in the left operand and get the result */
5484 iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2, IEndianess);
5485 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
5487 // will set RMC when issuing instruction
5488 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
5489 r_srcHi, r_srcLo, rmc));
5490 *rHi = r_dstHi;
5491 *rLo = r_dstLo;
5492 return;
5494 } else if (fpop == Pfp_DRRNDQ) {
5495 HReg r_srcHi = newVRegF(env);
5496 HReg r_srcLo = newVRegF(env);
5497 PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
5498 PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
5499 PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
5500 HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
5501 HReg r_zero = newVRegI( env );
5503 iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
5505 /* dst will be used to pass in the left operand and get the result */
5506 /* Move I8 to float register to issue instruction. Note, the
5507 * instruction only looks at the bottom 6 bits so we really don't
5508 * have to clear the upper bits since the iselWordExpr_R sets the
5509 * bottom 8-bits.
5511 sub_from_sp( env, 16 );
5513 if (env->mode64)
5514 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
5515 else
5516 addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/));
5518 /* Have to write to the upper bits to ensure they have been
5519 * initialized. The instruction ignores all but the lower 6-bits.
5521 addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
5522 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1));
5523 addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1));
5525 add_to_sp( env, 16 );
5527 // will set RMC when issuing instruction
5528 addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
5529 r_srcHi, r_srcLo, rmc));
5530 *rHi = r_dstHi;
5531 *rLo = r_dstLo;
5532 return;
5536 ppIRExpr( e );
5537 vpanic( "iselDfp128Expr(ppc64)" );
5541 /*---------------------------------------------------------*/
5542 /*--- ISEL: SIMD (Vector) expressions, 128 bit. ---*/
5543 /*---------------------------------------------------------*/
5545 static HReg iselVecExpr ( ISelEnv* env, const IRExpr* e, IREndness IEndianess )
5547 HReg r = iselVecExpr_wrk( env, e, IEndianess );
5548 # if 0
5549 vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
5550 # endif
5551 vassert(hregClass(r) == HRcVec128);
5552 vassert(hregIsVirtual(r));
5553 return r;
5556 /* DO NOT CALL THIS DIRECTLY */
5557 static HReg iselVecExpr_wrk ( ISelEnv* env, const IRExpr* e,
5558 IREndness IEndianess )
5560 Bool mode64 = env->mode64;
5561 PPCAvOp op = Pav_INVALID;
5562 PPCAvFpOp fpop = Pavfp_INVALID;
5563 IRType ty = typeOfIRExpr(env->type_env,e);
5564 vassert(e);
5565 vassert(ty == Ity_V128);
5567 if (e->tag == Iex_RdTmp) {
5568 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
5571 if (e->tag == Iex_Get) {
5572 /* Guest state vectors are 16byte aligned,
5573 so don't need to worry here */
5574 HReg dst = newVRegV(env);
5575 addInstr(env,
5576 PPCInstr_AvLdSt( True/*load*/, 16, dst,
5577 PPCAMode_IR( e->Iex.Get.offset,
5578 GuestStatePtr(mode64) )));
5579 return dst;
5582 if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
5583 /* Need to be able to do V128 unaligned loads. The BE unaligned load
5584 * can be accomplised using the following code sequece from the ISA.
5585 * It uses the lvx instruction that does two aligned loads and then
5586 * permute the data to store the required data as if it had been an
5587 * unaligned load.
5589 * lvx Vhi,0,Rb # load MSQ, using the unaligned address in Rb
5590 * lvsl Vp, 0,Rb # Set permute control vector
5591 * addi Rb,Rb,15 # Address of LSQ
5592 * lvx Vlo,0,Rb # load LSQ
5593 * vperm Vt,Vhi,Vlo,Vp # align the data as requested
5596 HReg Vhi = newVRegV(env);
5597 HReg Vlo = newVRegV(env);
5598 HReg Vp = newVRegV(env);
5599 HReg v_dst = newVRegV(env);
5600 HReg rB;
5601 HReg rB_plus_15 = newVRegI(env);
5603 vassert(e->Iex.Load.ty == Ity_V128);
5604 rB = iselWordExpr_R( env, e->Iex.Load.addr, IEndianess );
5606 // lvx Vhi, 0, Rb
5607 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi,
5608 PPCAMode_IR(0, rB)) );
5610 if (IEndianess == Iend_LE)
5611 // lvsr Vp, 0, Rb
5612 addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp,
5613 PPCAMode_IR(0, rB)) );
5614 else
5615 // lvsl Vp, 0, Rb
5616 addInstr(env, PPCInstr_AvSh( True/*left shift*/, Vp,
5617 PPCAMode_IR(0, rB)) );
5619 // addi Rb_plus_15, Rb, 15
5620 addInstr(env, PPCInstr_Alu( Palu_ADD, rB_plus_15,
5621 rB, PPCRH_Imm(True, toUShort(15))) );
5623 // lvx Vlo, 0, Rb_plus_15
5624 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vlo,
5625 PPCAMode_IR(0, rB_plus_15)) );
5627 if (IEndianess == Iend_LE)
5628 // vperm Vt, Vhi, Vlo, Vp
5629 addInstr(env, PPCInstr_AvPerm( v_dst, Vlo, Vhi, Vp ));
5630 else
5631 // vperm Vt, Vhi, Vlo, Vp
5632 addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp ));
5634 return v_dst;
5637 if (e->tag == Iex_Unop) {
5638 switch (e->Iex.Unop.op) {
5640 case Iop_F16toF64x2:
5642 HReg dst = newVRegV(env);
5643 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5644 /* Note: PPC only coverts the 16-bt value in the upper word
5645 * to a 64-bit value stored in the upper word. The
5646 * contents of the lower word is undefined.
5648 addInstr(env, PPCInstr_AvUnary(Pav_F16toF64x2, dst, arg));
5649 return dst;
5652 case Iop_F64toF16x2:
5654 HReg dst = newVRegV(env);
5655 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5656 /* Note: PPC only coverts the 64-bt value in the upper 64-bit of V128
5657 * to a 16-bit value stored in the upper 64-bits of the result
5658 * V128. The contents of the lower 64-bits is undefined.
5660 addInstr(env, PPCInstr_AvUnary(Pav_F64toF16x2, dst, arg));
5661 return dst;
5664 case Iop_F16toF32x4:
5666 HReg src = newVRegV(env);
5667 HReg dst = newVRegV(env);
5668 HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5669 PPCAMode *am_off0, *am_off8;
5670 HReg r_aligned16;
5672 vassert(mode64);
5673 /* need to put I64 src into upper 64-bits of vector register,
5674 use stack */
5675 sub_from_sp( env, 32 ); // Move SP down
5677 /* Get a quadword aligned address within our stack space */
5678 r_aligned16 = get_sp_aligned16( env );
5679 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5680 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5682 /* Store I64 to stack */
5684 if (IEndianess == Iend_LE) {
5685 addInstr(env, PPCInstr_Store( 8, am_off8, arg, mode64 ));
5686 } else {
5687 addInstr(env, PPCInstr_Store( 8, am_off0, arg, mode64 ));
5690 /* Fetch new v128 src back from stack. */
5691 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, src, am_off0));
5693 /* issue instruction */
5694 addInstr(env, PPCInstr_AvUnary(Pav_F16toF32x4, dst, src));
5695 add_to_sp( env, 32 ); // Reset SP
5697 return dst;
5700 case Iop_F32toF16x4:
5702 HReg dst = newVRegI(env);
5703 HReg tmp = newVRegV(env);
5704 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5705 PPCAMode *am_off0, *am_off8;
5706 HReg r_aligned16;
5708 /* Instruction returns a V128, the Iop_F32toF16x4 needs to return
5709 * I64. Move the upper 64-bits from the instruction to an I64 via
5710 * the stack and return it.
5712 sub_from_sp( env, 32 ); // Move SP down
5714 addInstr(env, PPCInstr_AvUnary(Pav_F32toF16x4, tmp, arg));
5716 /* Get a quadword aligned address within our stack space */
5717 r_aligned16 = get_sp_aligned16( env );
5718 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5719 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5721 /* Store v128 tmp to stack. */
5722 addInstr(env, PPCInstr_AvLdSt(False/*store*/, 16, tmp, am_off0));
5724 /* Fetch I64 from stack */
5725 if (IEndianess == Iend_LE) {
5726 addInstr(env, PPCInstr_Load( 8, dst, am_off8, mode64 ));
5727 } else {
5728 addInstr(env, PPCInstr_Load( 8, dst, am_off0, mode64 ));
5731 add_to_sp( env, 32 ); // Reset SP
5732 return dst;
5735 case Iop_NotV128: {
5736 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5737 HReg dst = newVRegV(env);
5738 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
5739 return dst;
5742 case Iop_CmpNEZ8x16: {
5743 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5744 HReg zero = newVRegV(env);
5745 HReg dst = newVRegV(env);
5746 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
5747 addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
5748 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5749 return dst;
5752 case Iop_CmpNEZ16x8: {
5753 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5754 HReg zero = newVRegV(env);
5755 HReg dst = newVRegV(env);
5756 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
5757 addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
5758 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5759 return dst;
5762 case Iop_CmpNEZ32x4: {
5763 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5764 HReg zero = newVRegV(env);
5765 HReg dst = newVRegV(env);
5766 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
5767 addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
5768 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5769 return dst;
5772 case Iop_CmpNEZ64x2: {
5773 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5774 HReg zero = newVRegV(env);
5775 HReg dst = newVRegV(env);
5776 addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
5777 addInstr(env, PPCInstr_AvBin64x2(Pav_CMPEQU, dst, arg, zero));
5778 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5779 return dst;
5782 case Iop_RecipEst32Fx4: fpop = Pavfp_RCPF; goto do_32Fx4_unary;
5783 case Iop_RSqrtEst32Fx4: fpop = Pavfp_RSQRTF; goto do_32Fx4_unary;
5784 case Iop_I32UtoFx4: fpop = Pavfp_CVTU2F; goto do_32Fx4_unary;
5785 case Iop_I32StoFx4: fpop = Pavfp_CVTS2F; goto do_32Fx4_unary;
5786 case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
5787 case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
5788 case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM; goto do_32Fx4_unary;
5789 case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP; goto do_32Fx4_unary;
5790 case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN; goto do_32Fx4_unary;
5791 case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ; goto do_32Fx4_unary;
5792 do_32Fx4_unary:
5794 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5795 HReg dst = newVRegV(env);
5796 addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
5797 return dst;
5800 case Iop_32UtoV128: {
5801 HReg r_aligned16, r_zeros;
5802 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5803 HReg dst = newVRegV(env);
5804 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5805 sub_from_sp( env, 32 ); // Move SP down
5807 /* Get a quadword aligned address within our stack space */
5808 r_aligned16 = get_sp_aligned16( env );
5809 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5810 am_off4 = PPCAMode_IR( 4, r_aligned16 );
5811 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5812 am_off12 = PPCAMode_IR( 12, r_aligned16 );
5814 /* Store zeros */
5815 r_zeros = newVRegI(env);
5816 addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
5817 if (IEndianess == Iend_LE)
5818 addInstr(env, PPCInstr_Store( 4, am_off0, r_src, mode64 ));
5819 else
5820 addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
5821 addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
5822 addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
5824 /* Store r_src in low word of quadword-aligned mem */
5825 if (IEndianess == Iend_LE)
5826 addInstr(env, PPCInstr_Store( 4, am_off12, r_zeros, mode64 ));
5827 else
5828 addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
5830 /* Load word into low word of quadword vector reg */
5831 if (IEndianess == Iend_LE)
5832 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off0 ));
5833 else
5834 addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
5836 add_to_sp( env, 32 ); // Reset SP
5837 return dst;
5840 case Iop_Dup8x16:
5841 case Iop_Dup16x8:
5842 case Iop_Dup32x4:
5843 return mk_AvDuplicateRI(env, e->Iex.Unop.arg, IEndianess);
5845 case Iop_CipherSV128: op = Pav_CIPHERSUBV128; goto do_AvCipherV128Un;
5846 do_AvCipherV128Un: {
5847 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5848 HReg dst = newVRegV(env);
5849 addInstr(env, PPCInstr_AvCipherV128Unary(op, dst, arg));
5850 return dst;
5853 case Iop_Clz8x16: op = Pav_ZEROCNTBYTE; goto do_zerocnt;
5854 case Iop_Clz16x8: op = Pav_ZEROCNTHALF; goto do_zerocnt;
5855 case Iop_Clz32x4: op = Pav_ZEROCNTWORD; goto do_zerocnt;
5856 case Iop_Clz64x2: op = Pav_ZEROCNTDBL; goto do_zerocnt;
5857 case Iop_Ctz8x16: op = Pav_TRAILINGZEROCNTBYTE; goto do_zerocnt;
5858 case Iop_Ctz16x8: op = Pav_TRAILINGZEROCNTHALF; goto do_zerocnt;
5859 case Iop_Ctz32x4: op = Pav_TRAILINGZEROCNTWORD; goto do_zerocnt;
5860 case Iop_Ctz64x2: op = Pav_TRAILINGZEROCNTDBL; goto do_zerocnt;
5861 case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE; goto do_zerocnt;
5862 do_zerocnt:
5864 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5865 HReg dst = newVRegV(env);
5866 addInstr(env, PPCInstr_AvUnary(op, dst, arg));
5867 return dst;
5870 /* BCD Iops */
5871 case Iop_BCD128toI128S:
5873 HReg dst = newVRegV(env);
5874 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5875 addInstr(env, PPCInstr_AvUnary( Pav_BCD128toI128S, dst, arg ) );
5876 return dst;
5879 case Iop_MulI128by10: op = Pav_MulI128by10; goto do_MulI128;
5880 case Iop_MulI128by10Carry: op = Pav_MulI128by10Carry; goto do_MulI128;
5881 do_MulI128: {
5882 HReg dst = newVRegV(env);
5883 HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5884 addInstr(env, PPCInstr_AvUnary(op, dst, arg));
5885 return dst;
5888 default:
5889 break;
5890 } /* switch (e->Iex.Unop.op) */
5891 } /* if (e->tag == Iex_Unop) */
5893 if (e->tag == Iex_Binop) {
5894 switch (e->Iex.Binop.op) {
5896 case Iop_64HLtoV128: {
5897 if (!mode64) {
5898 HReg r3, r2, r1, r0, r_aligned16;
5899 PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5900 HReg dst = newVRegV(env);
5901 /* do this via the stack (easy, convenient, etc) */
5902 sub_from_sp( env, 32 ); // Move SP down
5904 // get a quadword aligned address within our stack space
5905 r_aligned16 = get_sp_aligned16( env );
5906 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5907 am_off4 = PPCAMode_IR( 4, r_aligned16 );
5908 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5909 am_off12 = PPCAMode_IR( 12, r_aligned16 );
5911 /* Do the less significant 64 bits */
5912 iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2, IEndianess);
5913 addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
5914 addInstr(env, PPCInstr_Store( 4, am_off8, r1, mode64 ));
5915 /* Do the more significant 64 bits */
5916 iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1, IEndianess);
5917 addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
5918 addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
5920 /* Fetch result back from stack. */
5921 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5923 add_to_sp( env, 32 ); // Reset SP
5924 return dst;
5925 } else {
5926 HReg rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5927 HReg rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5928 HReg dst = newVRegV(env);
5929 HReg r_aligned16;
5930 PPCAMode *am_off0, *am_off8;
5931 /* do this via the stack (easy, convenient, etc) */
5932 sub_from_sp( env, 32 ); // Move SP down
5934 // get a quadword aligned address within our stack space
5935 r_aligned16 = get_sp_aligned16( env );
5936 am_off0 = PPCAMode_IR( 0, r_aligned16 );
5937 am_off8 = PPCAMode_IR( 8, r_aligned16 );
5939 /* Store 2*I64 to stack */
5940 if (IEndianess == Iend_LE) {
5941 addInstr(env, PPCInstr_Store( 8, am_off0, rLo, mode64 ));
5942 addInstr(env, PPCInstr_Store( 8, am_off8, rHi, mode64 ));
5943 } else {
5944 addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
5945 addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
5947 /* Fetch result back from stack. */
5948 addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5950 add_to_sp( env, 32 ); // Reset SP
5951 return dst;
5955 case Iop_Max32Fx4: fpop = Pavfp_MAXF; goto do_32Fx4;
5956 case Iop_Min32Fx4: fpop = Pavfp_MINF; goto do_32Fx4;
5957 case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
5958 case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
5959 case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
5960 do_32Fx4:
5962 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5963 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5964 HReg dst = newVRegV(env);
5965 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5966 return dst;
5969 case Iop_CmpLE32Fx4: {
5970 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5971 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5972 HReg dst = newVRegV(env);
5974 /* stay consistent with native ppc compares:
5975 if a left/right lane holds a nan, return zeros for that lane
5976 so: le == NOT(gt OR isNan)
5978 HReg isNanLR = newVRegV(env);
5979 HReg isNanL = isNan(env, argL, IEndianess);
5980 HReg isNanR = isNan(env, argR, IEndianess);
5981 addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
5982 isNanL, isNanR));
5984 addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
5985 argL, argR));
5986 addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
5987 addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5988 return dst;
5991 case Iop_AndV128: op = Pav_AND; goto do_AvBin;
5992 case Iop_OrV128: op = Pav_OR; goto do_AvBin;
5993 case Iop_XorV128: op = Pav_XOR; goto do_AvBin;
5994 do_AvBin: {
5995 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5996 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5997 HReg dst = newVRegV(env);
5998 addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
5999 return dst;
6002 case Iop_Shl8x16: op = Pav_SHL; goto do_AvBin8x16;
6003 case Iop_Shr8x16: op = Pav_SHR; goto do_AvBin8x16;
6004 case Iop_Sar8x16: op = Pav_SAR; goto do_AvBin8x16;
6005 case Iop_Rol8x16: op = Pav_ROTL; goto do_AvBin8x16;
6006 case Iop_InterleaveHI8x16: op = Pav_MRGHI; goto do_AvBin8x16;
6007 case Iop_InterleaveLO8x16: op = Pav_MRGLO; goto do_AvBin8x16;
6008 case Iop_Add8x16: op = Pav_ADDU; goto do_AvBin8x16;
6009 case Iop_QAdd8Ux16: op = Pav_QADDU; goto do_AvBin8x16;
6010 case Iop_QAdd8Sx16: op = Pav_QADDS; goto do_AvBin8x16;
6011 case Iop_Sub8x16: op = Pav_SUBU; goto do_AvBin8x16;
6012 case Iop_QSub8Ux16: op = Pav_QSUBU; goto do_AvBin8x16;
6013 case Iop_QSub8Sx16: op = Pav_QSUBS; goto do_AvBin8x16;
6014 case Iop_Avg8Ux16: op = Pav_AVGU; goto do_AvBin8x16;
6015 case Iop_Avg8Sx16: op = Pav_AVGS; goto do_AvBin8x16;
6016 case Iop_Max8Ux16: op = Pav_MAXU; goto do_AvBin8x16;
6017 case Iop_Max8Sx16: op = Pav_MAXS; goto do_AvBin8x16;
6018 case Iop_Min8Ux16: op = Pav_MINU; goto do_AvBin8x16;
6019 case Iop_Min8Sx16: op = Pav_MINS; goto do_AvBin8x16;
6020 case Iop_MullEven8Ux16: op = Pav_OMULU; goto do_AvBin8x16;
6021 case Iop_MullEven8Sx16: op = Pav_OMULS; goto do_AvBin8x16;
6022 case Iop_CmpEQ8x16: op = Pav_CMPEQU; goto do_AvBin8x16;
6023 case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
6024 case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
6025 case Iop_PolynomialMulAdd8x16: op = Pav_POLYMULADD; goto do_AvBin8x16;
6026 do_AvBin8x16: {
6027 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6028 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6029 HReg dst = newVRegV(env);
6030 addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
6031 return dst;
6034 case Iop_Shl16x8: op = Pav_SHL; goto do_AvBin16x8;
6035 case Iop_Shr16x8: op = Pav_SHR; goto do_AvBin16x8;
6036 case Iop_Sar16x8: op = Pav_SAR; goto do_AvBin16x8;
6037 case Iop_Rol16x8: op = Pav_ROTL; goto do_AvBin16x8;
6038 case Iop_NarrowBin16to8x16: op = Pav_PACKUU; goto do_AvBin16x8;
6039 case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8;
6040 case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8;
6041 case Iop_InterleaveHI16x8: op = Pav_MRGHI; goto do_AvBin16x8;
6042 case Iop_InterleaveLO16x8: op = Pav_MRGLO; goto do_AvBin16x8;
6043 case Iop_Add16x8: op = Pav_ADDU; goto do_AvBin16x8;
6044 case Iop_QAdd16Ux8: op = Pav_QADDU; goto do_AvBin16x8;
6045 case Iop_QAdd16Sx8: op = Pav_QADDS; goto do_AvBin16x8;
6046 case Iop_Sub16x8: op = Pav_SUBU; goto do_AvBin16x8;
6047 case Iop_QSub16Ux8: op = Pav_QSUBU; goto do_AvBin16x8;
6048 case Iop_QSub16Sx8: op = Pav_QSUBS; goto do_AvBin16x8;
6049 case Iop_Avg16Ux8: op = Pav_AVGU; goto do_AvBin16x8;
6050 case Iop_Avg16Sx8: op = Pav_AVGS; goto do_AvBin16x8;
6051 case Iop_Max16Ux8: op = Pav_MAXU; goto do_AvBin16x8;
6052 case Iop_Max16Sx8: op = Pav_MAXS; goto do_AvBin16x8;
6053 case Iop_Min16Ux8: op = Pav_MINU; goto do_AvBin16x8;
6054 case Iop_Min16Sx8: op = Pav_MINS; goto do_AvBin16x8;
6055 case Iop_MullEven16Ux8: op = Pav_OMULU; goto do_AvBin16x8;
6056 case Iop_MullEven16Sx8: op = Pav_OMULS; goto do_AvBin16x8;
6057 case Iop_CmpEQ16x8: op = Pav_CMPEQU; goto do_AvBin16x8;
6058 case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
6059 case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
6060 case Iop_PolynomialMulAdd16x8: op = Pav_POLYMULADD; goto do_AvBin16x8;
6061 do_AvBin16x8: {
6062 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6063 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6064 HReg dst = newVRegV(env);
6065 addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
6066 return dst;
6069 case Iop_Shl32x4: op = Pav_SHL; goto do_AvBin32x4;
6070 case Iop_Shr32x4: op = Pav_SHR; goto do_AvBin32x4;
6071 case Iop_Sar32x4: op = Pav_SAR; goto do_AvBin32x4;
6072 case Iop_Rol32x4: op = Pav_ROTL; goto do_AvBin32x4;
6073 case Iop_NarrowBin32to16x8: op = Pav_PACKUU; goto do_AvBin32x4;
6074 case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4;
6075 case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4;
6076 case Iop_InterleaveHI32x4: op = Pav_MRGHI; goto do_AvBin32x4;
6077 case Iop_InterleaveLO32x4: op = Pav_MRGLO; goto do_AvBin32x4;
6078 case Iop_Add32x4: op = Pav_ADDU; goto do_AvBin32x4;
6079 case Iop_QAdd32Ux4: op = Pav_QADDU; goto do_AvBin32x4;
6080 case Iop_QAdd32Sx4: op = Pav_QADDS; goto do_AvBin32x4;
6081 case Iop_Sub32x4: op = Pav_SUBU; goto do_AvBin32x4;
6082 case Iop_QSub32Ux4: op = Pav_QSUBU; goto do_AvBin32x4;
6083 case Iop_QSub32Sx4: op = Pav_QSUBS; goto do_AvBin32x4;
6084 case Iop_Avg32Ux4: op = Pav_AVGU; goto do_AvBin32x4;
6085 case Iop_Avg32Sx4: op = Pav_AVGS; goto do_AvBin32x4;
6086 case Iop_Max32Ux4: op = Pav_MAXU; goto do_AvBin32x4;
6087 case Iop_Max32Sx4: op = Pav_MAXS; goto do_AvBin32x4;
6088 case Iop_Min32Ux4: op = Pav_MINU; goto do_AvBin32x4;
6089 case Iop_Min32Sx4: op = Pav_MINS; goto do_AvBin32x4;
6090 case Iop_Mul32x4: op = Pav_MULU; goto do_AvBin32x4;
6091 case Iop_MullEven32Ux4: op = Pav_OMULU; goto do_AvBin32x4;
6092 case Iop_MullEven32Sx4: op = Pav_OMULS; goto do_AvBin32x4;
6093 case Iop_CmpEQ32x4: op = Pav_CMPEQU; goto do_AvBin32x4;
6094 case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
6095 case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
6096 case Iop_CatOddLanes32x4: op = Pav_CATODD; goto do_AvBin32x4;
6097 case Iop_CatEvenLanes32x4: op = Pav_CATEVEN; goto do_AvBin32x4;
6098 case Iop_PolynomialMulAdd32x4: op = Pav_POLYMULADD; goto do_AvBin32x4;
6099 do_AvBin32x4: {
6100 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6101 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6102 HReg dst = newVRegV(env);
6103 addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
6104 return dst;
6107 case Iop_Shl64x2: op = Pav_SHL; goto do_AvBin64x2;
6108 case Iop_Shr64x2: op = Pav_SHR; goto do_AvBin64x2;
6109 case Iop_Sar64x2: op = Pav_SAR; goto do_AvBin64x2;
6110 case Iop_Rol64x2: op = Pav_ROTL; goto do_AvBin64x2;
6111 case Iop_NarrowBin64to32x4: op = Pav_PACKUU; goto do_AvBin64x2;
6112 case Iop_QNarrowBin64Sto32Sx4: op = Pav_QPACKSS; goto do_AvBin64x2;
6113 case Iop_QNarrowBin64Uto32Ux4: op = Pav_QPACKUU; goto do_AvBin64x2;
6114 case Iop_InterleaveHI64x2: op = Pav_MRGHI; goto do_AvBin64x2;
6115 case Iop_InterleaveLO64x2: op = Pav_MRGLO; goto do_AvBin64x2;
6116 case Iop_Add64x2: op = Pav_ADDU; goto do_AvBin64x2;
6117 case Iop_Sub64x2: op = Pav_SUBU; goto do_AvBin64x2;
6118 case Iop_Max64Ux2: op = Pav_MAXU; goto do_AvBin64x2;
6119 case Iop_Max64Sx2: op = Pav_MAXS; goto do_AvBin64x2;
6120 case Iop_Min64Ux2: op = Pav_MINU; goto do_AvBin64x2;
6121 case Iop_Min64Sx2: op = Pav_MINS; goto do_AvBin64x2;
6122 case Iop_CmpEQ64x2: op = Pav_CMPEQU; goto do_AvBin64x2;
6123 case Iop_CmpGT64Ux2: op = Pav_CMPGTU; goto do_AvBin64x2;
6124 case Iop_CmpGT64Sx2: op = Pav_CMPGTS; goto do_AvBin64x2;
6125 case Iop_PolynomialMulAdd64x2: op = Pav_POLYMULADD; goto do_AvBin64x2;
6126 do_AvBin64x2: {
6127 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6128 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6129 HReg dst = newVRegV(env);
6130 addInstr(env, PPCInstr_AvBin64x2(op, dst, arg1, arg2));
6131 return dst;
6134 case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
6135 case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
6136 do_AvShift8x16: {
6137 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6138 HReg dst = newVRegV(env);
6139 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
6140 addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
6141 return dst;
6144 case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
6145 case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
6146 case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
6147 do_AvShift16x8: {
6148 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6149 HReg dst = newVRegV(env);
6150 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
6151 addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
6152 return dst;
6155 case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
6156 case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
6157 case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
6158 do_AvShift32x4: {
6159 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6160 HReg dst = newVRegV(env);
6161 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
6162 addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
6163 return dst;
6166 case Iop_ShlN64x2: op = Pav_SHL; goto do_AvShift64x2;
6167 case Iop_ShrN64x2: op = Pav_SHR; goto do_AvShift64x2;
6168 case Iop_SarN64x2: op = Pav_SAR; goto do_AvShift64x2;
6169 do_AvShift64x2: {
6170 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6171 HReg dst = newVRegV(env);
6172 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
6173 addInstr(env, PPCInstr_AvBin64x2(op, dst, r_src, v_shft));
6174 return dst;
6177 case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
6178 case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
6179 do_AvShiftV128: {
6180 HReg dst = newVRegV(env);
6181 HReg r_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6182 HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
6183 /* Note: shift value gets masked by 127 */
6184 addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
6185 return dst;
6188 case Iop_Perm8x16: {
6189 HReg dst = newVRegV(env);
6190 HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6191 HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6192 addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
6193 return dst;
6196 case Iop_CipherV128: op = Pav_CIPHERV128; goto do_AvCipherV128;
6197 case Iop_CipherLV128: op = Pav_CIPHERLV128; goto do_AvCipherV128;
6198 case Iop_NCipherV128: op = Pav_NCIPHERV128; goto do_AvCipherV128;
6199 case Iop_NCipherLV128:op = Pav_NCIPHERLV128; goto do_AvCipherV128;
6200 do_AvCipherV128: {
6201 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6202 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6203 HReg dst = newVRegV(env);
6204 addInstr(env, PPCInstr_AvCipherV128Binary(op, dst, arg1, arg2));
6205 return dst;
6208 case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128;
6209 case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128;
6210 do_AvHashV128: {
6211 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6212 HReg dst = newVRegV(env);
6213 PPCRI* s_field = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
6214 addInstr(env, PPCInstr_AvHashV128Binary(op, dst, arg1, s_field));
6215 return dst;
6218 /* BCD Iops */
6219 case Iop_I128StoBCD128:
6221 HReg dst = newVRegV(env);
6222 HReg arg = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6223 PPCRI* ps = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
6225 addInstr(env, PPCInstr_AvBinaryInt( Pav_I128StoBCD128, dst, arg,
6226 ps ) );
6227 return dst;
6230 case Iop_MulI128by10E: op = Pav_MulI128by10E; goto do_MulI128E;
6231 case Iop_MulI128by10ECarry: op = Pav_MulI128by10ECarry; goto do_MulI128E;
6232 do_MulI128E: {
6233 HReg dst = newVRegV(env);
6234 HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6235 HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6236 addInstr(env, PPCInstr_AvBinary(op, dst, argL, argR));
6237 return dst;
6240 case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
6241 case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
6242 do_AvBCDV128: {
6243 HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
6244 HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
6245 HReg dst = newVRegV(env);
6246 addInstr(env, PPCInstr_AvBCDV128Binary(op, dst, arg1, arg2));
6247 return dst;
6250 default:
6251 break;
6252 } /* switch (e->Iex.Binop.op) */
6253 } /* if (e->tag == Iex_Binop) */
6255 if (e->tag == Iex_Triop) {
6256 IRTriop *triop = e->Iex.Triop.details;
6257 switch (triop->op) {
6258 case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4_with_rm;
6259 case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4_with_rm;
6260 case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4_with_rm;
6261 do_32Fx4_with_rm:
6263 HReg argL = iselVecExpr(env, triop->arg2, IEndianess);
6264 HReg argR = iselVecExpr(env, triop->arg3, IEndianess);
6265 HReg dst = newVRegV(env);
6266 /* FIXME: this is bogus, in the sense that Altivec ignores
6267 FPSCR.RM, at least for some FP operations. So setting the
6268 RM is pointless. This is only really correct in the case
6269 where the RM is known, at JIT time, to be Irrm_NEAREST,
6270 since -- at least for Altivec FP add/sub/mul -- the
6271 emitted insn is hardwired to round to nearest. */
6272 set_FPU_rounding_mode(env, triop->arg1, IEndianess);
6273 addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
6274 return dst;
6277 default:
6278 break;
6279 } /* switch (e->Iex.Triop.op) */
6280 } /* if (e->tag == Iex_Trinop) */
6283 if (e->tag == Iex_Const ) {
6284 vassert(e->Iex.Const.con->tag == Ico_V128);
6285 if (e->Iex.Const.con->Ico.V128 == 0x0000) {
6286 return generate_zeroes_V128(env);
6288 else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
6289 return generate_ones_V128(env);
6293 vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
6294 LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
6295 env->hwcaps));
6296 ppIRExpr(e);
6297 vpanic("iselVecExpr_wrk(ppc)");
6301 /*---------------------------------------------------------*/
6302 /*--- ISEL: Statements ---*/
6303 /*---------------------------------------------------------*/
6305 static void iselStmt ( ISelEnv* env, IRStmt* stmt, IREndness IEndianess )
6307 Bool mode64 = env->mode64;
6308 if (vex_traceflags & VEX_TRACE_VCODE) {
6309 vex_printf("\n -- ");
6310 ppIRStmt(stmt);
6311 vex_printf("\n");
6314 switch (stmt->tag) {
6316 /* --------- STORE --------- */
6317 case Ist_Store: {
6318 IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
6319 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
6320 IREndness end = stmt->Ist.Store.end;
6322 if (end != IEndianess)
6323 goto stmt_fail;
6324 if (!mode64 && (tya != Ity_I32))
6325 goto stmt_fail;
6326 if (mode64 && (tya != Ity_I64))
6327 goto stmt_fail;
6329 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
6330 (mode64 && (tyd == Ity_I64))) {
6331 PPCAMode* am_addr
6332 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6333 IEndianess);
6334 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data, IEndianess);
6335 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
6336 am_addr, r_src, mode64 ));
6337 return;
6339 if (tyd == Ity_F64) {
6340 PPCAMode* am_addr
6341 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6342 IEndianess);
6343 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess);
6344 addInstr(env,
6345 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
6346 return;
6348 if (tyd == Ity_F32) {
6349 PPCAMode* am_addr
6350 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6351 IEndianess);
6352 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess);
6353 addInstr(env,
6354 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
6355 return;
6357 if (tyd == Ity_D64) {
6358 PPCAMode* am_addr
6359 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6360 IEndianess);
6361 HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess);
6362 addInstr(env,
6363 PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
6364 return;
6366 if (tyd == Ity_D32) {
6367 PPCAMode* am_addr
6368 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6369 IEndianess);
6370 HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess);
6371 addInstr(env,
6372 PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
6373 return;
6375 if (tyd == Ity_V128) {
6376 PPCAMode* am_addr
6377 = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
6378 IEndianess);
6379 HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess);
6380 addInstr(env,
6381 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
6382 return;
6384 if (tyd == Ity_I64 && !mode64) {
6385 /* Just calculate the address in the register. Life is too
6386 short to arse around trying and possibly failing to adjust
6387 the offset in a 'reg+offset' style amode. */
6388 HReg rHi32, rLo32;
6389 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess);
6390 iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data,
6391 IEndianess );
6392 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
6393 PPCAMode_IR( 0, r_addr ),
6394 rHi32,
6395 False/*32-bit insn please*/) );
6396 addInstr(env, PPCInstr_Store( 4/*byte-store*/,
6397 PPCAMode_IR( 4, r_addr ),
6398 rLo32,
6399 False/*32-bit insn please*/) );
6400 return;
6402 break;
6405 /* --------- PUT --------- */
6406 case Ist_Put: {
6407 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
6408 if (ty == Ity_I8 || ty == Ity_I16 ||
6409 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
6410 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data, IEndianess);
6411 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6412 GuestStatePtr(mode64) );
6413 addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
6414 am_addr, r_src, mode64 ));
6415 return;
6417 if (!mode64 && ty == Ity_I64) {
6418 HReg rHi, rLo;
6419 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6420 GuestStatePtr(mode64) );
6421 PPCAMode* am_addr4 = advance4(env, am_addr);
6422 iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
6423 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
6424 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
6425 return;
6427 if (ty == Ity_I128) {
6428 HReg rHi, rLo;
6429 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6430 GuestStatePtr(mode64) );
6431 PPCAMode* am_addr4 = advance4(env, am_addr);
6433 iselInt128Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
6434 addInstr(env, PPCInstr_Store( 4, am_addr, rHi, mode64 ));
6435 addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
6436 return;
6438 if (ty == Ity_F128) {
6439 /* Guest state vectors are 16byte aligned,
6440 so don't need to worry here */
6441 HReg v_src = iselFp128Expr(env, stmt->Ist.Put.data, IEndianess);
6443 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6444 GuestStatePtr(mode64) );
6445 addInstr(env,
6446 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
6447 return;
6449 if (ty == Ity_V128) {
6450 /* Guest state vectors are 16byte aligned,
6451 so don't need to worry here */
6452 HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess);
6453 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6454 GuestStatePtr(mode64) );
6455 addInstr(env,
6456 PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
6457 return;
6459 if (ty == Ity_F64) {
6460 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data, IEndianess);
6461 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6462 GuestStatePtr(mode64) );
6463 addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
6464 fr_src, am_addr ));
6465 return;
6467 if (ty == Ity_D32) {
6468 /* The 32-bit value is stored in a 64-bit register */
6469 HReg fr_src = iselDfp32Expr( env, stmt->Ist.Put.data, IEndianess );
6470 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6471 GuestStatePtr(mode64) );
6472 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8,
6473 fr_src, am_addr ) );
6474 return;
6476 if (ty == Ity_D64) {
6477 HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data, IEndianess );
6478 PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
6479 GuestStatePtr(mode64) );
6480 addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) );
6481 return;
6483 break;
6486 /* --------- Indexed PUT --------- */
6487 case Ist_PutI: {
6488 IRPutI *puti = stmt->Ist.PutI.details;
6490 PPCAMode* dst_am
6491 = genGuestArrayOffset(
6492 env, puti->descr,
6493 puti->ix, puti->bias,
6494 IEndianess );
6495 IRType ty = typeOfIRExpr(env->type_env, puti->data);
6496 if (mode64 && ty == Ity_I64) {
6497 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
6498 addInstr(env, PPCInstr_Store( toUChar(8),
6499 dst_am, r_src, mode64 ));
6500 return;
6502 if ((!mode64) && ty == Ity_I32) {
6503 HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
6504 addInstr(env, PPCInstr_Store( toUChar(4),
6505 dst_am, r_src, mode64 ));
6506 return;
6508 break;
6511 /* --------- TMP --------- */
6512 case Ist_WrTmp: {
6513 IRTemp tmp = stmt->Ist.WrTmp.tmp;
6514 IRType ty = typeOfIRTemp(env->type_env, tmp);
6515 if (ty == Ity_I8 || ty == Ity_I16 ||
6516 ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
6517 HReg r_dst = lookupIRTemp(env, tmp);
6518 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data, IEndianess);
6519 addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
6520 return;
6522 if (!mode64 && ty == Ity_I64) {
6523 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
6525 iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
6526 IEndianess);
6527 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
6528 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
6529 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
6530 return;
6532 if (mode64 && ty == Ity_I128) {
6533 HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
6534 iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
6535 IEndianess);
6536 lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
6537 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
6538 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
6539 return;
6541 if (!mode64 && ty == Ity_I128) {
6542 HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo;
6543 HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo;
6545 iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi,
6546 &r_srcMedLo, &r_srcLo,
6547 env, stmt->Ist.WrTmp.data, IEndianess);
6549 lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo,
6550 &r_dstLo, env, tmp);
6552 addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
6553 addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) );
6554 addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) );
6555 addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
6556 return;
6558 if (ty == Ity_I1) {
6559 PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data,
6560 IEndianess);
6561 HReg r_dst = lookupIRTemp(env, tmp);
6562 addInstr(env, PPCInstr_Set(cond, r_dst));
6563 return;
6565 if (ty == Ity_F64) {
6566 HReg fr_dst = lookupIRTemp(env, tmp);
6567 HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data, IEndianess);
6568 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
6569 return;
6571 if (ty == Ity_F32) {
6572 HReg fr_dst = lookupIRTemp(env, tmp);
6573 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data, IEndianess);
6574 addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
6575 return;
6577 if (ty == Ity_D32) {
6578 HReg fr_dst = lookupIRTemp(env, tmp);
6579 HReg fr_src = iselDfp32Expr(env, stmt->Ist.WrTmp.data, IEndianess);
6580 addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src));
6581 return;
6583 if (ty == Ity_F128) {
6584 HReg v_dst = lookupIRTemp(env, tmp);
6585 HReg v_src = iselFp128Expr(env, stmt->Ist.WrTmp.data, IEndianess);
6586 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
6587 return;
6589 if (ty == Ity_V128) {
6590 HReg v_dst = lookupIRTemp(env, tmp);
6591 HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess);
6592 addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
6593 return;
6595 if (ty == Ity_D64) {
6596 HReg fr_dst = lookupIRTemp( env, tmp );
6597 HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data, IEndianess );
6598 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) );
6599 return;
6601 if (ty == Ity_D128) {
6602 HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo;
6603 // lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
6604 lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
6605 iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data,
6606 IEndianess );
6607 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
6608 addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
6609 return;
6611 break;
6614 /* --------- Load Linked or Store Conditional --------- */
6615 case Ist_LLSC: {
6616 IRTemp res = stmt->Ist.LLSC.result;
6617 IRType tyRes = typeOfIRTemp(env->type_env, res);
6618 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
6620 if (stmt->Ist.LLSC.end != IEndianess)
6621 goto stmt_fail;
6622 if (!mode64 && (tyAddr != Ity_I32))
6623 goto stmt_fail;
6624 if (mode64 && (tyAddr != Ity_I64))
6625 goto stmt_fail;
6627 if (stmt->Ist.LLSC.storedata == NULL) {
6628 /* LL */
6629 HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr, IEndianess );
6630 HReg r_dst = lookupIRTemp(env, res);
6631 if (tyRes == Ity_I8) {
6632 addInstr(env, PPCInstr_LoadL( 1, r_dst, r_addr, mode64 ));
6633 return;
6635 if (tyRes == Ity_I16) {
6636 addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 ));
6637 return;
6639 if (tyRes == Ity_I32) {
6640 addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
6641 return;
6643 if (tyRes == Ity_I64 && mode64) {
6644 addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
6645 return;
6647 /* fallthru */;
6648 } else {
6649 /* SC */
6650 HReg r_res = lookupIRTemp(env, res); /* :: Ity_I1 */
6651 HReg r_a = iselWordExpr_R(env, stmt->Ist.LLSC.addr, IEndianess);
6652 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata,
6653 IEndianess);
6654 HReg r_tmp = newVRegI(env);
6655 IRType tyData = typeOfIRExpr(env->type_env,
6656 stmt->Ist.LLSC.storedata);
6657 vassert(tyRes == Ity_I1);
6658 if (tyData == Ity_I8 || tyData == Ity_I16 || tyData == Ity_I32 ||
6659 (tyData == Ity_I64 && mode64)) {
6660 int size = 0;
6662 if (tyData == Ity_I64)
6663 size = 8;
6664 else if (tyData == Ity_I32)
6665 size = 4;
6666 else if (tyData == Ity_I16)
6667 size = 2;
6668 else if (tyData == Ity_I8)
6669 size = 1;
6671 addInstr(env, PPCInstr_StoreC( size,
6672 r_a, r_src, mode64 ));
6673 addInstr(env, PPCInstr_MfCR( r_tmp ));
6674 addInstr(env, PPCInstr_Shft(
6675 Pshft_SHR,
6676 env->mode64 ? False : True
6677 /*F:64-bit, T:32-bit shift*/,
6678 r_tmp, r_tmp,
6679 PPCRH_Imm(False/*unsigned*/, 29)));
6680 /* Probably unnecessary, since the IR dest type is Ity_I1,
6681 and so we are entitled to leave whatever junk we like
6682 drifting round in the upper 31 or 63 bits of r_res.
6683 However, for the sake of conservativeness .. */
6684 addInstr(env, PPCInstr_Alu(
6685 Palu_AND,
6686 r_res, r_tmp,
6687 PPCRH_Imm(False/*signed*/, 1)));
6688 return;
6690 /* fallthru */
6692 goto stmt_fail;
6693 /*NOTREACHED*/
6696 /* --------- Call to DIRTY helper --------- */
6697 case Ist_Dirty: {
6698 IRDirty* d = stmt->Ist.Dirty.details;
6700 /* Figure out the return type, if any. */
6701 IRType retty = Ity_INVALID;
6702 if (d->tmp != IRTemp_INVALID)
6703 retty = typeOfIRTemp(env->type_env, d->tmp);
6705 /* Throw out any return types we don't know about. The set of
6706 acceptable return types is the same in both 32- and 64-bit
6707 mode, so we don't need to inspect mode64 to make a
6708 decision. */
6709 Bool retty_ok = False;
6710 switch (retty) {
6711 case Ity_INVALID: /* function doesn't return anything */
6712 case Ity_V128:
6713 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
6714 retty_ok = True; break;
6715 default:
6716 break;
6718 if (!retty_ok)
6719 break; /* will go to stmt_fail: */
6721 /* Marshal args, do the call, clear stack, set the return value
6722 to 0x555..555 if this is a conditional call that returns a
6723 value and the call is skipped. */
6724 UInt addToSp = 0;
6725 RetLoc rloc = mk_RetLoc_INVALID();
6726 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args,
6727 IEndianess );
6728 vassert(is_sane_RetLoc(rloc));
6730 /* Now figure out what to do with the returned value, if any. */
6731 switch (retty) {
6732 case Ity_INVALID: {
6733 /* No return value. Nothing to do. */
6734 vassert(d->tmp == IRTemp_INVALID);
6735 vassert(rloc.pri == RLPri_None);
6736 vassert(addToSp == 0);
6737 return;
6739 case Ity_I32: case Ity_I16: case Ity_I8: {
6740 /* The returned value is in %r3. Park it in the register
6741 associated with tmp. */
6742 HReg r_dst = lookupIRTemp(env, d->tmp);
6743 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
6744 vassert(rloc.pri == RLPri_Int);
6745 vassert(addToSp == 0);
6746 return;
6748 case Ity_I64:
6749 if (mode64) {
6750 /* The returned value is in %r3. Park it in the register
6751 associated with tmp. */
6752 HReg r_dst = lookupIRTemp(env, d->tmp);
6753 addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
6754 vassert(rloc.pri == RLPri_Int);
6755 vassert(addToSp == 0);
6756 } else {
6757 /* The returned value is in %r3:%r4. Park it in the
6758 register-pair associated with tmp. */
6759 HReg r_dstHi = INVALID_HREG;
6760 HReg r_dstLo = INVALID_HREG;
6761 lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
6762 addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
6763 addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
6764 vassert(rloc.pri == RLPri_2Int);
6765 vassert(addToSp == 0);
6767 return;
6768 case Ity_V128: {
6769 /* The returned value is on the stack, and *retloc tells
6770 us where. Fish it off the stack and then move the
6771 stack pointer upwards to clear it, as directed by
6772 doHelperCall. */
6773 vassert(rloc.pri == RLPri_V128SpRel);
6774 vassert(addToSp >= 16);
6775 HReg dst = lookupIRTemp(env, d->tmp);
6776 PPCAMode* am = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64));
6777 addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am ));
6778 add_to_sp(env, addToSp);
6779 return;
6781 default:
6782 /*NOTREACHED*/
6783 vassert(0);
6787 /* --------- MEM FENCE --------- */
6788 case Ist_MBE:
6789 switch (stmt->Ist.MBE.event) {
6790 case Imbe_Fence:
6791 addInstr(env, PPCInstr_MFence());
6792 return;
6793 default:
6794 break;
6796 break;
6798 /* --------- INSTR MARK --------- */
6799 /* Doesn't generate any executable code ... */
6800 case Ist_IMark:
6801 return;
6803 /* --------- ABI HINT --------- */
6804 /* These have no meaning (denotation in the IR) and so we ignore
6805 them ... if any actually made it this far. */
6806 case Ist_AbiHint:
6807 return;
6809 /* --------- NO-OP --------- */
6810 /* Fairly self-explanatory, wouldn't you say? */
6811 case Ist_NoOp:
6812 return;
6814 /* --------- EXIT --------- */
6815 case Ist_Exit: {
6816 IRConst* dst = stmt->Ist.Exit.dst;
6817 if (!mode64 && dst->tag != Ico_U32)
6818 vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
6819 if (mode64 && dst->tag != Ico_U64)
6820 vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
6822 PPCCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard, IEndianess);
6823 PPCAMode* amCIA = PPCAMode_IR(stmt->Ist.Exit.offsIP,
6824 hregPPC_GPR31(mode64));
6826 /* Case: boring transfer to known address */
6827 if (stmt->Ist.Exit.jk == Ijk_Boring
6828 || stmt->Ist.Exit.jk == Ijk_Call
6829 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
6830 if (env->chainingAllowed) {
6831 /* .. almost always true .. */
6832 /* Skip the event check at the dst if this is a forwards
6833 edge. */
6834 Bool toFastEP
6835 = mode64
6836 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
6837 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
6838 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
6839 addInstr(env, PPCInstr_XDirect(
6840 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
6841 : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
6842 amCIA, cc, toFastEP));
6843 } else {
6844 /* .. very occasionally .. */
6845 /* We can't use chaining, so ask for an assisted transfer,
6846 as that's the only alternative that is allowable. */
6847 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
6848 IEndianess);
6849 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring));
6851 return;
6854 /* Case: assisted transfer to arbitrary address */
6855 switch (stmt->Ist.Exit.jk) {
6856 /* Keep this list in sync with that in iselNext below */
6857 case Ijk_ClientReq:
6858 case Ijk_EmFail:
6859 case Ijk_EmWarn:
6860 case Ijk_NoDecode:
6861 case Ijk_NoRedir:
6862 case Ijk_SigBUS:
6863 case Ijk_SigTRAP:
6864 case Ijk_Sys_syscall:
6865 case Ijk_InvalICache:
6867 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
6868 IEndianess);
6869 addInstr(env, PPCInstr_XAssisted(r, amCIA, cc,
6870 stmt->Ist.Exit.jk));
6871 return;
6873 default:
6874 break;
6877 /* Do we ever expect to see any other kind? */
6878 goto stmt_fail;
6881 default: break;
6883 stmt_fail:
6884 ppIRStmt(stmt);
6885 vpanic("iselStmt(ppc)");
6889 /*---------------------------------------------------------*/
6890 /*--- ISEL: Basic block terminators (Nexts) ---*/
6891 /*---------------------------------------------------------*/
6893 static void iselNext ( ISelEnv* env,
6894 IRExpr* next, IRJumpKind jk, Int offsIP,
6895 IREndness IEndianess)
6897 if (vex_traceflags & VEX_TRACE_VCODE) {
6898 vex_printf( "\n-- PUT(%d) = ", offsIP);
6899 ppIRExpr( next );
6900 vex_printf( "; exit-");
6901 ppIRJumpKind(jk);
6902 vex_printf( "\n");
6905 PPCCondCode always = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
6907 /* Case: boring transfer to known address */
6908 if (next->tag == Iex_Const) {
6909 IRConst* cdst = next->Iex.Const.con;
6910 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
6911 if (jk == Ijk_Boring || jk == Ijk_Call) {
6912 /* Boring transfer to known address */
6913 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6914 if (env->chainingAllowed) {
6915 /* .. almost always true .. */
6916 /* Skip the event check at the dst if this is a forwards
6917 edge. */
6918 Bool toFastEP
6919 = env->mode64
6920 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
6921 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
6922 if (0) vex_printf("%s", toFastEP ? "X" : ".");
6923 addInstr(env, PPCInstr_XDirect(
6924 env->mode64 ? (Addr64)cdst->Ico.U64
6925 : (Addr64)cdst->Ico.U32,
6926 amCIA, always, toFastEP));
6927 } else {
6928 /* .. very occasionally .. */
6929 /* We can't use chaining, so ask for an assisted transfer,
6930 as that's the only alternative that is allowable. */
6931 HReg r = iselWordExpr_R(env, next, IEndianess);
6932 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6933 Ijk_Boring));
6935 return;
6939 /* Case: call/return (==boring) transfer to any address */
6940 switch (jk) {
6941 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
6942 HReg r = iselWordExpr_R(env, next, IEndianess);
6943 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6944 if (env->chainingAllowed) {
6945 addInstr(env, PPCInstr_XIndir(r, amCIA, always));
6946 } else {
6947 addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6948 Ijk_Boring));
6950 return;
6952 default:
6953 break;
6956 /* Case: assisted transfer to arbitrary address */
6957 switch (jk) {
6958 /* Keep this list in sync with that for Ist_Exit above */
6959 case Ijk_ClientReq:
6960 case Ijk_EmFail:
6961 case Ijk_EmWarn:
6962 case Ijk_NoDecode:
6963 case Ijk_NoRedir:
6964 case Ijk_SigBUS:
6965 case Ijk_SigTRAP:
6966 case Ijk_Sys_syscall:
6967 case Ijk_InvalICache:
6969 HReg r = iselWordExpr_R(env, next, IEndianess);
6970 PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6971 addInstr(env, PPCInstr_XAssisted(r, amCIA, always, jk));
6972 return;
6974 default:
6975 break;
6978 vex_printf( "\n-- PUT(%d) = ", offsIP);
6979 ppIRExpr( next );
6980 vex_printf( "; exit-");
6981 ppIRJumpKind(jk);
6982 vex_printf( "\n");
6983 vassert(0); // are we expecting any other kind?
6987 /*---------------------------------------------------------*/
6988 /*--- Insn selector top-level ---*/
6989 /*---------------------------------------------------------*/
6991 /* Translate an entire SB to ppc code. */
6992 HInstrArray* iselSB_PPC ( const IRSB* bb,
6993 VexArch arch_host,
6994 const VexArchInfo* archinfo_host,
6995 const VexAbiInfo* vbi,
6996 Int offs_Host_EvC_Counter,
6997 Int offs_Host_EvC_FailAddr,
6998 Bool chainingAllowed,
6999 Bool addProfInc,
7000 Addr max_ga)
7003 Int i, j;
7004 HReg hregLo, hregMedLo, hregMedHi, hregHi;
7005 ISelEnv* env;
7006 UInt hwcaps_host = archinfo_host->hwcaps;
7007 Bool mode64 = False;
7008 UInt mask32, mask64;
7009 PPCAMode *amCounter, *amFailAddr;
7010 IREndness IEndianess;
7012 vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
7013 mode64 = arch_host == VexArchPPC64;
7015 /* do some sanity checks,
7016 * Note: no 32-bit support for ISA 3.0
7018 mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
7019 | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
7020 | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
7022 mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
7023 | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
7024 | VEX_HWCAPS_PPC64_ISA2_07 | VEX_HWCAPS_PPC64_ISA3_0;
7026 if (mode64) {
7027 vassert((hwcaps_host & mask32) == 0);
7028 } else {
7029 vassert((hwcaps_host & mask64) == 0);
7032 /* Check that the host's endianness is as expected. */
7033 vassert((archinfo_host->endness == VexEndnessBE) ||
7034 (archinfo_host->endness == VexEndnessLE));
7036 if (archinfo_host->endness == VexEndnessBE)
7037 IEndianess = Iend_BE;
7038 else
7039 IEndianess = Iend_LE;
7041 /* Make up an initial environment to use. */
7042 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
7043 env->vreg_ctr = 0;
7045 /* Are we being ppc32 or ppc64? */
7046 env->mode64 = mode64;
7048 /* Set up output code array. */
7049 env->code = newHInstrArray();
7051 /* Copy BB's type env. */
7052 env->type_env = bb->tyenv;
7054 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
7055 * change as we go along.
7057 * vregmap2 and vregmap3 are only used in 32 bit mode
7058 * for supporting I128 in 32-bit mode
7060 env->n_vregmap = bb->tyenv->types_used;
7061 env->vregmapLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
7062 env->vregmapMedLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
7063 if (mode64) {
7064 env->vregmapMedHi = NULL;
7065 env->vregmapHi = NULL;
7066 } else {
7067 env->vregmapMedHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
7068 env->vregmapHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
7071 /* and finally ... */
7072 env->chainingAllowed = chainingAllowed;
7073 env->max_ga = max_ga;
7074 env->hwcaps = hwcaps_host;
7075 env->previous_rm = NULL;
7076 env->vbi = vbi;
7078 /* For each IR temporary, allocate a suitably-kinded virtual
7079 register. */
7080 j = 0;
7081 for (i = 0; i < env->n_vregmap; i++) {
7082 hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
7083 switch (bb->tyenv->types[i]) {
7084 case Ity_I1:
7085 case Ity_I8:
7086 case Ity_I16:
7087 case Ity_I32:
7088 if (mode64) {
7089 hregLo = mkHReg(True, HRcInt64, 0, j++);
7090 } else {
7091 hregLo = mkHReg(True, HRcInt32, 0, j++);
7093 break;
7094 case Ity_I64:
7095 if (mode64) {
7096 hregLo = mkHReg(True, HRcInt64, 0, j++);
7097 } else {
7098 hregLo = mkHReg(True, HRcInt32, 0, j++);
7099 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
7101 break;
7102 case Ity_I128:
7103 if (mode64) {
7104 hregLo = mkHReg(True, HRcInt64, 0, j++);
7105 hregMedLo = mkHReg(True, HRcInt64, 0, j++);
7106 } else {
7107 hregLo = mkHReg(True, HRcInt32, 0, j++);
7108 hregMedLo = mkHReg(True, HRcInt32, 0, j++);
7109 hregMedHi = mkHReg(True, HRcInt32, 0, j++);
7110 hregHi = mkHReg(True, HRcInt32, 0, j++);
7112 break;
7113 case Ity_F32:
7114 case Ity_F64:
7115 hregLo = mkHReg(True, HRcFlt64, 0, j++);
7116 break;
7117 case Ity_F128:
7118 case Ity_V128:
7119 hregLo = mkHReg(True, HRcVec128, 0, j++);
7120 break;
7121 case Ity_D32:
7122 case Ity_D64:
7123 hregLo = mkHReg(True, HRcFlt64, 0, j++);
7124 break;
7125 case Ity_D128:
7126 hregLo = mkHReg(True, HRcFlt64, 0, j++);
7127 hregMedLo = mkHReg(True, HRcFlt64, 0, j++);
7128 break;
7129 default:
7130 ppIRType(bb->tyenv->types[i]);
7131 vpanic("iselBB(ppc): IRTemp type");
7133 env->vregmapLo[i] = hregLo;
7134 env->vregmapMedLo[i] = hregMedLo;
7135 if (!mode64) {
7136 env->vregmapMedHi[i] = hregMedHi;
7137 env->vregmapHi[i] = hregHi;
7140 env->vreg_ctr = j;
7142 /* The very first instruction must be an event check. */
7143 amCounter = PPCAMode_IR(offs_Host_EvC_Counter, hregPPC_GPR31(mode64));
7144 amFailAddr = PPCAMode_IR(offs_Host_EvC_FailAddr, hregPPC_GPR31(mode64));
7145 addInstr(env, PPCInstr_EvCheck(amCounter, amFailAddr));
7147 /* Possibly a block counter increment (for profiling). At this
7148 point we don't know the address of the counter, so just pretend
7149 it is zero. It will have to be patched later, but before this
7150 translation is used, by a call to LibVEX_patchProfCtr. */
7151 if (addProfInc) {
7152 addInstr(env, PPCInstr_ProfInc());
7155 /* Ok, finally we can iterate over the statements. */
7156 for (i = 0; i < bb->stmts_used; i++)
7157 iselStmt(env, bb->stmts[i], IEndianess);
7159 iselNext(env, bb->next, bb->jumpkind, bb->offsIP, IEndianess);
7161 /* record the number of vregs we used. */
7162 env->code->n_vregs = env->vreg_ctr;
7163 return env->code;
7167 /*---------------------------------------------------------------*/
7168 /*--- end host_ppc_isel.c ---*/
7169 /*---------------------------------------------------------------*/