1 
2 /*---------------------------------------------------------------*/
3 /*--- begin                                   host_ppc_isel.c ---*/
4 /*---------------------------------------------------------------*/
5 
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9 
10    Copyright (C) 2004-2013 OpenWorks LLP
11       info@open-works.net
12 
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.
17 
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.
22 
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.
27 
28    The GNU General Public License is contained in the file COPYING.
29 
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.
34 */
35 
36 #include "libvex_basictypes.h"
37 #include "libvex_ir.h"
38 #include "libvex.h"
39 
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"
46 
47 /* GPR register class for ppc32/64 */
48 #define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
49 
50 
51 /*---------------------------------------------------------*/
52 /*--- Register Usage Conventions                        ---*/
53 /*---------------------------------------------------------*/
54 /*
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
68 
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
75 
76   GPR3       [Return | Parameter] - carrying reg
77   GPR4:10    Parameter-carrying regs
78 
79 
80   Floating Point Regs
81   -------------------
82   FPR0:31    Allocateable
83 
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
91 
92 
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
100 */
101 
102 
103 /*---------------------------------------------------------*/
104 /*--- PPC FP Status & Control Register Conventions      ---*/
105 /*---------------------------------------------------------*/
106 /*
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.
113 
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.
117 */
118 /* Notes on the FP instruction set, 6 Feb 06.
119 
120 What                 exns -> CR1 ?   Sets FPRF ?   Observes RM ?
121 -------------------------------------------------------------
122 
123 fmr[.]                   if .             n             n
124 fneg[.]                  if .             n             n
125 fabs[.]                  if .             n             n
126 fnabs[.]                 if .             n             n
127 
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
148 
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
154 
155 fre[.]                   if .             y             y
156 fres[.]                  if .             y             y
157 
158 frsqrte[.]               if .             y       apparently not
159 
160 fsqrt[.]                 if .             y             y
161 fsqrts[.]                if .             y             y
162 fsub[.]                  if .             y             y
163 fsubs[.]                 if .             y             y
164 
165 
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
169 
170 ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF
171 in future)
172 
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]
179 
180 For [.] presumably cr1 is set with exn summary bits, as per
181 main FP insns
182 
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.
186 */
187 
188 
189 /*---------------------------------------------------------*/
190 /*--- misc helpers                                      ---*/
191 /*---------------------------------------------------------*/
192 
193 /* These are duplicated in guest-ppc/toIR.c */
unop(IROp op,IRExpr * a)194 static IRExpr* unop ( IROp op, IRExpr* a )
195 {
196    return IRExpr_Unop(op, a);
197 }
198 
mkU32(UInt i)199 static IRExpr* mkU32 ( UInt i )
200 {
201    return IRExpr_Const(IRConst_U32(i));
202 }
203 
bind(Int binder)204 static IRExpr* bind ( Int binder )
205 {
206    return IRExpr_Binder(binder);
207 }
208 
isZeroU8(IRExpr * e)209 static Bool isZeroU8 ( IRExpr* e )
210 {
211    return e->tag == Iex_Const
212           && e->Iex.Const.con->tag == Ico_U8
213           && e->Iex.Const.con->Ico.U8 == 0;
214 }
215 
216 
217 /*---------------------------------------------------------*/
218 /*--- ISelEnv                                           ---*/
219 /*---------------------------------------------------------*/
220 
221 /* This carries around:
222 
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.
226 
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.
232 
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.
243 
244     - The code array, that is, the insns selected so far.
245 
246     - A counter, for generating new virtual registers.
247 
248     - The host subarchitecture we are selecting insns for.
249       This is set at the start and does not change.
250 
251     - A Bool to tell us if the host is 32 or 64bit.
252       This is set at the start and does not change.
253 
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.
259 
260     - A VexMiscInfo*, needed for knowing how to generate
261       function calls for this target.
262 
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.
270 */
271 
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;
282 
283       /* 27 Jan 06: Not currently used, but should be */
284       UInt         hwcaps;
285 
286       Bool         mode64;
287 
288       const VexAbiInfo*  vbi;   // unused
289 
290       Bool         chainingAllowed;
291       Addr64       max_ga;
292 
293       /* These are modified as we go along. */
294       HInstrArray* code;
295       Int          vreg_ctr;
296 
297       IRExpr*      previous_rm;
298    }
299    ISelEnv;
300 
301 
lookupIRTemp(ISelEnv * env,IRTemp tmp)302 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
303 {
304    vassert(tmp >= 0);
305    vassert(tmp < env->n_vregmap);
306    return env->vregmapLo[tmp];
307 }
308 
lookupIRTempPair(HReg * vrHI,HReg * vrLO,ISelEnv * env,IRTemp tmp)309 static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO,
310                                ISelEnv* env, IRTemp tmp )
311 {
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];
317 }
318 
319 /* Only for used in 32-bit mode */
lookupIRTempQuad(HReg * vrHi,HReg * vrMedHi,HReg * vrMedLo,HReg * vrLo,ISelEnv * env,IRTemp tmp)320 static void lookupIRTempQuad ( HReg* vrHi, HReg* vrMedHi, HReg* vrMedLo,
321                                HReg* vrLo, ISelEnv* env, IRTemp tmp )
322 {
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];
331 }
332 
addInstr(ISelEnv * env,PPCInstr * instr)333 static void addInstr ( ISelEnv* env, PPCInstr* instr )
334 {
335    addHInstr(env->code, instr);
336    if (vex_traceflags & VEX_TRACE_VCODE) {
337       ppPPCInstr(instr, env->mode64);
338       vex_printf("\n");
339    }
340 }
341 
newVRegI(ISelEnv * env)342 static HReg newVRegI ( ISelEnv* env )
343 {
344    HReg reg
345       = mkHReg(True/*vreg*/, HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
346    env->vreg_ctr++;
347    return reg;
348 }
349 
newVRegF(ISelEnv * env)350 static HReg newVRegF ( ISelEnv* env )
351 {
352    HReg reg = mkHReg(True/*vreg*/, HRcFlt64, 0/*enc*/, env->vreg_ctr);
353    env->vreg_ctr++;
354    return reg;
355 }
356 
newVRegV(ISelEnv * env)357 static HReg newVRegV ( ISelEnv* env )
358 {
359    HReg reg = mkHReg(True/*vreg*/, HRcVec128, 0/*enc*/, env->vreg_ctr);
360    env->vreg_ctr++;
361    return reg;
362 }
363 
364 
365 /*---------------------------------------------------------*/
366 /*--- ISEL: Forward declarations                        ---*/
367 /*---------------------------------------------------------*/
368 
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.
374 
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.
379 */
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, IRExpr* e,
383                                           IREndness IEndianess );
384 static HReg          iselWordExpr_R     ( ISelEnv* env, IRExpr* e,
385                                           IREndness IEndianess );
386 
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.
395 */
396 static PPCRH*        iselWordExpr_RH_wrk ( ISelEnv* env,
397                                            Bool syned, IRExpr* e,
398                                            IREndness IEndianess );
399 static PPCRH*        iselWordExpr_RH     ( ISelEnv* env,
400                                            Bool syned, IRExpr* e,
401                                            IREndness IEndianess );
402 
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, IRExpr* e,
406                                            IREndness IEndianess );
407 static PPCRI*        iselWordExpr_RI     ( ISelEnv* env, IRExpr* e,
408                                            IREndness IEndianess );
409 
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, IRExpr* e,
414                                              IREndness IEndianess );
415 static PPCRH*        iselWordExpr_RH5u     ( ISelEnv* env, IRExpr* e,
416                                              IREndness IEndianess );
417 
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, IRExpr* e,
422                                              IREndness IEndianess );
423 static PPCRH*        iselWordExpr_RH6u     ( ISelEnv* env, IRExpr* e,
424                                              IREndness IEndianess );
425 
426 /* 32-bit mode: compute an I32 into an AMode.
427    64-bit mode: compute an I64 into an AMode.
428 
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.
434 
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, IRExpr* e,
438                                               IRType xferTy,
439                                               IREndness IEndianess );
440 static PPCAMode*     iselWordExpr_AMode     ( ISelEnv* env, IRExpr* e,
441                                               IRType xferTy,
442                                               IREndness IEndianess );
443 
444 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
445                                          HReg* rMedLo, HReg* rLo,
446                                          ISelEnv* env, IRExpr* e,
447                                          IREndness IEndianess );
448 static void iselInt128Expr_to_32x4     ( HReg* rHi, HReg* rMedHi,
449                                          HReg* rMedLo, HReg* rLo,
450                                          ISelEnv* env, IRExpr* e,
451                                          IREndness IEndianess );
452 
453 
454 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */
455 static void          iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
456                                          ISelEnv* env, IRExpr* e,
457                                          IREndness IEndianess );
458 static void          iselInt64Expr     ( HReg* rHi, HReg* rLo,
459                                          ISelEnv* env, IRExpr* e,
460                                          IREndness IEndianess );
461 
462 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
463 static void          iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
464                                           ISelEnv* env, IRExpr* e,
465                                           IREndness IEndianess );
466 
467 static void          iselInt128Expr     ( HReg* rHi, HReg* rLo,
468                                           ISelEnv* env, IRExpr* e,
469                                           IREndness IEndianess );
470 
471 static PPCCondCode   iselCondCode_wrk ( ISelEnv* env, IRExpr* e,
472                                         IREndness IEndianess );
473 static PPCCondCode   iselCondCode     ( ISelEnv* env, IRExpr* e,
474                                         IREndness IEndianess );
475 
476 static HReg          iselDblExpr_wrk ( ISelEnv* env, IRExpr* e,
477                                        IREndness IEndianess );
478 static HReg          iselDblExpr     ( ISelEnv* env, IRExpr* e,
479                                        IREndness IEndianess );
480 
481 static HReg          iselFltExpr_wrk ( ISelEnv* env, IRExpr* e,
482                                        IREndness IEndianess );
483 static HReg          iselFltExpr     ( ISelEnv* env, IRExpr* e,
484                                        IREndness IEndianess );
485 
486 static HReg          iselVecExpr_wrk ( ISelEnv* env, IRExpr* e,
487                                        IREndness IEndianess );
488 static HReg          iselVecExpr     ( ISelEnv* env, IRExpr* e,
489                                        IREndness IEndianess );
490 
491 /* 64-bit mode ONLY. */
492 static HReg          iselDfp32Expr_wrk ( ISelEnv* env, IRExpr* e,
493                                          IREndness IEndianess );
494 static HReg          iselDfp32Expr     ( ISelEnv* env, IRExpr* e,
495                                          IREndness IEndianess );
496 static HReg          iselDfp64Expr_wrk ( ISelEnv* env, IRExpr* e,
497                                          IREndness IEndianess );
498 static HReg          iselDfp64Expr     ( ISelEnv* env, IRExpr* e,
499                                          IREndness IEndianess );
500 
501 /* 64-bit mode ONLY: compute an D128 into a GPR64 pair. */
502 static void iselDfp128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env,
503                                  IRExpr* e, IREndness IEndianess );
504 static void iselDfp128Expr     ( HReg* rHi, HReg* rLo, ISelEnv* env,
505                                  IRExpr* e, IREndness IEndianess );
506 
507 /*---------------------------------------------------------*/
508 /*--- ISEL: Misc helpers                                ---*/
509 /*---------------------------------------------------------*/
510 
511 /* Make an int reg-reg move. */
512 
mk_iMOVds_RR(HReg r_dst,HReg r_src)513 static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src )
514 {
515    vassert(hregClass(r_dst) == hregClass(r_src));
516    vassert(hregClass(r_src) ==  HRcInt32 ||
517            hregClass(r_src) ==  HRcInt64);
518    return PPCInstr_Alu(Palu_OR, r_dst, r_src, PPCRH_Reg(r_src));
519 }
520 
521 /* Advance/retreat %r1 by n. */
522 
add_to_sp(ISelEnv * env,UInt n)523 static void add_to_sp ( ISelEnv* env, UInt n )
524 {
525    HReg sp = StackFramePtr(env->mode64);
526    vassert(n <= 1024 && (n%16) == 0);
527    addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp,
528                                PPCRH_Imm(True,toUShort(n)) ));
529 }
530 
sub_from_sp(ISelEnv * env,UInt n)531 static void sub_from_sp ( ISelEnv* env, UInt n )
532 {
533    HReg sp = StackFramePtr(env->mode64);
534    vassert(n <= 1024 && (n%16) == 0);
535    addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp,
536                                PPCRH_Imm(True,toUShort(n)) ));
537 }
538 
539 /*
540   returns a quadword aligned address on the stack
541    - copies SP, adds 16bytes, aligns to quadword.
542   use sub_from_sp(32) before calling this,
543   as expects to have 32 bytes to play with.
544 */
get_sp_aligned16(ISelEnv * env)545 static HReg get_sp_aligned16 ( ISelEnv* env )
546 {
547    HReg       r = newVRegI(env);
548    HReg align16 = newVRegI(env);
549    addInstr(env, mk_iMOVds_RR(r, StackFramePtr(env->mode64)));
550    // add 16
551    addInstr(env, PPCInstr_Alu( Palu_ADD, r, r,
552                                PPCRH_Imm(True,toUShort(16)) ));
553    // mask to quadword
554    addInstr(env,
555             PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64));
556    addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16)));
557    return r;
558 }
559 
560 
561 
562 /* Load 2*I32 regs to fp reg */
mk_LoadRR32toFPR(ISelEnv * env,HReg r_srcHi,HReg r_srcLo)563 static HReg mk_LoadRR32toFPR ( ISelEnv* env,
564                                HReg r_srcHi, HReg r_srcLo )
565 {
566    HReg fr_dst = newVRegF(env);
567    PPCAMode *am_addr0, *am_addr1;
568 
569    vassert(!env->mode64);
570    vassert(hregClass(r_srcHi) == HRcInt32);
571    vassert(hregClass(r_srcLo) == HRcInt32);
572 
573    sub_from_sp( env, 16 );        // Move SP down 16 bytes
574    am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
575    am_addr1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
576 
577    // store hi,lo as Ity_I32's
578    addInstr(env, PPCInstr_Store( 4, am_addr0, r_srcHi, env->mode64 ));
579    addInstr(env, PPCInstr_Store( 4, am_addr1, r_srcLo, env->mode64 ));
580 
581    // load as float
582    addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
583 
584    add_to_sp( env, 16 );          // Reset SP
585    return fr_dst;
586 }
587 
588 /* Load I64 reg to fp reg */
mk_LoadR64toFPR(ISelEnv * env,HReg r_src)589 static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src )
590 {
591    HReg fr_dst = newVRegF(env);
592    PPCAMode *am_addr0;
593 
594    vassert(env->mode64);
595    vassert(hregClass(r_src) == HRcInt64);
596 
597    sub_from_sp( env, 16 );        // Move SP down 16 bytes
598    am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
599 
600    // store as Ity_I64
601    addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 ));
602 
603    // load as float
604    addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
605 
606    add_to_sp( env, 16 );          // Reset SP
607    return fr_dst;
608 }
609 
610 
611 /* Given an amode, return one which references 4 bytes further
612    along. */
613 
advance4(ISelEnv * env,PPCAMode * am)614 static PPCAMode* advance4 ( ISelEnv* env, PPCAMode* am )
615 {
616    PPCAMode* am4 = dopyPPCAMode( am );
617    if (am4->tag == Pam_IR
618        && am4->Pam.IR.index + 4 <= 32767) {
619       am4->Pam.IR.index += 4;
620    } else {
621       vpanic("advance4(ppc,host)");
622    }
623    return am4;
624 }
625 
626 
627 /* Given a guest-state array descriptor, an index expression and a
628    bias, generate a PPCAMode pointing at the relevant piece of
629    guest state.  */
630 static
genGuestArrayOffset(ISelEnv * env,IRRegArray * descr,IRExpr * off,Int bias,IREndness IEndianess)631 PPCAMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
632                                 IRExpr* off, Int bias, IREndness IEndianess )
633 {
634    HReg rtmp, roff;
635    Int  elemSz = sizeofIRType(descr->elemTy);
636    Int  nElems = descr->nElems;
637    Int  shift  = 0;
638 
639    /* Throw out any cases we don't need.  In theory there might be a
640       day where we need to handle others, but not today. */
641 
642    if (nElems != 16 && nElems != 32)
643       vpanic("genGuestArrayOffset(ppc host)(1)");
644 
645    switch (elemSz) {
646       case 4:  shift = 2; break;
647       case 8:  shift = 3; break;
648       default: vpanic("genGuestArrayOffset(ppc host)(2)");
649    }
650 
651    if (bias < -100 || bias > 100) /* somewhat arbitrarily */
652       vpanic("genGuestArrayOffset(ppc host)(3)");
653    if (descr->base < 0 || descr->base > 5000) /* somewhat arbitrarily */
654       vpanic("genGuestArrayOffset(ppc host)(4)");
655 
656    /* Compute off into a reg, %off.  Then return:
657 
658          addi %tmp, %off, bias (if bias != 0)
659          andi %tmp, nElems-1
660          sldi %tmp, shift
661          addi %tmp, %tmp, base
662          ... Baseblockptr + %tmp ...
663    */
664    roff = iselWordExpr_R(env, off, IEndianess);
665    rtmp = newVRegI(env);
666    addInstr(env, PPCInstr_Alu(
667                     Palu_ADD,
668                     rtmp, roff,
669                     PPCRH_Imm(True/*signed*/, toUShort(bias))));
670    addInstr(env, PPCInstr_Alu(
671                     Palu_AND,
672                     rtmp, rtmp,
673                     PPCRH_Imm(False/*unsigned*/, toUShort(nElems-1))));
674    addInstr(env, PPCInstr_Shft(
675                     Pshft_SHL,
676                     env->mode64 ? False : True/*F:64-bit, T:32-bit shift*/,
677                     rtmp, rtmp,
678                     PPCRH_Imm(False/*unsigned*/, toUShort(shift))));
679    addInstr(env, PPCInstr_Alu(
680                     Palu_ADD,
681                     rtmp, rtmp,
682                     PPCRH_Imm(True/*signed*/, toUShort(descr->base))));
683    return
684       PPCAMode_RR( GuestStatePtr(env->mode64), rtmp );
685 }
686 
687 
688 /*---------------------------------------------------------*/
689 /*--- ISEL: Function call helpers                       ---*/
690 /*---------------------------------------------------------*/
691 
692 /* Used only in doHelperCall.  See big comment in doHelperCall re
693    handling of register-parameter args.  This function figures out
694    whether evaluation of an expression might require use of a fixed
695    register.  If in doubt return True (safe but suboptimal).
696 */
697 static
mightRequireFixedRegs(IRExpr * e)698 Bool mightRequireFixedRegs ( IRExpr* e )
699 {
700    switch (e->tag) {
701    case Iex_RdTmp: case Iex_Const: case Iex_Get:
702       return False;
703    default:
704       return True;
705    }
706 }
707 
708 
709 /* Do a complete function call.  |guard| is a Ity_Bit expression
710    indicating whether or not the call happens.  If guard==NULL, the
711    call is unconditional.  |retloc| is set to indicate where the
712    return value is after the call.  The caller (of this fn) must
713    generate code to add |stackAdjustAfterCall| to the stack pointer
714    after the call is done. */
715 
716 static
doHelperCall(UInt * stackAdjustAfterCall,RetLoc * retloc,ISelEnv * env,IRExpr * guard,IRCallee * cee,IRType retTy,IRExpr ** args,IREndness IEndianess)717 void doHelperCall ( /*OUT*/UInt*   stackAdjustAfterCall,
718                     /*OUT*/RetLoc* retloc,
719                     ISelEnv* env,
720                     IRExpr* guard,
721                     IRCallee* cee, IRType retTy, IRExpr** args,
722                     IREndness IEndianess)
723 {
724    PPCCondCode cc;
725    HReg        argregs[PPC_N_REGPARMS];
726    HReg        tmpregs[PPC_N_REGPARMS];
727    Bool        go_fast;
728    Int         n_args, i, argreg;
729    UInt        argiregs;
730    Bool        mode64 = env->mode64;
731 
732    /* Set default returns.  We'll update them later if needed. */
733    *stackAdjustAfterCall = 0;
734    *retloc               = mk_RetLoc_INVALID();
735 
736    /* These are used for cross-checking that IR-level constraints on
737       the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
738    UInt nVECRETs = 0;
739    UInt nBBPTRs  = 0;
740 
741    /* Marshal args for a call and do the call.
742 
743       This function only deals with a tiny set of possibilities, which
744       cover all helpers in practice.  The restrictions are that only
745       arguments in registers are supported, hence only PPC_N_REGPARMS x
746       (mode32:32 | mode64:64) integer bits in total can be passed.
747       In fact the only supported arg type is (mode32:I32 | mode64:I64).
748 
749       The return type can be I{64,32,16,8} or V{128,256}.  In the
750       latter two cases, it is expected that |args| will contain the
751       special node IRExpr_VECRET(), in which case this routine
752       generates code to allocate space on the stack for the vector
753       return value.  Since we are not passing any scalars on the
754       stack, it is enough to preallocate the return space before
755       marshalling any arguments, in this case.
756 
757       |args| may also contain IRExpr_BBPTR(), in which case the value
758       in the guest state pointer register is passed as the
759       corresponding argument.
760 
761       Generating code which is both efficient and correct when
762       parameters are to be passed in registers is difficult, for the
763       reasons elaborated in detail in comments attached to
764       doHelperCall() in priv/host-x86/isel.c.  Here, we use a variant
765       of the method described in those comments.
766 
767       The problem is split into two cases: the fast scheme and the
768       slow scheme.  In the fast scheme, arguments are computed
769       directly into the target (real) registers.  This is only safe
770       when we can be sure that computation of each argument will not
771       trash any real registers set by computation of any other
772       argument.
773 
774       In the slow scheme, all args are first computed into vregs, and
775       once they are all done, they are moved to the relevant real
776       regs.  This always gives correct code, but it also gives a bunch
777       of vreg-to-rreg moves which are usually redundant but are hard
778       for the register allocator to get rid of.
779 
780       To decide which scheme to use, all argument expressions are
781       first examined.  If they are all so simple that it is clear they
782       will be evaluated without use of any fixed registers, use the
783       fast scheme, else use the slow scheme.  Note also that only
784       unconditional calls may use the fast scheme, since having to
785       compute a condition expression could itself trash real
786       registers.
787 
788       Note this requires being able to examine an expression and
789       determine whether or not evaluation of it might use a fixed
790       register.  That requires knowledge of how the rest of this insn
791       selector works.  Currently just the following 3 are regarded as
792       safe -- hopefully they cover the majority of arguments in
793       practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
794    */
795 
796    /* Note that the cee->regparms field is meaningless on PPC32/64 host
797       (since there is only one calling convention) and so we always
798       ignore it. */
799 
800    n_args = 0;
801    for (i = 0; args[i]; i++)
802       n_args++;
803 
804    if (n_args > PPC_N_REGPARMS) {
805       vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
806       // PPC_N_REGPARMS
807    }
808 
809    /* This is kind of stupid .. the arrays are sized as PPC_N_REGPARMS
810       but we then assume that that value is 8. */
811    vassert(PPC_N_REGPARMS == 8);
812 
813    argregs[0] = hregPPC_GPR3(mode64);
814    argregs[1] = hregPPC_GPR4(mode64);
815    argregs[2] = hregPPC_GPR5(mode64);
816    argregs[3] = hregPPC_GPR6(mode64);
817    argregs[4] = hregPPC_GPR7(mode64);
818    argregs[5] = hregPPC_GPR8(mode64);
819    argregs[6] = hregPPC_GPR9(mode64);
820    argregs[7] = hregPPC_GPR10(mode64);
821    argiregs = 0;
822 
823    tmpregs[0] = tmpregs[1] = tmpregs[2] =
824    tmpregs[3] = tmpregs[4] = tmpregs[5] =
825    tmpregs[6] = tmpregs[7] = INVALID_HREG;
826 
827    /* First decide which scheme (slow or fast) is to be used.  First
828       assume the fast scheme, and select slow if any contraindications
829       (wow) appear. */
830 
831    go_fast = True;
832 
833    /* We'll need space on the stack for the return value.  Avoid
834       possible complications with nested calls by using the slow
835       scheme. */
836    if (retTy == Ity_V128 || retTy == Ity_V256)
837       go_fast = False;
838 
839    if (go_fast && guard) {
840       if (guard->tag == Iex_Const
841           && guard->Iex.Const.con->tag == Ico_U1
842           && guard->Iex.Const.con->Ico.U1 == True) {
843          /* unconditional */
844       } else {
845          /* Not manifestly unconditional -- be conservative. */
846          go_fast = False;
847       }
848    }
849 
850    if (go_fast) {
851       for (i = 0; i < n_args; i++) {
852          IRExpr* arg = args[i];
853          if (UNLIKELY(arg->tag == Iex_BBPTR)) {
854             /* that's OK */
855          }
856          else if (UNLIKELY(arg->tag == Iex_VECRET)) {
857             /* This implies ill-formed IR, since if the IR was
858                well-formed, the return-type test above would have
859                filtered it out. */
860             vpanic("doHelperCall(PPC): invalid IR");
861          }
862          else if (mightRequireFixedRegs(arg)) {
863             go_fast = False;
864             break;
865          }
866       }
867    }
868 
869    /* At this point the scheme to use has been established.  Generate
870       code to get the arg values into the argument rregs. */
871 
872    if (go_fast) {
873 
874       /* FAST SCHEME */
875       argreg = 0;
876 
877       for (i = 0; i < n_args; i++) {
878          IRExpr* arg = args[i];
879          vassert(argreg < PPC_N_REGPARMS);
880 
881          if (arg->tag == Iex_BBPTR) {
882             argiregs |= (1 << (argreg+3));
883             addInstr(env, mk_iMOVds_RR( argregs[argreg],
884                                         GuestStatePtr(mode64) ));
885             argreg++;
886          } else {
887             vassert(arg->tag != Iex_VECRET);
888             IRType ty = typeOfIRExpr(env->type_env, arg);
889             vassert(ty == Ity_I32 || ty == Ity_I64);
890             if (!mode64) {
891                if (ty == Ity_I32) {
892                   argiregs |= (1 << (argreg+3));
893                   addInstr(env,
894                            mk_iMOVds_RR( argregs[argreg],
895                                          iselWordExpr_R(env, arg,
896 							IEndianess) ));
897                } else { // Ity_I64 in 32-bit mode
898                   HReg rHi, rLo;
899                   if ((argreg%2) == 1)
900                                  // ppc32 ELF abi spec for passing LONG_LONG
901                      argreg++;   // XXX: odd argreg => even rN
902                   vassert(argreg < PPC_N_REGPARMS-1);
903                   iselInt64Expr(&rHi,&rLo, env, arg, IEndianess);
904                   argiregs |= (1 << (argreg+3));
905                   addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
906                   argiregs |= (1 << (argreg+3));
907                   addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
908                }
909             } else { // mode64
910                argiregs |= (1 << (argreg+3));
911                addInstr(env, mk_iMOVds_RR( argregs[argreg],
912                                            iselWordExpr_R(env, arg,
913                                                           IEndianess) ));
914             }
915             argreg++;
916          } /* if (arg == IRExprP__BBPR) */
917       }
918 
919       /* Fast scheme only applies for unconditional calls.  Hence: */
920       cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
921 
922    } else {
923 
924       /* SLOW SCHEME; move via temporaries */
925       argreg = 0;
926 
927       /* If we have a vector return type, allocate a place for it on
928          the stack and record its address.  Rather than figure out the
929          complexities of PPC{32,64} ELF ABI stack frame layout, simply
930          drop the SP by 1024 and allocate the return point in the
931          middle.  I think this should comfortably clear any ABI
932          mandated register save areas.  Note that it doesn't maintain
933          the backchain as it should, since we're not doing st{d,w}u to
934          adjust the SP, but .. that doesn't seem to be a big deal.
935          Since we're not expecting to have to unwind out of here. */
936       HReg r_vecRetAddr = INVALID_HREG;
937       if (retTy == Ity_V128) {
938          r_vecRetAddr = newVRegI(env);
939          sub_from_sp(env, 512);
940          addInstr(env, mk_iMOVds_RR( r_vecRetAddr, StackFramePtr(mode64) ));
941          sub_from_sp(env, 512);
942       }
943       else if (retTy == Ity_V256) {
944          vassert(0); //ATC
945          r_vecRetAddr = newVRegI(env);
946          sub_from_sp(env, 512);
947          addInstr(env, mk_iMOVds_RR( r_vecRetAddr, StackFramePtr(mode64) ));
948          sub_from_sp(env, 512);
949       }
950 
951       vassert(n_args >= 0 && n_args <= 8);
952       for (i = 0; i < n_args; i++) {
953          IRExpr* arg = args[i];
954          vassert(argreg < PPC_N_REGPARMS);
955          if (UNLIKELY(arg->tag == Iex_BBPTR)) {
956             tmpregs[argreg] = newVRegI(env);
957             addInstr(env, mk_iMOVds_RR( tmpregs[argreg],
958                                         GuestStatePtr(mode64) ));
959             nBBPTRs++;
960          }
961          else if (UNLIKELY(arg->tag == Iex_VECRET)) {
962             /* We stashed the address of the return slot earlier, so just
963                retrieve it now. */
964             vassert(!hregIsInvalid(r_vecRetAddr));
965             tmpregs[i] = r_vecRetAddr;
966             nVECRETs++;
967          }
968          else {
969             IRType ty = typeOfIRExpr(env->type_env, arg);
970             vassert(ty == Ity_I32 || ty == Ity_I64);
971             if (!mode64) {
972                if (ty == Ity_I32) {
973                   tmpregs[argreg] = iselWordExpr_R(env, arg, IEndianess);
974                } else { // Ity_I64 in 32-bit mode
975                   HReg rHi, rLo;
976                   if ((argreg%2) == 1)
977                                 // ppc32 ELF abi spec for passing LONG_LONG
978                      argreg++;  // XXX: odd argreg => even rN
979                   vassert(argreg < PPC_N_REGPARMS-1);
980                   iselInt64Expr(&rHi,&rLo, env, arg, IEndianess);
981                   tmpregs[argreg++] = rHi;
982                   tmpregs[argreg]   = rLo;
983                }
984             } else { // mode64
985                tmpregs[argreg] = iselWordExpr_R(env, arg, IEndianess);
986             }
987          }
988          argreg++;
989       }
990 
991       /* Now we can compute the condition.  We can't do it earlier
992          because the argument computations could trash the condition
993          codes.  Be a bit clever to handle the common case where the
994          guard is 1:Bit. */
995       cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
996       if (guard) {
997          if (guard->tag == Iex_Const
998              && guard->Iex.Const.con->tag == Ico_U1
999              && guard->Iex.Const.con->Ico.U1 == True) {
1000             /* unconditional -- do nothing */
1001          } else {
1002             cc = iselCondCode( env, guard, IEndianess );
1003          }
1004       }
1005 
1006       /* Move the args to their final destinations. */
1007       for (i = 0; i < argreg; i++) {
1008          if (hregIsInvalid(tmpregs[i]))  // Skip invalid regs
1009             continue;
1010          /* None of these insns, including any spill code that might
1011             be generated, may alter the condition codes. */
1012          argiregs |= (1 << (i+3));
1013          addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
1014       }
1015 
1016    }
1017 
1018    /* Do final checks, set the return values, and generate the call
1019       instruction proper. */
1020    if (retTy == Ity_V128 || retTy == Ity_V256) {
1021       vassert(nVECRETs == 1);
1022    } else {
1023       vassert(nVECRETs == 0);
1024    }
1025 
1026    vassert(nBBPTRs == 0 || nBBPTRs == 1);
1027 
1028    vassert(*stackAdjustAfterCall == 0);
1029    vassert(is_RetLoc_INVALID(*retloc));
1030    switch (retTy) {
1031       case Ity_INVALID:
1032          /* Function doesn't return a value. */
1033          *retloc = mk_RetLoc_simple(RLPri_None);
1034          break;
1035       case Ity_I64:
1036          *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
1037          break;
1038       case Ity_I32: case Ity_I16: case Ity_I8:
1039          *retloc = mk_RetLoc_simple(RLPri_Int);
1040          break;
1041       case Ity_V128:
1042          /* Result is 512 bytes up the stack, and after it has been
1043             retrieved, adjust SP upwards by 1024. */
1044          *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 512);
1045          *stackAdjustAfterCall = 1024;
1046          break;
1047       case Ity_V256:
1048          vassert(0); // ATC
1049          /* Ditto */
1050          *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 512);
1051          *stackAdjustAfterCall = 1024;
1052          break;
1053       default:
1054          /* IR can denote other possible return types, but we don't
1055             handle those here. */
1056          vassert(0);
1057    }
1058 
1059    /* Finally, generate the call itself.  This needs the *retloc value
1060       set in the switch above, which is why it's at the end. */
1061 
1062    Addr64 target = mode64 ? (Addr)cee->addr
1063                           : toUInt((Addr)(cee->addr));
1064    addInstr(env, PPCInstr_Call( cc, target, argiregs, *retloc ));
1065 }
1066 
1067 
1068 /*---------------------------------------------------------*/
1069 /*--- ISEL: FP rounding mode helpers                    ---*/
1070 /*---------------------------------------------------------*/
1071 
1072 ///* Set FPU's rounding mode to the default */
1073 //static
1074 //void set_FPU_rounding_default ( ISelEnv* env )
1075 //{
1076 //   HReg fr_src = newVRegF(env);
1077 //   HReg r_src  = newVRegI(env);
1078 //
1079 //   /* Default rounding mode = 0x0
1080 //      Only supporting the rounding-mode bits - the rest of FPSCR is 0x0
1081 //       - so we can set the whole register at once (faster)
1082 //      note: upper 32 bits ignored by FpLdFPSCR
1083 //   */
1084 //   addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64));
1085 //   if (env->mode64) {
1086 //      fr_src = mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
1087 //   } else {
1088 //      fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1089 //   }
1090 //   addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
1091 //}
1092 
1093 /* Convert IR rounding mode to PPC encoding */
roundModeIRtoPPC(ISelEnv * env,HReg r_rmIR)1094 static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
1095 {
1096    /*
1097    rounding mode                     | PPC  |  IR
1098    -----------------------------------------------
1099    to nearest, ties to even          | 000  | 000
1100    to zero                           | 001  | 011
1101    to +infinity                      | 010  | 010
1102    to -infinity                      | 011  | 001
1103    +++++ Below are the extended rounding modes for decimal floating point +++++
1104    to nearest, ties away from 0      | 100  | 100
1105    to nearest, ties toward 0         | 101  | 111
1106    to away from 0                    | 110  | 110
1107    to prepare for shorter precision  | 111  | 101
1108    */
1109    HReg r_rmPPC = newVRegI(env);
1110    HReg r_tmp1  = newVRegI(env);
1111    HReg r_tmp2  = newVRegI(env);
1112 
1113    vassert(hregClass(r_rmIR) == HRcGPR(env->mode64));
1114 
1115    // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3
1116    //
1117    // slwi  tmp1,    r_rmIR, 1
1118    // xor   tmp1,    r_rmIR, tmp1
1119    // andi  r_rmPPC, tmp1, 3
1120 
1121    addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1122                                r_tmp1, r_rmIR, PPCRH_Imm(False,1)));
1123 
1124    addInstr( env, PPCInstr_Alu( Palu_AND,
1125                                 r_tmp2, r_tmp1, PPCRH_Imm( False, 3 ) ) );
1126 
1127    addInstr( env, PPCInstr_Alu( Palu_XOR,
1128                                 r_rmPPC, r_rmIR, PPCRH_Reg( r_tmp2 ) ) );
1129 
1130    return r_rmPPC;
1131 }
1132 
1133 
1134 /* Set the FPU's rounding mode: 'mode' is an I32-typed expression
1135    denoting a value in the range 0 .. 7, indicating a round mode
1136    encoded as per type IRRoundingMode.  Set the PPC FPSCR to have the
1137    same rounding.  When the dfp_rm arg is True, set the decimal
1138    floating point rounding mode bits (29:31); otherwise, set the
1139    binary floating point rounding mode bits (62:63).
1140 
1141    For speed & simplicity, we're setting the *entire* FPSCR here.
1142 
1143    Setting the rounding mode is expensive.  So this function tries to
1144    avoid repeatedly setting the rounding mode to the same thing by
1145    first comparing 'mode' to the 'mode' tree supplied in the previous
1146    call to this function, if any.  (The previous value is stored in
1147    env->previous_rm.)  If 'mode' is a single IR temporary 't' and
1148    env->previous_rm is also just 't', then the setting is skipped.
1149 
1150    This is safe because of the SSA property of IR: an IR temporary can
1151    only be defined once and so will have the same value regardless of
1152    where it appears in the block.  Cool stuff, SSA.
1153 
1154    A safety condition: all attempts to set the RM must be aware of
1155    this mechanism - by being routed through the functions here.
1156 
1157    Of course this only helps if blocks where the RM is set more than
1158    once and it is set to the same value each time, *and* that value is
1159    held in the same IR temporary each time.  In order to assure the
1160    latter as much as possible, the IR optimiser takes care to do CSE
1161    on any block with any sign of floating point activity.
1162 */
1163 static
_set_FPU_rounding_mode(ISelEnv * env,IRExpr * mode,Bool dfp_rm,IREndness IEndianess)1164 void _set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode, Bool dfp_rm,
1165                               IREndness IEndianess )
1166 {
1167    HReg fr_src = newVRegF(env);
1168    HReg r_src;
1169 
1170    vassert(typeOfIRExpr(env->type_env,mode) == Ity_I32);
1171 
1172    /* Do we need to do anything? */
1173    if (env->previous_rm
1174        && env->previous_rm->tag == Iex_RdTmp
1175        && mode->tag == Iex_RdTmp
1176        && env->previous_rm->Iex.RdTmp.tmp == mode->Iex.RdTmp.tmp) {
1177       /* no - setting it to what it was before.  */
1178       vassert(typeOfIRExpr(env->type_env, env->previous_rm) == Ity_I32);
1179       return;
1180    }
1181 
1182    /* No luck - we better set it, and remember what we set it to. */
1183    env->previous_rm = mode;
1184 
1185    /* Only supporting the rounding-mode bits - the rest of FPSCR is
1186       0x0 - so we can set the whole register at once (faster). */
1187 
1188    // Resolve rounding mode and convert to PPC representation
1189    r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode, IEndianess) );
1190 
1191    // gpr -> fpr
1192    if (env->mode64) {
1193       if (dfp_rm) {
1194          HReg r_tmp1 = newVRegI( env );
1195          addInstr( env,
1196                    PPCInstr_Shft( Pshft_SHL, False/*64bit shift*/,
1197                                   r_tmp1, r_src, PPCRH_Imm( False, 32 ) ) );
1198          fr_src = mk_LoadR64toFPR( env, r_tmp1 );
1199       } else {
1200          fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64
1201       }
1202    } else {
1203       if (dfp_rm) {
1204          HReg r_zero = newVRegI( env );
1205          addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
1206          fr_src = mk_LoadRR32toFPR( env, r_src, r_zero );
1207       } else {
1208          fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
1209       }
1210    }
1211 
1212    // Move to FPSCR
1213    addInstr(env, PPCInstr_FpLdFPSCR( fr_src, dfp_rm ));
1214 }
1215 
set_FPU_rounding_mode(ISelEnv * env,IRExpr * mode,IREndness IEndianess)1216 static void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode,
1217                                     IREndness IEndianess )
1218 {
1219    _set_FPU_rounding_mode(env, mode, False, IEndianess);
1220 }
1221 
set_FPU_DFP_rounding_mode(ISelEnv * env,IRExpr * mode,IREndness IEndianess)1222 static void set_FPU_DFP_rounding_mode ( ISelEnv* env, IRExpr* mode,
1223                                         IREndness IEndianess )
1224 {
1225    _set_FPU_rounding_mode(env, mode, True, IEndianess);
1226 }
1227 
1228 
1229 /*---------------------------------------------------------*/
1230 /*--- ISEL: vector helpers                              ---*/
1231 /*---------------------------------------------------------*/
1232 
1233 /* Generate all-zeroes into a new vector register.
1234 */
generate_zeroes_V128(ISelEnv * env)1235 static HReg generate_zeroes_V128 ( ISelEnv* env )
1236 {
1237    HReg dst = newVRegV(env);
1238    addInstr(env, PPCInstr_AvBinary(Pav_XOR, dst, dst, dst));
1239    return dst;
1240 }
1241 
1242 /* Generate all-ones into a new vector register.
1243 */
generate_ones_V128(ISelEnv * env)1244 static HReg generate_ones_V128 ( ISelEnv* env )
1245 {
1246    HReg dst = newVRegV(env);
1247    PPCVI5s * src = PPCVI5s_Imm(-1);
1248    addInstr(env, PPCInstr_AvSplat(8, dst, src));
1249    return dst;
1250 }
1251 
1252 
1253 /*
1254   Generates code for AvSplat
1255   - takes in IRExpr* of type 8|16|32
1256     returns vector reg of duplicated lanes of input
1257   - uses AvSplat(imm) for imms up to simm6.
1258     otherwise must use store reg & load vector
1259 */
mk_AvDuplicateRI(ISelEnv * env,IRExpr * e,IREndness IEndianess)1260 static HReg mk_AvDuplicateRI( ISelEnv* env, IRExpr* e, IREndness IEndianess )
1261 {
1262    HReg   r_src;
1263    HReg   dst = newVRegV(env);
1264    PPCRI* ri  = iselWordExpr_RI(env, e, IEndianess);
1265    IRType ty  = typeOfIRExpr(env->type_env,e);
1266    UInt   sz  = (ty == Ity_I8) ? 8 : (ty == Ity_I16) ? 16 : 32;
1267    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1268 
1269    /* special case: immediate */
1270    if (ri->tag == Pri_Imm) {
1271       Int simm32 = (Int)ri->Pri.Imm;
1272 
1273       /* figure out if it's do-able with imm splats. */
1274       if (simm32 >= -32 && simm32 <= 31) {
1275          Char simm6 = (Char)simm32;
1276          if (simm6 > 15) {           /* 16:31 inclusive */
1277             HReg v1 = newVRegV(env);
1278             HReg v2 = newVRegV(env);
1279             addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1280             addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6-16)));
1281             addInstr(env,
1282                (sz== 8) ? PPCInstr_AvBin8x16(Pav_SUBU, dst, v2, v1) :
1283                (sz==16) ? PPCInstr_AvBin16x8(Pav_SUBU, dst, v2, v1)
1284                         : PPCInstr_AvBin32x4(Pav_SUBU, dst, v2, v1) );
1285             return dst;
1286          }
1287          if (simm6 < -16) {          /* -32:-17 inclusive */
1288             HReg v1 = newVRegV(env);
1289             HReg v2 = newVRegV(env);
1290             addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1291             addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6+16)));
1292             addInstr(env,
1293                (sz== 8) ? PPCInstr_AvBin8x16(Pav_ADDU, dst, v2, v1) :
1294                (sz==16) ? PPCInstr_AvBin16x8(Pav_ADDU, dst, v2, v1)
1295                         : PPCInstr_AvBin32x4(Pav_ADDU, dst, v2, v1) );
1296             return dst;
1297          }
1298          /* simplest form:              -16:15 inclusive */
1299          addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6)));
1300          return dst;
1301       }
1302 
1303       /* no luck; use the Slow way. */
1304       r_src = newVRegI(env);
1305       addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64));
1306    }
1307    else {
1308       r_src = ri->Pri.Reg;
1309    }
1310 
1311    {
1312       /* Store r_src multiple times (sz dependent); then load the dest vector. */
1313       HReg r_aligned16;
1314       PPCAMode *am_offset, *am_offset_zero;
1315 
1316       sub_from_sp( env, 32 );     // Move SP down
1317       /* Get a 16-aligned address within our stack space */
1318       r_aligned16 = get_sp_aligned16( env );
1319 
1320       Int i;
1321       Int stride = (sz == 8) ? 1 : (sz == 16) ? 2 : 4;
1322       UChar num_bytes_to_store = stride;
1323       am_offset_zero = PPCAMode_IR( 0, r_aligned16 );
1324       am_offset = am_offset_zero;
1325       for (i = 0; i < 16; i+=stride, am_offset = PPCAMode_IR( i, r_aligned16)) {
1326          addInstr(env, PPCInstr_Store( num_bytes_to_store, am_offset, r_src, env->mode64 ));
1327       }
1328 
1329       /* Effectively splat the r_src value to dst */
1330       addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 16, dst, am_offset_zero ) );
1331       add_to_sp( env, 32 );       // Reset SP
1332 
1333       return dst;
1334    }
1335 }
1336 
1337 
1338 /* for each lane of vSrc: lane == nan ? laneX = all 1's : all 0's */
isNan(ISelEnv * env,HReg vSrc,IREndness IEndianess)1339 static HReg isNan ( ISelEnv* env, HReg vSrc, IREndness IEndianess )
1340 {
1341    HReg zeros, msk_exp, msk_mnt, expt, mnts, vIsNan;
1342 
1343    vassert(hregClass(vSrc) == HRcVec128);
1344 
1345    zeros   = mk_AvDuplicateRI(env, mkU32(0), IEndianess);
1346    msk_exp = mk_AvDuplicateRI(env, mkU32(0x7F800000), IEndianess);
1347    msk_mnt = mk_AvDuplicateRI(env, mkU32(0x7FFFFF), IEndianess);
1348    expt    = newVRegV(env);
1349    mnts    = newVRegV(env);
1350    vIsNan  = newVRegV(env);
1351 
1352    /* 32bit float => sign(1) | exponent(8) | mantissa(23)
1353       nan => exponent all ones, mantissa > 0 */
1354 
1355    addInstr(env, PPCInstr_AvBinary(Pav_AND, expt, vSrc, msk_exp));
1356    addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, expt, expt, msk_exp));
1357    addInstr(env, PPCInstr_AvBinary(Pav_AND, mnts, vSrc, msk_mnt));
1358    addInstr(env, PPCInstr_AvBin32x4(Pav_CMPGTU, mnts, mnts, zeros));
1359    addInstr(env, PPCInstr_AvBinary(Pav_AND, vIsNan, expt, mnts));
1360    return vIsNan;
1361 }
1362 
1363 
1364 /*---------------------------------------------------------*/
1365 /*--- ISEL: Integer expressions (64/32/16/8 bit)        ---*/
1366 /*---------------------------------------------------------*/
1367 
1368 /* Select insns for an integer-typed expression, and add them to the
1369    code list.  Return a reg holding the result.  This reg will be a
1370    virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
1371    want to modify it, ask for a new vreg, copy it in there, and modify
1372    the copy.  The register allocator will do its best to map both
1373    vregs to the same real register, so the copies will often disappear
1374    later in the game.
1375 
1376    This should handle expressions of 64, 32, 16 and 8-bit type.
1377    All results are returned in a (mode64 ? 64bit : 32bit) register.
1378    For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1379    are arbitrary, so you should mask or sign extend partial values
1380    if necessary.
1381 */
1382 
iselWordExpr_R(ISelEnv * env,IRExpr * e,IREndness IEndianess)1383 static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
1384 {
1385    HReg r = iselWordExpr_R_wrk(env, e, IEndianess);
1386    /* sanity checks ... */
1387 #  if 0
1388    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1389 #  endif
1390 
1391    vassert(hregClass(r) == HRcGPR(env->mode64));
1392    vassert(hregIsVirtual(r));
1393    return r;
1394 }
1395 
1396 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_R_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)1397 static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e,
1398                                  IREndness IEndianess )
1399 {
1400    Bool mode64 = env->mode64;
1401    MatchInfo mi;
1402    DECLARE_PATTERN(p_32to1_then_1Uto8);
1403 
1404    IRType ty = typeOfIRExpr(env->type_env,e);
1405    vassert(ty == Ity_I8 || ty == Ity_I16 ||
1406            ty == Ity_I32 || ((ty == Ity_I64) && mode64));
1407 
1408    switch (e->tag) {
1409 
1410    /* --------- TEMP --------- */
1411    case Iex_RdTmp:
1412       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1413 
1414    /* --------- LOAD --------- */
1415    case Iex_Load: {
1416       HReg      r_dst;
1417       PPCAMode* am_addr;
1418       if (e->Iex.Load.end != IEndianess)
1419          goto irreducible;
1420       r_dst   = newVRegI(env);
1421       am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/,
1422                                     IEndianess );
1423       addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1424                                    r_dst, am_addr, mode64 ));
1425       return r_dst;
1426       /*NOTREACHED*/
1427    }
1428 
1429    /* --------- BINARY OP --------- */
1430    case Iex_Binop: {
1431       PPCAluOp  aluOp;
1432       PPCShftOp shftOp;
1433 
1434       /* Is it an addition or logical style op? */
1435       switch (e->Iex.Binop.op) {
1436       case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64:
1437          aluOp = Palu_ADD; break;
1438       case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64:
1439          aluOp = Palu_SUB; break;
1440       case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64:
1441          aluOp = Palu_AND; break;
1442       case Iop_Or8:  case Iop_Or16:  case Iop_Or32:  case Iop_Or64:
1443          aluOp = Palu_OR; break;
1444       case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: case Iop_Xor64:
1445          aluOp = Palu_XOR; break;
1446       default:
1447          aluOp = Palu_INVALID; break;
1448       }
1449       /* For commutative ops we assume any literal
1450          values are on the second operand. */
1451       if (aluOp != Palu_INVALID) {
1452          HReg   r_dst   = newVRegI(env);
1453          HReg   r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1454          PPCRH* ri_srcR = NULL;
1455          /* get right arg into an RH, in the appropriate way */
1456          switch (aluOp) {
1457          case Palu_ADD: case Palu_SUB:
1458             ri_srcR = iselWordExpr_RH(env, True/*signed*/,
1459                                       e->Iex.Binop.arg2, IEndianess);
1460             break;
1461          case Palu_AND: case Palu_OR: case Palu_XOR:
1462             ri_srcR = iselWordExpr_RH(env, False/*signed*/,
1463                                       e->Iex.Binop.arg2, IEndianess);
1464             break;
1465          default:
1466             vpanic("iselWordExpr_R_wrk-aluOp-arg2");
1467          }
1468          addInstr(env, PPCInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
1469          return r_dst;
1470       }
1471 
1472       /* a shift? */
1473       switch (e->Iex.Binop.op) {
1474       case Iop_Shl8: case Iop_Shl16: case Iop_Shl32: case Iop_Shl64:
1475          shftOp = Pshft_SHL; break;
1476       case Iop_Shr8: case Iop_Shr16: case Iop_Shr32: case Iop_Shr64:
1477          shftOp = Pshft_SHR; break;
1478       case Iop_Sar8: case Iop_Sar16: case Iop_Sar32: case Iop_Sar64:
1479          shftOp = Pshft_SAR; break;
1480       default:
1481          shftOp = Pshft_INVALID; break;
1482       }
1483       /* we assume any literal values are on the second operand. */
1484       if (shftOp != Pshft_INVALID) {
1485          HReg   r_dst   = newVRegI(env);
1486          HReg   r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1487          PPCRH* ri_srcR = NULL;
1488          /* get right arg into an RH, in the appropriate way */
1489          switch (shftOp) {
1490          case Pshft_SHL: case Pshft_SHR: case Pshft_SAR:
1491             if (!mode64)
1492                ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2, IEndianess);
1493             else
1494                ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2, IEndianess);
1495             break;
1496          default:
1497             vpanic("iselIntExpr_R_wrk-shftOp-arg2");
1498          }
1499          /* widen the left arg if needed */
1500          if (shftOp == Pshft_SHR || shftOp == Pshft_SAR) {
1501             if (ty == Ity_I8 || ty == Ity_I16) {
1502                PPCRH* amt = PPCRH_Imm(False,
1503                                       toUShort(ty == Ity_I8 ? 24 : 16));
1504                HReg   tmp = newVRegI(env);
1505                addInstr(env, PPCInstr_Shft(Pshft_SHL,
1506                                            True/*32bit shift*/,
1507                                            tmp, r_srcL, amt));
1508                addInstr(env, PPCInstr_Shft(shftOp,
1509                                            True/*32bit shift*/,
1510                                            tmp, tmp,    amt));
1511                r_srcL = tmp;
1512                vassert(0); /* AWAITING TEST CASE */
1513             }
1514          }
1515          /* Only 64 expressions need 64bit shifts,
1516             32bit shifts are fine for all others */
1517          if (ty == Ity_I64) {
1518             vassert(mode64);
1519             addInstr(env, PPCInstr_Shft(shftOp, False/*64bit shift*/,
1520                                         r_dst, r_srcL, ri_srcR));
1521          } else {
1522             addInstr(env, PPCInstr_Shft(shftOp, True/*32bit shift*/,
1523                                         r_dst, r_srcL, ri_srcR));
1524          }
1525          return r_dst;
1526       }
1527 
1528       /* How about a div? */
1529       if (e->Iex.Binop.op == Iop_DivS32 ||
1530           e->Iex.Binop.op == Iop_DivU32 ||
1531           e->Iex.Binop.op == Iop_DivS32E ||
1532           e->Iex.Binop.op == Iop_DivU32E) {
1533          Bool syned  = toBool((e->Iex.Binop.op == Iop_DivS32) || (e->Iex.Binop.op == Iop_DivS32E));
1534          HReg r_dst  = newVRegI(env);
1535          HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1536          HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1537          addInstr( env,
1538                       PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivU32E )
1539                                              || ( e->Iex.Binop.op == Iop_DivS32E ) ) ? True
1540                                                                                      : False,
1541                                     syned,
1542                                     True/*32bit div*/,
1543                                     r_dst,
1544                                     r_srcL,
1545                                     r_srcR ) );
1546          return r_dst;
1547       }
1548       if (e->Iex.Binop.op == Iop_DivS64 ||
1549           e->Iex.Binop.op == Iop_DivU64 || e->Iex.Binop.op == Iop_DivS64E
1550           || e->Iex.Binop.op == Iop_DivU64E ) {
1551          Bool syned  = toBool((e->Iex.Binop.op == Iop_DivS64) ||(e->Iex.Binop.op == Iop_DivS64E));
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          vassert(mode64);
1556          addInstr( env,
1557                       PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivS64E )
1558                                              || ( e->Iex.Binop.op
1559                                                       == Iop_DivU64E ) ) ? True
1560                                                                          : False,
1561                                     syned,
1562                                     False/*64bit div*/,
1563                                     r_dst,
1564                                     r_srcL,
1565                                     r_srcR ) );
1566          return r_dst;
1567       }
1568 
1569       /* No? Anyone for a mul? */
1570       if (e->Iex.Binop.op == Iop_Mul32
1571           || e->Iex.Binop.op == Iop_Mul64) {
1572          Bool syned       = False;
1573          Bool sz32        = (e->Iex.Binop.op != Iop_Mul64);
1574          HReg r_dst       = newVRegI(env);
1575          HReg r_srcL      = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1576          HReg r_srcR      = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1577          addInstr(env, PPCInstr_MulL(syned, False/*lo32*/, sz32,
1578                                      r_dst, r_srcL, r_srcR));
1579          return r_dst;
1580       }
1581 
1582       /* 32 x 32 -> 64 multiply */
1583       if (mode64
1584           && (e->Iex.Binop.op == Iop_MullU32
1585               || e->Iex.Binop.op == Iop_MullS32)) {
1586          HReg tLo    = newVRegI(env);
1587          HReg tHi    = newVRegI(env);
1588          HReg r_dst  = newVRegI(env);
1589          Bool syned  = toBool(e->Iex.Binop.op == Iop_MullS32);
1590          HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1591          HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1592          addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
1593                                      False/*lo32*/, True/*32bit mul*/,
1594                                      tLo, r_srcL, r_srcR));
1595          addInstr(env, PPCInstr_MulL(syned,
1596                                      True/*hi32*/, True/*32bit mul*/,
1597                                      tHi, r_srcL, r_srcR));
1598          addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1599                                      r_dst, tHi, PPCRH_Imm(False,32)));
1600          addInstr(env, PPCInstr_Alu(Palu_OR,
1601                                     r_dst, r_dst, PPCRH_Reg(tLo)));
1602          return r_dst;
1603       }
1604 
1605       /* El-mutanto 3-way compare? */
1606       if (e->Iex.Binop.op == Iop_CmpORD32S
1607           || e->Iex.Binop.op == Iop_CmpORD32U) {
1608          Bool   syned = toBool(e->Iex.Binop.op == Iop_CmpORD32S);
1609          HReg   dst   = newVRegI(env);
1610          HReg   srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1611          PPCRH* srcR  = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2,
1612                                         IEndianess);
1613          addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
1614                                     7/*cr*/, srcL, srcR));
1615          addInstr(env, PPCInstr_MfCR(dst));
1616          addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1617                                     PPCRH_Imm(False,7<<1)));
1618          return dst;
1619       }
1620 
1621       if (e->Iex.Binop.op == Iop_CmpORD64S
1622           || e->Iex.Binop.op == Iop_CmpORD64U) {
1623          Bool   syned = toBool(e->Iex.Binop.op == Iop_CmpORD64S);
1624          HReg   dst   = newVRegI(env);
1625          HReg   srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1626          PPCRH* srcR  = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2,
1627                                         IEndianess);
1628          vassert(mode64);
1629          addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
1630                                     7/*cr*/, srcL, srcR));
1631          addInstr(env, PPCInstr_MfCR(dst));
1632          addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1633                                     PPCRH_Imm(False,7<<1)));
1634          return dst;
1635       }
1636 
1637       if (e->Iex.Binop.op == Iop_Max32U) {
1638          HReg        r1   = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1639          HReg        r2   = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1640          HReg        rdst = newVRegI(env);
1641          PPCCondCode cc   = mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
1642          addInstr(env, mk_iMOVds_RR(rdst, r1));
1643          addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1644                                     7/*cr*/, rdst, PPCRH_Reg(r2)));
1645          addInstr(env, PPCInstr_CMov(cc, rdst, PPCRI_Reg(r2)));
1646          return rdst;
1647       }
1648 
1649       if (e->Iex.Binop.op == Iop_32HLto64) {
1650          HReg   r_Hi  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
1651          HReg   r_Lo  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
1652          HReg   r_Tmp = newVRegI(env);
1653          HReg   r_dst = newVRegI(env);
1654          HReg   msk   = newVRegI(env);
1655          vassert(mode64);
1656          /* r_dst = OR( r_Hi<<32, r_Lo ) */
1657          addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1658                                      r_dst, r_Hi, PPCRH_Imm(False,32)));
1659          addInstr(env, PPCInstr_LI(msk, 0xFFFFFFFF, mode64));
1660          addInstr(env, PPCInstr_Alu( Palu_AND, r_Tmp, r_Lo,
1661                                      PPCRH_Reg(msk) ));
1662          addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst,
1663                                      PPCRH_Reg(r_Tmp) ));
1664          return r_dst;
1665       }
1666 
1667       if ((e->Iex.Binop.op == Iop_CmpF64) ||
1668           (e->Iex.Binop.op == Iop_CmpD64) ||
1669           (e->Iex.Binop.op == Iop_CmpD128)) {
1670          HReg fr_srcL;
1671          HReg fr_srcL_lo;
1672          HReg fr_srcR;
1673          HReg fr_srcR_lo;
1674 
1675          HReg r_ccPPC   = newVRegI(env);
1676          HReg r_ccIR    = newVRegI(env);
1677          HReg r_ccIR_b0 = newVRegI(env);
1678          HReg r_ccIR_b2 = newVRegI(env);
1679          HReg r_ccIR_b6 = newVRegI(env);
1680 
1681          if (e->Iex.Binop.op == Iop_CmpF64) {
1682             fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
1683             fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
1684             addInstr(env, PPCInstr_FpCmp(r_ccPPC, fr_srcL, fr_srcR));
1685 
1686          } else if (e->Iex.Binop.op == Iop_CmpD64) {
1687             fr_srcL = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
1688             fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
1689             addInstr(env, PPCInstr_Dfp64Cmp(r_ccPPC, fr_srcL, fr_srcR));
1690 
1691          } else {    //  e->Iex.Binop.op == Iop_CmpD128
1692             iselDfp128Expr(&fr_srcL, &fr_srcL_lo, env, e->Iex.Binop.arg1,
1693                            IEndianess);
1694             iselDfp128Expr(&fr_srcR, &fr_srcR_lo, env, e->Iex.Binop.arg2,
1695                            IEndianess);
1696             addInstr(env, PPCInstr_Dfp128Cmp(r_ccPPC, fr_srcL, fr_srcL_lo,
1697                                              fr_srcR, fr_srcR_lo));
1698          }
1699 
1700          /* Map compare result from PPC to IR,
1701             conforming to CmpF64 definition. */
1702          /*
1703            FP cmp result | PPC | IR
1704            --------------------------
1705            UN            | 0x1 | 0x45
1706            EQ            | 0x2 | 0x40
1707            GT            | 0x4 | 0x00
1708            LT            | 0x8 | 0x01
1709          */
1710 
1711          // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1712          addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1713                                      r_ccIR_b0, r_ccPPC,
1714                                      PPCRH_Imm(False,0x3)));
1715          addInstr(env, PPCInstr_Alu(Palu_OR,  r_ccIR_b0,
1716                                     r_ccPPC,   PPCRH_Reg(r_ccIR_b0)));
1717          addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b0,
1718                                     r_ccIR_b0, PPCRH_Imm(False,0x1)));
1719 
1720          // r_ccIR_b2 = r_ccPPC[0]
1721          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1722                                      r_ccIR_b2, r_ccPPC,
1723                                      PPCRH_Imm(False,0x2)));
1724          addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b2,
1725                                     r_ccIR_b2, PPCRH_Imm(False,0x4)));
1726 
1727          // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
1728          addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1729                                      r_ccIR_b6, r_ccPPC,
1730                                      PPCRH_Imm(False,0x1)));
1731          addInstr(env, PPCInstr_Alu(Palu_OR,  r_ccIR_b6,
1732                                     r_ccPPC, PPCRH_Reg(r_ccIR_b6)));
1733          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1734                                      r_ccIR_b6, r_ccIR_b6,
1735                                      PPCRH_Imm(False,0x6)));
1736          addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b6,
1737                                     r_ccIR_b6, PPCRH_Imm(False,0x40)));
1738 
1739          // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
1740          addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1741                                     r_ccIR_b0, PPCRH_Reg(r_ccIR_b2)));
1742          addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1743                                     r_ccIR,    PPCRH_Reg(r_ccIR_b6)));
1744          return r_ccIR;
1745       }
1746 
1747       if ( e->Iex.Binop.op == Iop_F64toI32S ||
1748                e->Iex.Binop.op == Iop_F64toI32U ) {
1749          /* This works in both mode64 and mode32. */
1750          HReg      r1      = StackFramePtr(env->mode64);
1751          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1752          HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
1753          HReg      ftmp    = newVRegF(env);
1754          HReg      idst    = newVRegI(env);
1755 
1756          /* Set host rounding mode */
1757          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1758 
1759          sub_from_sp( env, 16 );
1760          addInstr(env, PPCInstr_FpCftI(False/*F->I*/, True/*int32*/,
1761                                        e->Iex.Binop.op == Iop_F64toI32S ? True/*syned*/
1762                                                                      : False,
1763                                        True/*flt64*/,
1764                                        ftmp, fsrc));
1765          addInstr(env, PPCInstr_FpSTFIW(r1, ftmp));
1766          addInstr(env, PPCInstr_Load(4, idst, zero_r1, mode64));
1767 
1768          /* in 64-bit mode we need to sign-widen idst. */
1769          if (mode64)
1770             addInstr(env, PPCInstr_Unary(Pun_EXTSW, idst, idst));
1771 
1772          add_to_sp( env, 16 );
1773 
1774          ///* Restore default FPU rounding. */
1775          //set_FPU_rounding_default( env );
1776          return idst;
1777       }
1778 
1779       if (e->Iex.Binop.op == Iop_F64toI64S || e->Iex.Binop.op == Iop_F64toI64U ) {
1780          if (mode64) {
1781             HReg      r1      = StackFramePtr(env->mode64);
1782             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1783             HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2,
1784                                             IEndianess);
1785             HReg      idst    = newVRegI(env);
1786             HReg      ftmp    = newVRegF(env);
1787 
1788             /* Set host rounding mode */
1789             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1790 
1791             sub_from_sp( env, 16 );
1792             addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
1793                                           ( e->Iex.Binop.op == Iop_F64toI64S ) ? True
1794                                                                             : False,
1795                                           True, ftmp, fsrc));
1796             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1797             addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1798             add_to_sp( env, 16 );
1799 
1800             ///* Restore default FPU rounding. */
1801             //set_FPU_rounding_default( env );
1802             return idst;
1803          }
1804       }
1805 
1806       if (e->Iex.Binop.op == Iop_D64toI64S ) {
1807          HReg      r1      = StackFramePtr(env->mode64);
1808          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1809          HReg      fr_src  = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
1810          HReg      idst    = newVRegI(env);
1811          HReg      ftmp    = newVRegF(env);
1812 
1813          /* Set host rounding mode */
1814          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1815          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, ftmp, fr_src));
1816          sub_from_sp( env, 16 );
1817          addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1818          addInstr(env, PPCInstr_Load(8, idst, zero_r1, mode64));
1819 
1820          add_to_sp( env, 16 );
1821 
1822          ///* Restore default FPU rounding. */
1823          //set_FPU_rounding_default( env );
1824          return idst;
1825       }
1826 
1827       if (e->Iex.Binop.op == Iop_D128toI64S ) {
1828          PPCFpOp fpop = Pfp_DCTFIXQ;
1829          HReg r_srcHi = newVRegF(env);
1830          HReg r_srcLo = newVRegF(env);
1831          HReg idst    = newVRegI(env);
1832          HReg ftmp    = newVRegF(env);
1833          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
1834 
1835          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
1836          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
1837                         IEndianess);
1838          addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
1839 
1840          // put the D64 result into an integer register
1841          sub_from_sp( env, 16 );
1842          addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1843          addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1844          add_to_sp( env, 16 );
1845          return idst;
1846       }
1847       break;
1848    }
1849 
1850    /* --------- UNARY OP --------- */
1851    case Iex_Unop: {
1852       IROp op_unop = e->Iex.Unop.op;
1853 
1854       /* 1Uto8(32to1(expr32)) */
1855       DEFINE_PATTERN(p_32to1_then_1Uto8,
1856                      unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1857       if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1858          IRExpr* expr32 = mi.bindee[0];
1859          HReg r_dst = newVRegI(env);
1860          HReg r_src = iselWordExpr_R(env, expr32, IEndianess);
1861          addInstr(env, PPCInstr_Alu(Palu_AND, r_dst,
1862                                     r_src, PPCRH_Imm(False,1)));
1863          return r_dst;
1864       }
1865 
1866       /* 16Uto32(LDbe:I16(expr32)) */
1867       {
1868          DECLARE_PATTERN(p_LDbe16_then_16Uto32);
1869          DEFINE_PATTERN(p_LDbe16_then_16Uto32,
1870                         unop(Iop_16Uto32,
1871                              IRExpr_Load(IEndianess,Ity_I16,bind(0))) );
1872          if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
1873             HReg r_dst = newVRegI(env);
1874             PPCAMode* amode
1875                = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/,
1876                                      IEndianess );
1877             addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
1878             return r_dst;
1879          }
1880       }
1881 
1882       switch (op_unop) {
1883       case Iop_8Uto16:
1884       case Iop_8Uto32:
1885       case Iop_8Uto64:
1886       case Iop_16Uto32:
1887       case Iop_16Uto64: {
1888          HReg   r_dst = newVRegI(env);
1889          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1890          UShort mask  = toUShort(op_unop==Iop_16Uto64 ? 0xFFFF :
1891                                  op_unop==Iop_16Uto32 ? 0xFFFF : 0xFF);
1892          addInstr(env, PPCInstr_Alu(Palu_AND,r_dst,r_src,
1893                                     PPCRH_Imm(False,mask)));
1894          return r_dst;
1895       }
1896       case Iop_32Uto64: {
1897          HReg r_dst = newVRegI(env);
1898          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1899          vassert(mode64);
1900          addInstr(env,
1901                   PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1902                                 r_dst, r_src, PPCRH_Imm(False,32)));
1903          addInstr(env,
1904                   PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1905                                 r_dst, r_dst, PPCRH_Imm(False,32)));
1906          return r_dst;
1907       }
1908       case Iop_8Sto16:
1909       case Iop_8Sto32:
1910       case Iop_16Sto32: {
1911          HReg   r_dst = newVRegI(env);
1912          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1913          UShort amt   = toUShort(op_unop==Iop_16Sto32 ? 16 : 24);
1914          addInstr(env,
1915                   PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1916                                 r_dst, r_src, PPCRH_Imm(False,amt)));
1917          addInstr(env,
1918                   PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1919                                 r_dst, r_dst, PPCRH_Imm(False,amt)));
1920          return r_dst;
1921       }
1922       case Iop_8Sto64:
1923       case Iop_16Sto64: {
1924          HReg   r_dst = newVRegI(env);
1925          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1926          UShort amt   = toUShort(op_unop==Iop_8Sto64  ? 56 : 48);
1927          vassert(mode64);
1928          addInstr(env,
1929                   PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1930                                 r_dst, r_src, PPCRH_Imm(False,amt)));
1931          addInstr(env,
1932                   PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1933                                 r_dst, r_dst, PPCRH_Imm(False,amt)));
1934          return r_dst;
1935       }
1936       case Iop_32Sto64: {
1937          HReg   r_dst = newVRegI(env);
1938          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1939 	 vassert(mode64);
1940          /* According to the IBM docs, in 64 bit mode, srawi r,r,0
1941             sign extends the lower 32 bits into the upper 32 bits. */
1942          addInstr(env,
1943                   PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1944                                 r_dst, r_src, PPCRH_Imm(False,0)));
1945          return r_dst;
1946       }
1947       case Iop_Not8:
1948       case Iop_Not16:
1949       case Iop_Not32:
1950       case Iop_Not64: {
1951          if (op_unop == Iop_Not64) vassert(mode64);
1952          HReg r_dst = newVRegI(env);
1953          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1954          addInstr(env, PPCInstr_Unary(Pun_NOT,r_dst,r_src));
1955          return r_dst;
1956       }
1957       case Iop_64HIto32: {
1958          if (!mode64) {
1959             HReg rHi, rLo;
1960             iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
1961             return rHi; /* and abandon rLo .. poor wee thing :-) */
1962          } else {
1963             HReg   r_dst = newVRegI(env);
1964             HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1965             addInstr(env,
1966                      PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1967                                    r_dst, r_src, PPCRH_Imm(False,32)));
1968             return r_dst;
1969          }
1970       }
1971       case Iop_64to32: {
1972          if (!mode64) {
1973             HReg rHi, rLo;
1974             iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
1975             return rLo; /* similar stupid comment to the above ... */
1976          } else {
1977             /* This is a no-op. */
1978             return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1979          }
1980       }
1981       case Iop_64to16: {
1982          if (mode64) { /* This is a no-op. */
1983             return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1984          }
1985          break; /* evidently not used in 32-bit mode */
1986       }
1987       case Iop_16HIto8:
1988       case Iop_32HIto16: {
1989          HReg   r_dst = newVRegI(env);
1990          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
1991          UShort shift = toUShort(op_unop == Iop_16HIto8 ? 8 : 16);
1992          addInstr(env,
1993                   PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1994                                 r_dst, r_src, PPCRH_Imm(False,shift)));
1995          return r_dst;
1996       }
1997       case Iop_128HIto64:
1998          if (mode64) {
1999             HReg rHi, rLo;
2000             iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
2001             return rHi; /* and abandon rLo .. poor wee thing :-) */
2002          }
2003          break;
2004       case Iop_128to64:
2005          if (mode64) {
2006             HReg rHi, rLo;
2007             iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg, IEndianess);
2008             return rLo; /* similar stupid comment to the above ... */
2009          }
2010          break;
2011       case Iop_1Uto64:
2012       case Iop_1Uto32:
2013       case Iop_1Uto8:
2014          if ((op_unop != Iop_1Uto64) || mode64) {
2015             HReg        r_dst = newVRegI(env);
2016             PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2017             addInstr(env, PPCInstr_Set(cond,r_dst));
2018             return r_dst;
2019          }
2020          break;
2021       case Iop_1Sto8:
2022       case Iop_1Sto16:
2023       case Iop_1Sto32: {
2024          /* could do better than this, but for now ... */
2025          HReg        r_dst = newVRegI(env);
2026          PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2027          addInstr(env, PPCInstr_Set(cond,r_dst));
2028          addInstr(env,
2029                   PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
2030                                 r_dst, r_dst, PPCRH_Imm(False,31)));
2031          addInstr(env,
2032                   PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2033                                 r_dst, r_dst, PPCRH_Imm(False,31)));
2034          return r_dst;
2035       }
2036       case Iop_1Sto64:
2037          if (mode64) {
2038             /* could do better than this, but for now ... */
2039             HReg        r_dst = newVRegI(env);
2040             PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2041             addInstr(env, PPCInstr_Set(cond,r_dst));
2042             addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
2043                                         r_dst, r_dst, PPCRH_Imm(False,63)));
2044             addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
2045                                         r_dst, r_dst, PPCRH_Imm(False,63)));
2046             return r_dst;
2047          }
2048          break;
2049       case Iop_Clz32:
2050       case Iop_Clz64: {
2051          HReg r_src, r_dst;
2052          PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 :
2053                                                       Pun_CLZ64;
2054          if (op_unop == Iop_Clz64 && !mode64)
2055             goto irreducible;
2056          /* Count leading zeroes. */
2057          r_dst = newVRegI(env);
2058          r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2059          addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
2060          return r_dst;
2061       }
2062 
2063       case Iop_Left8:
2064       case Iop_Left16:
2065       case Iop_Left32:
2066       case Iop_Left64: {
2067          HReg r_src, r_dst;
2068          if (op_unop == Iop_Left64 && !mode64)
2069             goto irreducible;
2070          r_dst = newVRegI(env);
2071          r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2072          addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2073          addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2074          return r_dst;
2075       }
2076 
2077       case Iop_CmpwNEZ32: {
2078          HReg r_dst = newVRegI(env);
2079          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2080          addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2081          addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2082          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2083                                      r_dst, r_dst, PPCRH_Imm(False, 31)));
2084          return r_dst;
2085       }
2086 
2087       case Iop_CmpwNEZ64: {
2088          HReg r_dst = newVRegI(env);
2089          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2090          if (!mode64) goto irreducible;
2091          addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
2092          addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
2093          addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
2094                                      r_dst, r_dst, PPCRH_Imm(False, 63)));
2095          return r_dst;
2096       }
2097 
2098       case Iop_V128to32: {
2099          HReg        r_aligned16;
2100          HReg        dst  = newVRegI(env);
2101          HReg        vec  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2102          PPCAMode *am_off0, *am_off_word0;
2103          sub_from_sp( env, 32 );     // Move SP down 32 bytes
2104 
2105          // get a quadword aligned address within our stack space
2106          r_aligned16 = get_sp_aligned16( env );
2107          am_off0  = PPCAMode_IR( 0, r_aligned16 );
2108 
2109          /* Note that the store below (done via PPCInstr_AvLdSt) uses
2110           * stvx, which stores the vector in proper LE format,
2111           * with byte zero (far right byte of the register in LE format)
2112           * stored at the lowest memory address.  Therefore, to obtain
2113           * integer word zero, we need to use that lowest memory address
2114           * as the base for the load.
2115           */
2116          if (IEndianess == Iend_LE)
2117             am_off_word0 = am_off0;
2118          else
2119             am_off_word0 = PPCAMode_IR( 12,r_aligned16 );
2120 
2121          // store vec, load low word to dst
2122          addInstr(env,
2123                   PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2124          addInstr(env,
2125                   PPCInstr_Load( 4, dst, am_off_word0, mode64 ));
2126 
2127          add_to_sp( env, 32 );       // Reset SP
2128          return dst;
2129       }
2130 
2131       case Iop_V128to64:
2132       case Iop_V128HIto64:
2133          if (mode64) {
2134             HReg     r_aligned16;
2135             HReg     dst = newVRegI(env);
2136             HReg     vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
2137             PPCAMode *am_off0, *am_off8, *am_off_arg;
2138             sub_from_sp( env, 32 );     // Move SP down 32 bytes
2139 
2140             // get a quadword aligned address within our stack space
2141             r_aligned16 = get_sp_aligned16( env );
2142             am_off0 = PPCAMode_IR( 0, r_aligned16 );
2143             am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
2144 
2145             // store vec, load low word or high to dst
2146             addInstr(env,
2147                      PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2148             if (IEndianess == Iend_LE) {
2149                if (op_unop == Iop_V128HIto64)
2150                   am_off_arg = am_off8;
2151                else
2152                   am_off_arg = am_off0;
2153             } else {
2154                if (op_unop == Iop_V128HIto64)
2155                   am_off_arg = am_off0;
2156                else
2157                   am_off_arg = am_off8;
2158             }
2159             addInstr(env,
2160                      PPCInstr_Load(
2161                         8, dst,
2162                         am_off_arg,
2163                         mode64 ));
2164 
2165             add_to_sp( env, 32 );       // Reset SP
2166             return dst;
2167          }
2168          break;
2169       case Iop_16to8:
2170       case Iop_32to8:
2171       case Iop_32to16:
2172       case Iop_64to8:
2173          /* These are no-ops. */
2174          return iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2175 
2176       /* ReinterpF64asI64(e) */
2177       /* Given an IEEE754 double, produce an I64 with the same bit
2178          pattern. */
2179       case Iop_ReinterpF64asI64:
2180          if (mode64) {
2181             PPCAMode *am_addr;
2182             HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
2183             HReg r_dst  = newVRegI(env);
2184 
2185             sub_from_sp( env, 16 );     // Move SP down 16 bytes
2186             am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2187 
2188             // store as F64
2189             addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2190                                            fr_src, am_addr ));
2191             // load as Ity_I64
2192             addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2193 
2194             add_to_sp( env, 16 );       // Reset SP
2195             return r_dst;
2196          }
2197          break;
2198 
2199       /* ReinterpF32asI32(e) */
2200       /* Given an IEEE754 float, produce an I32 with the same bit
2201          pattern. */
2202       case Iop_ReinterpF32asI32: {
2203          /* I believe this generates correct code for both 32- and
2204             64-bit hosts. */
2205          PPCAMode *am_addr;
2206          HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
2207          HReg r_dst  = newVRegI(env);
2208 
2209          sub_from_sp( env, 16 );     // Move SP down 16 bytes
2210          am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2211 
2212          // store as F32
2213          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
2214                                         fr_src, am_addr ));
2215          // load as Ity_I32
2216          addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
2217 
2218          add_to_sp( env, 16 );       // Reset SP
2219          return r_dst;
2220       }
2221       break;
2222 
2223       case Iop_ReinterpD64asI64:
2224          if (mode64) {
2225             PPCAMode *am_addr;
2226             HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
2227             HReg r_dst  = newVRegI(env);
2228 
2229             sub_from_sp( env, 16 );     // Move SP down 16 bytes
2230             am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
2231 
2232             // store as D64
2233             addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2234                                            fr_src, am_addr ));
2235             // load as Ity_I64
2236             addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
2237             add_to_sp( env, 16 );       // Reset SP
2238             return r_dst;
2239          }
2240          break;
2241 
2242       case Iop_BCDtoDPB: {
2243          /* the following is only valid in 64 bit mode */
2244          if (!mode64) break;
2245 
2246          PPCCondCode cc;
2247          UInt        argiregs;
2248          HReg        argregs[1];
2249          HReg        r_dst  = newVRegI(env);
2250          Int         argreg;
2251 
2252          argiregs = 0;
2253          argreg = 0;
2254          argregs[0] = hregPPC_GPR3(mode64);
2255 
2256          argiregs |= (1 << (argreg+3));
2257          addInstr(env, mk_iMOVds_RR( argregs[argreg++],
2258                                      iselWordExpr_R(env, e->Iex.Unop.arg,
2259                                                     IEndianess) ) );
2260 
2261          cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2262          if (IEndianess == Iend_LE) {
2263              addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
2264                                           argiregs,
2265                                           mk_RetLoc_simple(RLPri_Int)) );
2266          } else {
2267              HWord*      fdescr;
2268              fdescr = (HWord*)h_calc_BCDtoDPB;
2269              addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2270                                           argiregs,
2271                                           mk_RetLoc_simple(RLPri_Int)) );
2272          }
2273 
2274          addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2275          return r_dst;
2276       }
2277 
2278       case Iop_DPBtoBCD: {
2279          /* the following is only valid in 64 bit mode */
2280          if (!mode64) break;
2281 
2282          PPCCondCode cc;
2283          UInt        argiregs;
2284          HReg        argregs[1];
2285          HReg        r_dst  = newVRegI(env);
2286          Int         argreg;
2287 
2288          argiregs = 0;
2289          argreg = 0;
2290          argregs[0] = hregPPC_GPR3(mode64);
2291 
2292          argiregs |= (1 << (argreg+3));
2293          addInstr(env, mk_iMOVds_RR( argregs[argreg++],
2294                                      iselWordExpr_R(env, e->Iex.Unop.arg,
2295                                                     IEndianess) ) );
2296 
2297          cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
2298 
2299         if (IEndianess == Iend_LE) {
2300             addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
2301                                          argiregs,
2302                                          mk_RetLoc_simple(RLPri_Int) ) );
2303 	} else {
2304             HWord*      fdescr;
2305             fdescr = (HWord*)h_calc_DPBtoBCD;
2306             addInstr(env, PPCInstr_Call( cc, (Addr64)(fdescr[0]),
2307                                          argiregs,
2308                                          mk_RetLoc_simple(RLPri_Int) ) );
2309          }
2310 
2311          addInstr(env, mk_iMOVds_RR(r_dst, argregs[0]));
2312          return r_dst;
2313       }
2314 
2315       default:
2316          break;
2317       }
2318 
2319      switch (e->Iex.Unop.op) {
2320         case Iop_ExtractExpD64: {
2321 
2322             HReg fr_dst = newVRegI(env);
2323             HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
2324             HReg tmp    = newVRegF(env);
2325             PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
2326             addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
2327 
2328             // put the D64 result into a integer register
2329             sub_from_sp( env, 16 );
2330             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
2331             addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
2332             add_to_sp( env, 16 );
2333             return fr_dst;
2334          }
2335          case Iop_ExtractExpD128: {
2336             HReg fr_dst = newVRegI(env);
2337             HReg r_srcHi;
2338             HReg r_srcLo;
2339             HReg tmp    = newVRegF(env);
2340             PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
2341 
2342             iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
2343                            IEndianess);
2344             addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
2345                                                   r_srcHi, r_srcLo));
2346 
2347             sub_from_sp( env, 16 );
2348             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
2349             addInstr(env, PPCInstr_Load(8, fr_dst, zero_r1, env->mode64));
2350             add_to_sp( env, 16 );
2351             return fr_dst;
2352          }
2353          default:
2354             break;
2355       }
2356 
2357       break;
2358    }
2359 
2360    /* --------- GET --------- */
2361    case Iex_Get: {
2362       if (ty == Ity_I8  || ty == Ity_I16 ||
2363           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
2364          HReg r_dst = newVRegI(env);
2365          PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2366                                           GuestStatePtr(mode64) );
2367          addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
2368                                       r_dst, am_addr, mode64 ));
2369          return r_dst;
2370       }
2371       break;
2372    }
2373 
2374    case Iex_GetI: {
2375       PPCAMode* src_am
2376          = genGuestArrayOffset( env, e->Iex.GetI.descr,
2377                                 e->Iex.GetI.ix, e->Iex.GetI.bias,
2378                                 IEndianess );
2379       HReg r_dst = newVRegI(env);
2380       if (mode64 && ty == Ity_I64) {
2381          addInstr(env, PPCInstr_Load( toUChar(8),
2382                                       r_dst, src_am, mode64 ));
2383          return r_dst;
2384       }
2385       if ((!mode64) && ty == Ity_I32) {
2386          addInstr(env, PPCInstr_Load( toUChar(4),
2387                                       r_dst, src_am, mode64 ));
2388          return r_dst;
2389       }
2390       break;
2391    }
2392 
2393    /* --------- CCALL --------- */
2394    case Iex_CCall: {
2395       vassert(ty == e->Iex.CCall.retty); /* well-formedness of IR */
2396 
2397       /* be very restrictive for now.  Only 32/64-bit ints allowed for
2398          args, and 32 bits or host machine word for return type. */
2399       if (!(ty == Ity_I32 || (mode64 && ty == Ity_I64)))
2400          goto irreducible;
2401 
2402       /* Marshal args, do the call, clear stack. */
2403       UInt   addToSp = 0;
2404       RetLoc rloc    = mk_RetLoc_INVALID();
2405       doHelperCall( &addToSp, &rloc, env, NULL/*guard*/,
2406                     e->Iex.CCall.cee, e->Iex.CCall.retty, e->Iex.CCall.args,
2407                     IEndianess );
2408       vassert(is_sane_RetLoc(rloc));
2409       vassert(rloc.pri == RLPri_Int);
2410       vassert(addToSp == 0);
2411 
2412       /* GPR3 now holds the destination address from Pin_Goto */
2413       HReg r_dst = newVRegI(env);
2414       addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
2415       return r_dst;
2416    }
2417 
2418    /* --------- LITERAL --------- */
2419    /* 32/16/8-bit literals */
2420    case Iex_Const: {
2421       Long l;
2422       HReg r_dst = newVRegI(env);
2423       IRConst* con = e->Iex.Const.con;
2424       switch (con->tag) {
2425          case Ico_U64: if (!mode64) goto irreducible;
2426                        l = (Long)            con->Ico.U64; break;
2427          case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
2428          case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2429          case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
2430          default:      vpanic("iselIntExpr_R.const(ppc)");
2431       }
2432       addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64));
2433       return r_dst;
2434    }
2435 
2436    /* --------- MULTIPLEX --------- */
2437    case Iex_ITE: { // VFD
2438       if ((ty == Ity_I8  || ty == Ity_I16 ||
2439            ty == Ity_I32 || ((ty == Ity_I64) && mode64)) &&
2440           typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
2441          PPCRI* r1    = iselWordExpr_RI(env, e->Iex.ITE.iftrue, IEndianess);
2442          HReg   r0    = iselWordExpr_R(env, e->Iex.ITE.iffalse, IEndianess);
2443          HReg   r_dst = newVRegI(env);
2444          addInstr(env, mk_iMOVds_RR(r_dst,r0));
2445          PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
2446          addInstr(env, PPCInstr_CMov(cc, r_dst, r1));
2447          return r_dst;
2448       }
2449       break;
2450    }
2451 
2452    default:
2453       break;
2454    } /* switch (e->tag) */
2455 
2456 
2457    /* We get here if no pattern matched. */
2458  irreducible:
2459    ppIRExpr(e);
2460    vpanic("iselIntExpr_R(ppc): cannot reduce tree");
2461 }
2462 
2463 
2464 /*---------------------------------------------------------*/
2465 /*--- ISEL: Integer expression auxiliaries              ---*/
2466 /*---------------------------------------------------------*/
2467 
2468 /* --------------------- AMODEs --------------------- */
2469 
2470 /* Return an AMode which computes the value of the specified
2471    expression, possibly also adding insns to the code list as a
2472    result.  The expression may only be a word-size one.
2473 */
2474 
uInt_fits_in_16_bits(UInt u)2475 static Bool uInt_fits_in_16_bits ( UInt u )
2476 {
2477    /* Is u the same as the sign-extend of its lower 16 bits? */
2478    Int i = u & 0xFFFF;
2479    i <<= 16;
2480    i >>= 16;
2481    return toBool(u == (UInt)i);
2482 }
2483 
uLong_fits_in_16_bits(ULong u)2484 static Bool uLong_fits_in_16_bits ( ULong u )
2485 {
2486    /* Is u the same as the sign-extend of its lower 16 bits? */
2487    Long i = u & 0xFFFFULL;
2488    i <<= 48;
2489    i >>= 48;
2490    return toBool(u == (ULong)i);
2491 }
2492 
uLong_is_4_aligned(ULong u)2493 static Bool uLong_is_4_aligned ( ULong u )
2494 {
2495    return toBool((u & 3ULL) == 0);
2496 }
2497 
sane_AMode(ISelEnv * env,PPCAMode * am)2498 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2499 {
2500    Bool mode64 = env->mode64;
2501    switch (am->tag) {
2502    case Pam_IR:
2503       /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2504          somehow, but I think it's OK. */
2505       return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2506                      hregIsVirtual(am->Pam.IR.base) &&
2507                      uInt_fits_in_16_bits(am->Pam.IR.index) );
2508    case Pam_RR:
2509       return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2510                      hregIsVirtual(am->Pam.RR.base) &&
2511                      hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2512                      hregIsVirtual(am->Pam.RR.index) );
2513    default:
2514       vpanic("sane_AMode: unknown ppc amode tag");
2515    }
2516 }
2517 
2518 static
iselWordExpr_AMode(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2519 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy,
2520                                IREndness IEndianess )
2521 {
2522    PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy, IEndianess);
2523    vassert(sane_AMode(env, am));
2524    return am;
2525 }
2526 
2527 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_AMode_wrk(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2528 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e,
2529                                           IRType xferTy, IREndness IEndianess )
2530 {
2531    IRType ty = typeOfIRExpr(env->type_env,e);
2532 
2533    if (env->mode64) {
2534 
2535       /* If the data load/store type is I32 or I64, this amode might
2536          be destined for use in ld/ldu/lwa/st/stu.  In which case
2537          insist that if it comes out as an _IR, the immediate must
2538          have its bottom two bits be zero.  This does assume that for
2539          any other type (I8/I16/I128/F32/F64/V128) the amode will not
2540          be parked in any such instruction.  But that seems a
2541          reasonable assumption.  */
2542       Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2543 
2544       vassert(ty == Ity_I64);
2545 
2546       /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2547       if (e->tag == Iex_Binop
2548           && e->Iex.Binop.op == Iop_Add64
2549           && e->Iex.Binop.arg2->tag == Iex_Const
2550           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2551           && (aligned4imm  ? uLong_is_4_aligned(e->Iex.Binop.arg2
2552                                                  ->Iex.Const.con->Ico.U64)
2553                            : True)
2554           && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2555                                     ->Iex.Const.con->Ico.U64)) {
2556          return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2557                              iselWordExpr_R(env, e->Iex.Binop.arg1,
2558                                             IEndianess) );
2559       }
2560 
2561       /* Add64(expr,expr) */
2562       if (e->tag == Iex_Binop
2563           && e->Iex.Binop.op == Iop_Add64) {
2564          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2565          HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2566          return PPCAMode_RR( r_idx, r_base );
2567       }
2568 
2569    } else {
2570 
2571       vassert(ty == Ity_I32);
2572 
2573       /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2574       if (e->tag == Iex_Binop
2575           && e->Iex.Binop.op == Iop_Add32
2576           && e->Iex.Binop.arg2->tag == Iex_Const
2577           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2578           && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2579                                    ->Iex.Const.con->Ico.U32)) {
2580          return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2581                              iselWordExpr_R(env, e->Iex.Binop.arg1,
2582                                             IEndianess) );
2583       }
2584 
2585       /* Add32(expr,expr) */
2586       if (e->tag == Iex_Binop
2587           && e->Iex.Binop.op == Iop_Add32) {
2588          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2589          HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2590          return PPCAMode_RR( r_idx, r_base );
2591       }
2592 
2593    }
2594 
2595    /* Doesn't match anything in particular.  Generate it into
2596       a register and use that. */
2597    return PPCAMode_IR( 0, iselWordExpr_R(env,e,IEndianess) );
2598 }
2599 
2600 
2601 /* --------------------- RH --------------------- */
2602 
2603 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2604    (reg-or-halfword-immediate).  It's important to specify whether the
2605    immediate is to be regarded as signed or not.  If yes, this will
2606    never return -32768 as an immediate; this guaranteed that all
2607    signed immediates that are return can have their sign inverted if
2608    need be. */
2609 
iselWordExpr_RH(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2610 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e,
2611                                 IREndness IEndianess )
2612 {
2613   PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e, IEndianess);
2614    /* sanity checks ... */
2615    switch (ri->tag) {
2616    case Prh_Imm:
2617       vassert(ri->Prh.Imm.syned == syned);
2618       if (syned)
2619          vassert(ri->Prh.Imm.imm16 != 0x8000);
2620       return ri;
2621    case Prh_Reg:
2622       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2623       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2624       return ri;
2625    default:
2626       vpanic("iselIntExpr_RH: unknown ppc RH tag");
2627    }
2628 }
2629 
2630 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH_wrk(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2631 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e,
2632                                     IREndness IEndianess )
2633 {
2634    ULong u;
2635    Long  l;
2636    IRType ty = typeOfIRExpr(env->type_env,e);
2637    vassert(ty == Ity_I8  || ty == Ity_I16 ||
2638            ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2639 
2640    /* special case: immediate */
2641    if (e->tag == Iex_Const) {
2642       IRConst* con = e->Iex.Const.con;
2643       /* What value are we aiming to generate? */
2644       switch (con->tag) {
2645       /* Note: Not sign-extending - we carry 'syned' around */
2646       case Ico_U64: vassert(env->mode64);
2647                     u =              con->Ico.U64; break;
2648       case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2649       case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2650       case Ico_U8:  u = 0x000000FF & con->Ico.U8; break;
2651       default:      vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2652       }
2653       l = (Long)u;
2654       /* Now figure out if it's representable. */
2655       if (!syned && u <= 65535) {
2656          return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2657       }
2658       if (syned && l >= -32767 && l <= 32767) {
2659          return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2660       }
2661       /* no luck; use the Slow Way. */
2662    }
2663 
2664    /* default case: calculate into a register and return that */
2665    return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2666 }
2667 
2668 
2669 /* --------------------- RIs --------------------- */
2670 
2671 /* Calculate an expression into an PPCRI operand.  As with
2672    iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2673    in 64-bit mode, 64 bits. */
2674 
iselWordExpr_RI(ISelEnv * env,IRExpr * e,IREndness IEndianess)2675 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
2676 {
2677    PPCRI* ri = iselWordExpr_RI_wrk(env, e, IEndianess);
2678    /* sanity checks ... */
2679    switch (ri->tag) {
2680    case Pri_Imm:
2681       return ri;
2682    case Pri_Reg:
2683       vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2684       vassert(hregIsVirtual(ri->Pri.Reg));
2685       return ri;
2686    default:
2687       vpanic("iselIntExpr_RI: unknown ppc RI tag");
2688    }
2689 }
2690 
2691 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RI_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2692 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e,
2693                                     IREndness IEndianess )
2694 {
2695    Long  l;
2696    IRType ty = typeOfIRExpr(env->type_env,e);
2697    vassert(ty == Ity_I8  || ty == Ity_I16 ||
2698            ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2699 
2700    /* special case: immediate */
2701    if (e->tag == Iex_Const) {
2702       IRConst* con = e->Iex.Const.con;
2703       switch (con->tag) {
2704       case Ico_U64: vassert(env->mode64);
2705                     l = (Long)            con->Ico.U64; break;
2706       case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
2707       case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2708       case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
2709       default:      vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2710       }
2711       return PPCRI_Imm((ULong)l);
2712    }
2713 
2714    /* default case: calculate into a register and return that */
2715    return PPCRI_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2716 }
2717 
2718 
2719 /* --------------------- RH5u --------------------- */
2720 
2721 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2722    being an immediate in the range 1 .. 31 inclusive.  Used for doing
2723    shift amounts.  Only used in 32-bit mode. */
2724 
iselWordExpr_RH5u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2725 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e,
2726                                   IREndness IEndianess )
2727 {
2728    PPCRH* ri;
2729    vassert(!env->mode64);
2730    ri = iselWordExpr_RH5u_wrk(env, e, IEndianess);
2731    /* sanity checks ... */
2732    switch (ri->tag) {
2733    case Prh_Imm:
2734       vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2735       vassert(!ri->Prh.Imm.syned);
2736       return ri;
2737    case Prh_Reg:
2738       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2739       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2740       return ri;
2741    default:
2742       vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2743    }
2744 }
2745 
2746 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH5u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2747 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e,
2748                                       IREndness IEndianess )
2749 {
2750    IRType ty = typeOfIRExpr(env->type_env,e);
2751    vassert(ty == Ity_I8);
2752 
2753    /* special case: immediate */
2754    if (e->tag == Iex_Const
2755        && e->Iex.Const.con->tag == Ico_U8
2756        && e->Iex.Const.con->Ico.U8 >= 1
2757        && e->Iex.Const.con->Ico.U8 <= 31) {
2758       return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2759    }
2760 
2761    /* default case: calculate into a register and return that */
2762    return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2763 }
2764 
2765 
2766 /* --------------------- RH6u --------------------- */
2767 
2768 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2769    being an immediate in the range 1 .. 63 inclusive.  Used for doing
2770    shift amounts.  Only used in 64-bit mode. */
2771 
iselWordExpr_RH6u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2772 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e,
2773                                   IREndness IEndianess )
2774 {
2775    PPCRH* ri;
2776    vassert(env->mode64);
2777    ri = iselWordExpr_RH6u_wrk(env, e, IEndianess);
2778    /* sanity checks ... */
2779    switch (ri->tag) {
2780    case Prh_Imm:
2781       vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2782       vassert(!ri->Prh.Imm.syned);
2783       return ri;
2784    case Prh_Reg:
2785       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2786       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2787       return ri;
2788    default:
2789       vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2790    }
2791 }
2792 
2793 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH6u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2794 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e,
2795                                       IREndness IEndianess )
2796 {
2797    IRType ty = typeOfIRExpr(env->type_env,e);
2798    vassert(ty == Ity_I8);
2799 
2800    /* special case: immediate */
2801    if (e->tag == Iex_Const
2802        && e->Iex.Const.con->tag == Ico_U8
2803        && e->Iex.Const.con->Ico.U8 >= 1
2804        && e->Iex.Const.con->Ico.U8 <= 63) {
2805       return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2806    }
2807 
2808    /* default case: calculate into a register and return that */
2809    return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2810 }
2811 
2812 
2813 /* --------------------- CONDCODE --------------------- */
2814 
2815 /* Generate code to evaluated a bit-typed expression, returning the
2816    condition code which would correspond when the expression would
2817    notionally have returned 1. */
2818 
iselCondCode(ISelEnv * env,IRExpr * e,IREndness IEndianess)2819 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e,
2820                                   IREndness IEndianess )
2821 {
2822    /* Uh, there's nothing we can sanity check here, unfortunately. */
2823    return iselCondCode_wrk(env,e, IEndianess);
2824 }
2825 
2826 /* DO NOT CALL THIS DIRECTLY ! */
iselCondCode_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2827 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e,
2828                                       IREndness IEndianess )
2829 {
2830    vassert(e);
2831    vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2832 
2833    /* Constant 1:Bit */
2834    if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2835       // Make a compare that will always be true:
2836       HReg r_zero = newVRegI(env);
2837       addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2838       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2839                                  7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2840       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2841    }
2842 
2843    /* Not1(...) */
2844    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2845       /* Generate code for the arg, and negate the test condition */
2846       PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2847       cond.test = invertCondTest(cond.test);
2848       return cond;
2849    }
2850 
2851    /* --- patterns rooted at: 32to1 or 64to1 --- */
2852 
2853    /* 32to1, 64to1 */
2854    if (e->tag == Iex_Unop &&
2855        (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2856       HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2857       HReg tmp = newVRegI(env);
2858       /* could do better, probably -- andi. */
2859       addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2860                                  src, PPCRH_Imm(False,1)));
2861       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2862                                  7/*cr*/, tmp, PPCRH_Imm(False,1)));
2863       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2864    }
2865 
2866    /* --- patterns rooted at: CmpNEZ8 --- */
2867 
2868    /* CmpNEZ8(x) */
2869    /* Note this cloned as CmpNE8(x,0) below. */
2870    /* could do better -- andi. */
2871    if (e->tag == Iex_Unop
2872        && e->Iex.Unop.op == Iop_CmpNEZ8) {
2873       HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2874       HReg tmp = newVRegI(env);
2875       addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2876                                  PPCRH_Imm(False,0xFF)));
2877       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2878                                  7/*cr*/, tmp, PPCRH_Imm(False,0)));
2879       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2880    }
2881 
2882    /* --- patterns rooted at: CmpNEZ32 --- */
2883 
2884    /* CmpNEZ32(x) */
2885    if (e->tag == Iex_Unop
2886        && e->Iex.Unop.op == Iop_CmpNEZ32) {
2887       HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2888       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2889                                  7/*cr*/, r1, PPCRH_Imm(False,0)));
2890       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2891    }
2892 
2893    /* --- patterns rooted at: Cmp*32* --- */
2894 
2895    /* Cmp*32*(x,y) */
2896    if (e->tag == Iex_Binop
2897        && (e->Iex.Binop.op == Iop_CmpEQ32
2898            || e->Iex.Binop.op == Iop_CmpNE32
2899            || e->Iex.Binop.op == Iop_CmpLT32S
2900            || e->Iex.Binop.op == Iop_CmpLT32U
2901            || e->Iex.Binop.op == Iop_CmpLE32S
2902            || e->Iex.Binop.op == Iop_CmpLE32U)) {
2903       Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2904                     e->Iex.Binop.op == Iop_CmpLE32S);
2905       HReg   r1  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2906       PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2907       addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2908                                  7/*cr*/, r1, ri2));
2909 
2910       switch (e->Iex.Binop.op) {
2911       case Iop_CmpEQ32:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2912       case Iop_CmpNE32:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2913       case Iop_CmpLT32U: case Iop_CmpLT32S:
2914          return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2915       case Iop_CmpLE32U: case Iop_CmpLE32S:
2916          return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2917       default: vpanic("iselCondCode(ppc): CmpXX32");
2918       }
2919    }
2920 
2921    /* --- patterns rooted at: CmpNEZ64 --- */
2922 
2923    /* CmpNEZ64 */
2924    if (e->tag == Iex_Unop
2925        && e->Iex.Unop.op == Iop_CmpNEZ64) {
2926       if (!env->mode64) {
2927          HReg hi, lo;
2928          HReg tmp = newVRegI(env);
2929          iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg, IEndianess );
2930          addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2931          addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2932                                     7/*cr*/, tmp,PPCRH_Imm(False,0)));
2933          return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2934       } else {  // mode64
2935          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2936          addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2937                                     7/*cr*/, r_src,PPCRH_Imm(False,0)));
2938          return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2939       }
2940    }
2941 
2942    /* --- patterns rooted at: Cmp*64* --- */
2943 
2944    /* Cmp*64*(x,y) */
2945    if (e->tag == Iex_Binop
2946        && (e->Iex.Binop.op == Iop_CmpEQ64
2947            || e->Iex.Binop.op == Iop_CmpNE64
2948            || e->Iex.Binop.op == Iop_CmpLT64S
2949            || e->Iex.Binop.op == Iop_CmpLT64U
2950            || e->Iex.Binop.op == Iop_CmpLE64S
2951            || e->Iex.Binop.op == Iop_CmpLE64U)) {
2952       Bool   syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2953                       e->Iex.Binop.op == Iop_CmpLE64S);
2954       HReg    r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2955       PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2956       vassert(env->mode64);
2957       addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2958                                  7/*cr*/, r1, ri2));
2959 
2960       switch (e->Iex.Binop.op) {
2961       case Iop_CmpEQ64:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2962       case Iop_CmpNE64:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2963       case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2964       case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2965       default: vpanic("iselCondCode(ppc): CmpXX64");
2966       }
2967    }
2968 
2969    /* --- patterns rooted at: CmpNE8 --- */
2970 
2971    /* CmpNE8(x,0) */
2972    /* Note this is a direct copy of CmpNEZ8 above. */
2973    /* could do better -- andi. */
2974    if (e->tag == Iex_Binop
2975        && e->Iex.Binop.op == Iop_CmpNE8
2976        && isZeroU8(e->Iex.Binop.arg2)) {
2977       HReg arg = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2978       HReg tmp = newVRegI(env);
2979       addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2980                                  PPCRH_Imm(False,0xFF)));
2981       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2982                                  7/*cr*/, tmp, PPCRH_Imm(False,0)));
2983       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2984    }
2985 
2986    /* var */
2987    if (e->tag == Iex_RdTmp) {
2988       HReg r_src      = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2989       HReg src_masked = newVRegI(env);
2990       addInstr(env,
2991                PPCInstr_Alu(Palu_AND, src_masked,
2992                             r_src, PPCRH_Imm(False,1)));
2993       addInstr(env,
2994                PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2995                             7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2996       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2997    }
2998 
2999    vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
3000    ppIRExpr(e);
3001    vpanic("iselCondCode(ppc)");
3002 }
3003 
3004 
3005 /*---------------------------------------------------------*/
3006 /*--- ISEL: Integer expressions (128 bit)               ---*/
3007 /*---------------------------------------------------------*/
3008 
3009 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3010    which is returned as the first two parameters.  As with
3011    iselWordExpr_R, these may be either real or virtual regs; in any
3012    case they must not be changed by subsequent code emitted by the
3013    caller.  */
3014 
iselInt128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3015 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
3016                              ISelEnv* env, IRExpr* e, IREndness IEndianess )
3017 {
3018    vassert(env->mode64);
3019    iselInt128Expr_wrk(rHi, rLo, env, e, IEndianess);
3020 #  if 0
3021    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3022 #  endif
3023    vassert(hregClass(*rHi) == HRcGPR(env->mode64));
3024    vassert(hregIsVirtual(*rHi));
3025    vassert(hregClass(*rLo) == HRcGPR(env->mode64));
3026    vassert(hregIsVirtual(*rLo));
3027 }
3028 
3029 /* DO NOT CALL THIS DIRECTLY ! */
iselInt128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3030 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
3031                                  ISelEnv* env, IRExpr* e, IREndness IEndianess )
3032 {
3033    vassert(e);
3034    vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3035 
3036    /* read 128-bit IRTemp */
3037    if (e->tag == Iex_RdTmp) {
3038       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3039       return;
3040    }
3041 
3042    /* --------- BINARY ops --------- */
3043    if (e->tag == Iex_Binop) {
3044       switch (e->Iex.Binop.op) {
3045       /* 64 x 64 -> 128 multiply */
3046       case Iop_MullU64:
3047       case Iop_MullS64: {
3048          HReg     tLo     = newVRegI(env);
3049          HReg     tHi     = newVRegI(env);
3050          Bool     syned   = toBool(e->Iex.Binop.op == Iop_MullS64);
3051          HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3052          HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3053          addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3054                                      False/*lo64*/, False/*64bit mul*/,
3055                                      tLo, r_srcL, r_srcR));
3056          addInstr(env, PPCInstr_MulL(syned,
3057                                      True/*hi64*/, False/*64bit mul*/,
3058                                      tHi, r_srcL, r_srcR));
3059          *rHi = tHi;
3060          *rLo = tLo;
3061          return;
3062       }
3063 
3064       /* 64HLto128(e1,e2) */
3065       case Iop_64HLto128:
3066          *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3067          *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3068          return;
3069       default:
3070          break;
3071       }
3072    } /* if (e->tag == Iex_Binop) */
3073 
3074 
3075    /* --------- UNARY ops --------- */
3076    if (e->tag == Iex_Unop) {
3077       switch (e->Iex.Unop.op) {
3078       default:
3079          break;
3080       }
3081    } /* if (e->tag == Iex_Unop) */
3082 
3083    vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
3084    ppIRExpr(e);
3085    vpanic("iselInt128Expr(ppc64)");
3086 }
3087 
3088 
3089 /*---------------------------------------------------------*/
3090 /*--- ISEL: Integer expressions (64 bit)                ---*/
3091 /*---------------------------------------------------------*/
3092 
3093 /* 32-bit mode ONLY: compute a 128-bit value into a register quad */
iselInt128Expr_to_32x4(HReg * rHi,HReg * rMedHi,HReg * rMedLo,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3094 static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo,
3095                                      HReg* rLo, ISelEnv* env, IRExpr* e,
3096                                      IREndness IEndianess )
3097 {
3098    vassert(!env->mode64);
3099    iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e, IEndianess);
3100 #  if 0
3101    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3102 #  endif
3103    vassert(hregClass(*rHi) == HRcInt32);
3104    vassert(hregIsVirtual(*rHi));
3105    vassert(hregClass(*rMedHi) == HRcInt32);
3106    vassert(hregIsVirtual(*rMedHi));
3107    vassert(hregClass(*rMedLo) == HRcInt32);
3108    vassert(hregIsVirtual(*rMedLo));
3109    vassert(hregClass(*rLo) == HRcInt32);
3110    vassert(hregIsVirtual(*rLo));
3111 }
3112 
iselInt128Expr_to_32x4_wrk(HReg * rHi,HReg * rMedHi,HReg * rMedLo,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3113 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
3114                                          HReg* rMedLo, HReg* rLo,
3115                                          ISelEnv* env, IRExpr* e,
3116                                          IREndness IEndianess )
3117 {
3118    vassert(e);
3119    vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3120 
3121    /* read 128-bit IRTemp */
3122    if (e->tag == Iex_RdTmp) {
3123       lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp);
3124       return;
3125    }
3126 
3127    if (e->tag == Iex_Binop) {
3128 
3129       IROp op_binop = e->Iex.Binop.op;
3130       switch (op_binop) {
3131       case Iop_64HLto128:
3132          iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess);
3133          iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess);
3134          return;
3135       default:
3136          vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3137                     op_binop);
3138          break;
3139       }
3140    }
3141 
3142    vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
3143    return;
3144 }
3145 
3146 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3147    which is returned as the first two parameters.  As with
3148    iselIntExpr_R, these may be either real or virtual regs; in any
3149    case they must not be changed by subsequent code emitted by the
3150    caller.  */
3151 
iselInt64Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3152 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
3153                             ISelEnv* env, IRExpr* e,
3154                             IREndness IEndianess )
3155 {
3156    vassert(!env->mode64);
3157    iselInt64Expr_wrk(rHi, rLo, env, e, IEndianess);
3158 #  if 0
3159    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3160 #  endif
3161    vassert(hregClass(*rHi) == HRcInt32);
3162    vassert(hregIsVirtual(*rHi));
3163    vassert(hregClass(*rLo) == HRcInt32);
3164    vassert(hregIsVirtual(*rLo));
3165 }
3166 
3167 /* DO NOT CALL THIS DIRECTLY ! */
iselInt64Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3168 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
3169                                 ISelEnv* env, IRExpr* e,
3170                                 IREndness IEndianess )
3171 {
3172    vassert(e);
3173    vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
3174 
3175    /* 64-bit load */
3176    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3177       HReg tLo    = newVRegI(env);
3178       HReg tHi    = newVRegI(env);
3179       HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr, IEndianess);
3180       vassert(!env->mode64);
3181       addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3182                                    tHi, PPCAMode_IR( 0, r_addr ),
3183                                    False/*32-bit insn please*/) );
3184       addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3185                                    tLo, PPCAMode_IR( 4, r_addr ),
3186                                    False/*32-bit insn please*/) );
3187       *rHi = tHi;
3188       *rLo = tLo;
3189       return;
3190    }
3191 
3192    /* 64-bit literal */
3193    if (e->tag == Iex_Const) {
3194       ULong w64 = e->Iex.Const.con->Ico.U64;
3195       UInt  wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
3196       UInt  wLo = ((UInt)w64) & 0xFFFFFFFF;
3197       HReg  tLo = newVRegI(env);
3198       HReg  tHi = newVRegI(env);
3199       vassert(e->Iex.Const.con->tag == Ico_U64);
3200       addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
3201       addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
3202       *rHi = tHi;
3203       *rLo = tLo;
3204       return;
3205    }
3206 
3207    /* read 64-bit IRTemp */
3208    if (e->tag == Iex_RdTmp) {
3209       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3210       return;
3211    }
3212 
3213    /* 64-bit GET */
3214    if (e->tag == Iex_Get) {
3215       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3216                                        GuestStatePtr(False/*mode32*/) );
3217       PPCAMode* am_addr4 = advance4(env, am_addr);
3218       HReg tLo = newVRegI(env);
3219       HReg tHi = newVRegI(env);
3220       addInstr(env, PPCInstr_Load( 4, tHi, am_addr,  False/*mode32*/ ));
3221       addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
3222       *rHi = tHi;
3223       *rLo = tLo;
3224       return;
3225    }
3226 
3227    /* 64-bit ITE */
3228    if (e->tag == Iex_ITE) { // VFD
3229       HReg e0Lo, e0Hi, eXLo, eXHi;
3230       iselInt64Expr(&eXHi, &eXLo, env, e->Iex.ITE.iftrue, IEndianess);
3231       iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse, IEndianess);
3232       HReg tLo = newVRegI(env);
3233       HReg tHi = newVRegI(env);
3234       addInstr(env, mk_iMOVds_RR(tHi,e0Hi));
3235       addInstr(env, mk_iMOVds_RR(tLo,e0Lo));
3236       PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
3237       addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(eXHi)));
3238       addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(eXLo)));
3239       *rHi = tHi;
3240       *rLo = tLo;
3241       return;
3242    }
3243 
3244    /* --------- BINARY ops --------- */
3245    if (e->tag == Iex_Binop) {
3246       IROp op_binop = e->Iex.Binop.op;
3247       switch (op_binop) {
3248          /* 32 x 32 -> 64 multiply */
3249          case Iop_MullU32:
3250          case Iop_MullS32: {
3251             HReg     tLo     = newVRegI(env);
3252             HReg     tHi     = newVRegI(env);
3253             Bool     syned   = toBool(op_binop == Iop_MullS32);
3254             HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1,
3255                                               IEndianess);
3256             HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2,
3257                                               IEndianess);
3258             addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3259                                         False/*lo32*/, True/*32bit mul*/,
3260                                         tLo, r_srcL, r_srcR));
3261             addInstr(env, PPCInstr_MulL(syned,
3262                                         True/*hi32*/, True/*32bit mul*/,
3263                                         tHi, r_srcL, r_srcR));
3264             *rHi = tHi;
3265             *rLo = tLo;
3266             return;
3267          }
3268 
3269          /* Or64/And64/Xor64 */
3270          case Iop_Or64:
3271          case Iop_And64:
3272          case Iop_Xor64: {
3273             HReg xLo, xHi, yLo, yHi;
3274             HReg tLo = newVRegI(env);
3275             HReg tHi = newVRegI(env);
3276             PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
3277                           (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
3278             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3279             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3280             addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
3281             addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
3282             *rHi = tHi;
3283             *rLo = tLo;
3284             return;
3285          }
3286 
3287          /* Add64 */
3288          case Iop_Add64: {
3289             HReg xLo, xHi, yLo, yHi;
3290             HReg tLo = newVRegI(env);
3291             HReg tHi = newVRegI(env);
3292             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3293             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3294             addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
3295                                             tLo, xLo, yLo));
3296             addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
3297                                             tHi, xHi, yHi));
3298             *rHi = tHi;
3299             *rLo = tLo;
3300             return;
3301          }
3302 
3303          /* 32HLto64(e1,e2) */
3304          case Iop_32HLto64:
3305             *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3306             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3307             return;
3308 
3309          /* F64toI64[S|U] */
3310          case Iop_F64toI64S: case Iop_F64toI64U: {
3311             HReg      tLo     = newVRegI(env);
3312             HReg      tHi     = newVRegI(env);
3313             HReg      r1      = StackFramePtr(env->mode64);
3314             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3315             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3316             HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2,
3317                                             IEndianess);
3318             HReg      ftmp    = newVRegF(env);
3319 
3320             vassert(!env->mode64);
3321             /* Set host rounding mode */
3322             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3323 
3324             sub_from_sp( env, 16 );
3325             addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
3326                                           (op_binop == Iop_F64toI64S) ? True : False,
3327                                           True, ftmp, fsrc));
3328             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3329             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3330             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3331             add_to_sp( env, 16 );
3332 
3333             ///* Restore default FPU rounding. */
3334             //set_FPU_rounding_default( env );
3335             *rHi = tHi;
3336             *rLo = tLo;
3337             return;
3338          }
3339          case Iop_D64toI64S: {
3340             HReg      tLo     = newVRegI(env);
3341             HReg      tHi     = newVRegI(env);
3342             HReg      r1      = StackFramePtr(env->mode64);
3343             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3344             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3345             HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
3346             HReg tmp    = newVRegF(env);
3347 
3348             vassert(!env->mode64);
3349             set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3350             addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src));
3351 
3352             sub_from_sp( env, 16 );
3353             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3354             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3355             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3356             add_to_sp( env, 16 );
3357             *rHi = tHi;
3358             *rLo = tLo;
3359             return;
3360          }
3361          case Iop_D128toI64S: {
3362             PPCFpOp fpop = Pfp_DCTFIXQ;
3363             HReg r_srcHi = newVRegF(env);
3364             HReg r_srcLo = newVRegF(env);
3365             HReg tLo     = newVRegI(env);
3366             HReg tHi     = newVRegI(env);
3367             HReg ftmp    = newVRegF(env);
3368             PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3369             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3370 
3371             set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3372             iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
3373                            IEndianess);
3374             addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
3375 
3376             // put the D64 result into an integer register pair
3377             sub_from_sp( env, 16 );
3378             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3379             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3380             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3381             add_to_sp( env, 16 );
3382             *rHi = tHi;
3383             *rLo = tLo;
3384             return;
3385          }
3386          default:
3387             break;
3388       }
3389    } /* if (e->tag == Iex_Binop) */
3390 
3391 
3392    /* --------- UNARY ops --------- */
3393    if (e->tag == Iex_Unop) {
3394       switch (e->Iex.Unop.op) {
3395 
3396       /* CmpwNEZ64(e) */
3397       case Iop_CmpwNEZ64: {
3398          HReg argHi, argLo;
3399          HReg tmp1  = newVRegI(env);
3400          HReg tmp2  = newVRegI(env);
3401          iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3402          /* tmp1 = argHi | argLo */
3403          addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
3404          /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3405          addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
3406          addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
3407          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3408                                      tmp2, tmp2, PPCRH_Imm(False, 31)));
3409          *rHi = tmp2;
3410          *rLo = tmp2; /* yes, really tmp2 */
3411          return;
3412       }
3413 
3414       /* Left64 */
3415       case Iop_Left64: {
3416          HReg argHi, argLo;
3417          HReg zero32 = newVRegI(env);
3418          HReg resHi  = newVRegI(env);
3419          HReg resLo  = newVRegI(env);
3420          iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3421          vassert(env->mode64 == False);
3422          addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
3423          /* resHi:resLo = - argHi:argLo */
3424          addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
3425                                          resLo, zero32, argLo ));
3426          addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
3427                                          resHi, zero32, argHi ));
3428          /* resHi:resLo |= srcHi:srcLo */
3429          addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
3430          addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
3431          *rHi = resHi;
3432          *rLo = resLo;
3433          return;
3434       }
3435 
3436       /* 32Sto64(e) */
3437       case Iop_32Sto64: {
3438          HReg tHi = newVRegI(env);
3439          HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3440          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3441                                      tHi, src, PPCRH_Imm(False,31)));
3442          *rHi = tHi;
3443          *rLo = src;
3444          return;
3445       }
3446       case Iop_ExtractExpD64: {
3447          HReg tmp    = newVRegF(env);
3448          HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3449          HReg      tLo     = newVRegI(env);
3450          HReg      tHi     = newVRegI(env);
3451          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3452          PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3453 
3454          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
3455 
3456          // put the D64 result into a integer register pair
3457          sub_from_sp( env, 16 );
3458          addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3459          addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3460          addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3461          add_to_sp( env, 16 );
3462          *rHi = tHi;
3463          *rLo = tLo;
3464          return;
3465       }
3466       case Iop_ExtractExpD128: {
3467          HReg      r_srcHi;
3468          HReg      r_srcLo;
3469          HReg      tmp     = newVRegF(env);
3470          HReg      tLo     = newVRegI(env);
3471          HReg      tHi     = newVRegI(env);
3472          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3473          PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3474 
3475          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, IEndianess);
3476          addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
3477                                                   r_srcHi, r_srcLo));
3478 
3479          // put the D64 result into a integer register pair
3480          sub_from_sp( env, 16 );
3481          addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3482          addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3483          addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3484          add_to_sp( env, 16 );
3485          *rHi = tHi;
3486          *rLo = tLo;
3487          return;
3488       }
3489 
3490       /* 32Uto64(e) */
3491       case Iop_32Uto64: {
3492          HReg tHi = newVRegI(env);
3493          HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3494          addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
3495          *rHi = tHi;
3496          *rLo = tLo;
3497          return;
3498       }
3499 
3500       case Iop_128to64: {
3501          /* Narrow, return the low 64-bit half as a 32-bit
3502           * register pair */
3503          HReg r_Hi    = INVALID_HREG;
3504          HReg r_MedHi = INVALID_HREG;
3505          HReg r_MedLo = INVALID_HREG;
3506          HReg r_Lo    = INVALID_HREG;
3507 
3508          iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3509                                 env, e->Iex.Unop.arg, IEndianess);
3510          *rHi = r_MedLo;
3511          *rLo = r_Lo;
3512          return;
3513       }
3514 
3515       case Iop_128HIto64: {
3516          /* Narrow, return the high 64-bit half as a 32-bit
3517           *  register pair */
3518          HReg r_Hi    = INVALID_HREG;
3519          HReg r_MedHi = INVALID_HREG;
3520          HReg r_MedLo = INVALID_HREG;
3521          HReg r_Lo    = INVALID_HREG;
3522 
3523          iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3524                                 env, e->Iex.Unop.arg, IEndianess);
3525          *rHi = r_Hi;
3526          *rLo = r_MedHi;
3527          return;
3528       }
3529 
3530       /* V128{HI}to64 */
3531       case Iop_V128HIto64:
3532       case Iop_V128to64: {
3533          HReg r_aligned16;
3534          Int  off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
3535          HReg tLo = newVRegI(env);
3536          HReg tHi = newVRegI(env);
3537          HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
3538          PPCAMode *am_off0, *am_offLO, *am_offHI;
3539          sub_from_sp( env, 32 );     // Move SP down 32 bytes
3540 
3541          // get a quadword aligned address within our stack space
3542          r_aligned16 = get_sp_aligned16( env );
3543          am_off0  = PPCAMode_IR( 0,     r_aligned16 );
3544          am_offHI = PPCAMode_IR( off,   r_aligned16 );
3545          am_offLO = PPCAMode_IR( off+4, r_aligned16 );
3546 
3547          // store as Vec128
3548          addInstr(env,
3549                   PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
3550 
3551          // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3552          addInstr(env,
3553                   PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
3554          addInstr(env,
3555                   PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
3556 
3557          add_to_sp( env, 32 );       // Reset SP
3558          *rHi = tHi;
3559          *rLo = tLo;
3560          return;
3561       }
3562 
3563       /* could do better than this, but for now ... */
3564       case Iop_1Sto64: {
3565          HReg tLo = newVRegI(env);
3566          HReg tHi = newVRegI(env);
3567          PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
3568          addInstr(env, PPCInstr_Set(cond,tLo));
3569          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
3570                                      tLo, tLo, PPCRH_Imm(False,31)));
3571          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3572                                      tLo, tLo, PPCRH_Imm(False,31)));
3573          addInstr(env, mk_iMOVds_RR(tHi, tLo));
3574          *rHi = tHi;
3575          *rLo = tLo;
3576          return;
3577       }
3578 
3579       case Iop_Not64: {
3580          HReg xLo, xHi;
3581          HReg tmpLo = newVRegI(env);
3582          HReg tmpHi = newVRegI(env);
3583          iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg, IEndianess);
3584          addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
3585          addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
3586          *rHi = tmpHi;
3587          *rLo = tmpLo;
3588          return;
3589       }
3590 
3591       /* ReinterpF64asI64(e) */
3592       /* Given an IEEE754 double, produce an I64 with the same bit
3593          pattern. */
3594       case Iop_ReinterpF64asI64: {
3595          PPCAMode *am_addr0, *am_addr1;
3596          HReg fr_src  = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3597          HReg r_dstLo = newVRegI(env);
3598          HReg r_dstHi = newVRegI(env);
3599 
3600          sub_from_sp( env, 16 );     // Move SP down 16 bytes
3601          am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3602          am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3603 
3604          // store as F64
3605          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3606                                         fr_src, am_addr0 ));
3607 
3608          // load hi,lo as Ity_I32's
3609          addInstr(env, PPCInstr_Load( 4, r_dstHi,
3610                                       am_addr0, False/*mode32*/ ));
3611          addInstr(env, PPCInstr_Load( 4, r_dstLo,
3612                                       am_addr1, False/*mode32*/ ));
3613          *rHi = r_dstHi;
3614          *rLo = r_dstLo;
3615 
3616          add_to_sp( env, 16 );       // Reset SP
3617          return;
3618       }
3619 
3620       case Iop_ReinterpD64asI64: {
3621          HReg fr_src  = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3622          PPCAMode *am_addr0, *am_addr1;
3623          HReg r_dstLo = newVRegI(env);
3624          HReg r_dstHi = newVRegI(env);
3625 
3626 
3627          sub_from_sp( env, 16 );     // Move SP down 16 bytes
3628          am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3629          am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3630 
3631          // store as D64
3632          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3633                                         fr_src, am_addr0 ));
3634 
3635          // load hi,lo as Ity_I32's
3636          addInstr(env, PPCInstr_Load( 4, r_dstHi,
3637                                       am_addr0, False/*mode32*/ ));
3638          addInstr(env, PPCInstr_Load( 4, r_dstLo,
3639                                       am_addr1, False/*mode32*/ ));
3640          *rHi = r_dstHi;
3641          *rLo = r_dstLo;
3642 
3643          add_to_sp( env, 16 );       // Reset SP
3644 
3645          return;
3646       }
3647 
3648       case Iop_BCDtoDPB: {
3649          PPCCondCode cc;
3650          UInt        argiregs;
3651          HReg        argregs[2];
3652          Int         argreg;
3653          HReg        tLo = newVRegI(env);
3654          HReg        tHi = newVRegI(env);
3655          HReg        tmpHi;
3656          HReg        tmpLo;
3657          Bool        mode64 = env->mode64;
3658 
3659          argregs[0] = hregPPC_GPR3(mode64);
3660          argregs[1] = hregPPC_GPR4(mode64);
3661 
3662          argiregs = 0;
3663          argreg = 0;
3664 
3665          iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess );
3666 
3667          argiregs |= ( 1 << (argreg+3 ) );
3668          addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
3669 
3670          argiregs |= ( 1 << (argreg+3 ) );
3671          addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
3672 
3673          cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3674 
3675          if (IEndianess == Iend_LE) {
3676              addInstr( env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
3677                                            argiregs,
3678                                            mk_RetLoc_simple(RLPri_2Int) ) );
3679          } else {
3680              Addr64 target;
3681              target = mode64 ? (Addr)h_calc_BCDtoDPB :
3682                toUInt( (Addr)h_calc_BCDtoDPB );
3683              addInstr( env, PPCInstr_Call( cc, target,
3684                                            argiregs,
3685                                            mk_RetLoc_simple(RLPri_2Int) ) );
3686          }
3687 
3688          addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
3689          addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
3690 
3691          *rHi = tHi;
3692          *rLo = tLo;
3693          return;
3694       }
3695 
3696       case Iop_DPBtoBCD: {
3697          PPCCondCode cc;
3698          UInt        argiregs;
3699          HReg        argregs[2];
3700          Int         argreg;
3701          HReg        tLo = newVRegI(env);
3702          HReg        tHi = newVRegI(env);
3703          HReg        tmpHi;
3704          HReg        tmpLo;
3705          Bool        mode64 = env->mode64;
3706 
3707          argregs[0] = hregPPC_GPR3(mode64);
3708          argregs[1] = hregPPC_GPR4(mode64);
3709 
3710          argiregs = 0;
3711          argreg = 0;
3712 
3713          iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess);
3714 
3715          argiregs |= (1 << (argreg+3));
3716          addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
3717 
3718          argiregs |= (1 << (argreg+3));
3719          addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
3720 
3721          cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3722 
3723          if (IEndianess == Iend_LE) {
3724              addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
3725                                           argiregs,
3726                                           mk_RetLoc_simple(RLPri_2Int) ) );
3727          } else {
3728              Addr64 target;
3729              target = mode64 ? (Addr)h_calc_DPBtoBCD :
3730                toUInt( (Addr)h_calc_DPBtoBCD );
3731              addInstr(env, PPCInstr_Call( cc, target, argiregs,
3732                                           mk_RetLoc_simple(RLPri_2Int) ) );
3733          }
3734 
3735          addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
3736          addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
3737 
3738          *rHi = tHi;
3739          *rLo = tLo;
3740          return;
3741       }
3742 
3743       default:
3744          break;
3745       }
3746    } /* if (e->tag == Iex_Unop) */
3747 
3748    vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
3749    ppIRExpr(e);
3750    vpanic("iselInt64Expr(ppc)");
3751 }
3752 
3753 
3754 /*---------------------------------------------------------*/
3755 /*--- ISEL: Floating point expressions (32 bit)         ---*/
3756 /*---------------------------------------------------------*/
3757 
3758 /* Nothing interesting here; really just wrappers for
3759    64-bit stuff. */
3760 
iselFltExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3761 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3762 {
3763   HReg r = iselFltExpr_wrk( env, e, IEndianess );
3764 #  if 0
3765    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3766 #  endif
3767    vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
3768    vassert(hregIsVirtual(r));
3769    return r;
3770 }
3771 
3772 /* DO NOT CALL THIS DIRECTLY */
iselFltExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3773 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3774 {
3775    Bool        mode64 = env->mode64;
3776 
3777    IRType ty = typeOfIRExpr(env->type_env,e);
3778    vassert(ty == Ity_F32);
3779 
3780    if (e->tag == Iex_RdTmp) {
3781       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3782    }
3783 
3784    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3785       PPCAMode* am_addr;
3786       HReg r_dst = newVRegF(env);
3787       vassert(e->Iex.Load.ty == Ity_F32);
3788       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/,
3789                                    IEndianess);
3790       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
3791       return r_dst;
3792    }
3793 
3794    if (e->tag == Iex_Get) {
3795       HReg r_dst = newVRegF(env);
3796       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3797                                        GuestStatePtr(env->mode64) );
3798       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
3799       return r_dst;
3800    }
3801 
3802    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3803       /* This is quite subtle.  The only way to do the relevant
3804          truncation is to do a single-precision store and then a
3805          double precision load to get it back into a register.  The
3806          problem is, if the data is then written to memory a second
3807          time, as in
3808 
3809             STbe(...) = TruncF64asF32(...)
3810 
3811          then will the second truncation further alter the value?  The
3812          answer is no: flds (as generated here) followed by fsts
3813          (generated for the STbe) is the identity function on 32-bit
3814          floats, so we are safe.
3815 
3816          Another upshot of this is that if iselStmt can see the
3817          entirety of
3818 
3819             STbe(...) = TruncF64asF32(arg)
3820 
3821          then it can short circuit having to deal with TruncF64asF32
3822          individually; instead just compute arg into a 64-bit FP
3823          register and do 'fsts' (since that itself does the
3824          truncation).
3825 
3826          We generate pretty poor code here (should be ok both for
3827          32-bit and 64-bit mode); but it is expected that for the most
3828          part the latter optimisation will apply and hence this code
3829          will not often be used.
3830       */
3831       HReg      fsrc    = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3832       HReg      fdst    = newVRegF(env);
3833       PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3834 
3835       sub_from_sp( env, 16 );
3836       // store as F32, hence truncating
3837       addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3838                                      fsrc, zero_r1 ));
3839       // and reload.  Good huh?! (sigh)
3840       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3841                                      fdst, zero_r1 ));
3842       add_to_sp( env, 16 );
3843       return fdst;
3844    }
3845 
3846    if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3847       if (mode64) {
3848          HReg fdst = newVRegF(env);
3849          HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3850          HReg r1   = StackFramePtr(env->mode64);
3851          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3852 
3853          /* Set host rounding mode */
3854          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3855 
3856          sub_from_sp( env, 16 );
3857 
3858          addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3859          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3860          addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3861                                        False, False,
3862                                        fdst, fdst));
3863 
3864          add_to_sp( env, 16 );
3865 
3866          ///* Restore default FPU rounding. */
3867          //set_FPU_rounding_default( env );
3868          return fdst;
3869       } else {
3870          /* 32-bit mode */
3871          HReg fdst = newVRegF(env);
3872          HReg isrcHi, isrcLo;
3873          HReg r1   = StackFramePtr(env->mode64);
3874          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3875          PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3876 
3877          iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, IEndianess);
3878 
3879          /* Set host rounding mode */
3880          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3881 
3882          sub_from_sp( env, 16 );
3883 
3884          addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3885          addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3886          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3887          addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3888                                        False, False,
3889                                        fdst, fdst));
3890 
3891          add_to_sp( env, 16 );
3892 
3893          ///* Restore default FPU rounding. */
3894          //set_FPU_rounding_default( env );
3895          return fdst;
3896       }
3897 
3898    }
3899 
3900    vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3901    ppIRExpr(e);
3902    vpanic("iselFltExpr_wrk(ppc)");
3903 }
3904 
3905 
3906 /*---------------------------------------------------------*/
3907 /*--- ISEL: Floating point expressions (64 bit)         ---*/
3908 /*---------------------------------------------------------*/
3909 
3910 /* Compute a 64-bit floating point value into a register, the identity
3911    of which is returned.  As with iselIntExpr_R, the reg may be either
3912    real or virtual; in any case it must not be changed by subsequent
3913    code emitted by the caller.  */
3914 
3915 /* IEEE 754 formats.  From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3916 
3917     Type                  S (1 bit)   E (11 bits)   F (52 bits)
3918     ----                  ---------   -----------   -----------
3919     signalling NaN        u           2047 (max)    .0uuuuu---u
3920                                                     (with at least
3921                                                      one 1 bit)
3922     quiet NaN             u           2047 (max)    .1uuuuu---u
3923 
3924     negative infinity     1           2047 (max)    .000000---0
3925 
3926     positive infinity     0           2047 (max)    .000000---0
3927 
3928     negative zero         1           0             .000000---0
3929 
3930     positive zero         0           0             .000000---0
3931 */
3932 
iselDblExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3933 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3934 {
3935    HReg r = iselDblExpr_wrk( env, e, IEndianess );
3936 #  if 0
3937    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3938 #  endif
3939    vassert(hregClass(r) == HRcFlt64);
3940    vassert(hregIsVirtual(r));
3941    return r;
3942 }
3943 
3944 /* DO NOT CALL THIS DIRECTLY */
iselDblExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3945 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3946 {
3947    Bool mode64 = env->mode64;
3948    IRType ty = typeOfIRExpr(env->type_env,e);
3949    vassert(e);
3950    vassert(ty == Ity_F64);
3951 
3952    if (e->tag == Iex_RdTmp) {
3953       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3954    }
3955 
3956    /* --------- LITERAL --------- */
3957    if (e->tag == Iex_Const) {
3958       union { UInt u32x2[2]; ULong u64; Double f64; } u;
3959       vassert(sizeof(u) == 8);
3960       vassert(sizeof(u.u64) == 8);
3961       vassert(sizeof(u.f64) == 8);
3962       vassert(sizeof(u.u32x2) == 8);
3963 
3964       if (e->Iex.Const.con->tag == Ico_F64) {
3965          u.f64 = e->Iex.Const.con->Ico.F64;
3966       }
3967       else if (e->Iex.Const.con->tag == Ico_F64i) {
3968          u.u64 = e->Iex.Const.con->Ico.F64i;
3969       }
3970       else
3971          vpanic("iselDblExpr(ppc): const");
3972 
3973       if (!mode64) {
3974          HReg r_srcHi = newVRegI(env);
3975          HReg r_srcLo = newVRegI(env);
3976          addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3977          addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3978          return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3979       } else { // mode64
3980          HReg r_src = newVRegI(env);
3981          addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3982          return mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
3983       }
3984    }
3985 
3986    /* --------- LOAD --------- */
3987    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3988       HReg r_dst = newVRegF(env);
3989       PPCAMode* am_addr;
3990       vassert(e->Iex.Load.ty == Ity_F64);
3991       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/,
3992                                    IEndianess);
3993       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3994       return r_dst;
3995    }
3996 
3997    /* --------- GET --------- */
3998    if (e->tag == Iex_Get) {
3999       HReg r_dst = newVRegF(env);
4000       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4001                                        GuestStatePtr(mode64) );
4002       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
4003       return r_dst;
4004    }
4005 
4006    /* --------- OPS --------- */
4007    if (e->tag == Iex_Qop) {
4008       PPCFpOp fpop = Pfp_INVALID;
4009       switch (e->Iex.Qop.details->op) {
4010          case Iop_MAddF64:    fpop = Pfp_MADDD; break;
4011          case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
4012          case Iop_MSubF64:    fpop = Pfp_MSUBD; break;
4013          case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
4014          default: break;
4015       }
4016       if (fpop != Pfp_INVALID) {
4017          HReg r_dst  = newVRegF(env);
4018          HReg r_srcML  = iselDblExpr(env, e->Iex.Qop.details->arg2,
4019                                      IEndianess);
4020          HReg r_srcMR  = iselDblExpr(env, e->Iex.Qop.details->arg3,
4021                                      IEndianess);
4022          HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4,
4023                                      IEndianess);
4024          set_FPU_rounding_mode( env, e->Iex.Qop.details->arg1, IEndianess );
4025          addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
4026                                                r_srcML, r_srcMR, r_srcAcc));
4027          return r_dst;
4028       }
4029    }
4030 
4031    if (e->tag == Iex_Triop) {
4032       IRTriop *triop = e->Iex.Triop.details;
4033       PPCFpOp fpop = Pfp_INVALID;
4034       switch (triop->op) {
4035          case Iop_AddF64:    fpop = Pfp_ADDD; break;
4036          case Iop_SubF64:    fpop = Pfp_SUBD; break;
4037          case Iop_MulF64:    fpop = Pfp_MULD; break;
4038          case Iop_DivF64:    fpop = Pfp_DIVD; break;
4039          case Iop_AddF64r32: fpop = Pfp_ADDS; break;
4040          case Iop_SubF64r32: fpop = Pfp_SUBS; break;
4041          case Iop_MulF64r32: fpop = Pfp_MULS; break;
4042          case Iop_DivF64r32: fpop = Pfp_DIVS; break;
4043          default: break;
4044       }
4045       if (fpop != Pfp_INVALID) {
4046          HReg r_dst  = newVRegF(env);
4047          HReg r_srcL = iselDblExpr(env, triop->arg2, IEndianess);
4048          HReg r_srcR = iselDblExpr(env, triop->arg3, IEndianess);
4049          set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4050          addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
4051          return r_dst;
4052       }
4053    }
4054 
4055    if (e->tag == Iex_Binop) {
4056       PPCFpOp fpop = Pfp_INVALID;
4057       switch (e->Iex.Binop.op) {
4058       case Iop_SqrtF64:   fpop = Pfp_SQRT;   break;
4059       default: break;
4060       }
4061       if (fpop == Pfp_SQRT) {
4062          HReg fr_dst = newVRegF(env);
4063          HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4064          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4065          addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4066          return fr_dst;
4067       }
4068    }
4069 
4070    if (e->tag == Iex_Binop) {
4071 
4072       if (e->Iex.Binop.op == Iop_RoundF64toF32) {
4073          HReg r_dst = newVRegF(env);
4074          HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4075          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4076          addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
4077          //set_FPU_rounding_default( env );
4078          return r_dst;
4079       }
4080 
4081       if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
4082          if (mode64) {
4083             HReg fdst = newVRegF(env);
4084             HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4085             HReg r1   = StackFramePtr(env->mode64);
4086             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4087 
4088             /* Set host rounding mode */
4089             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4090 
4091             sub_from_sp( env, 16 );
4092 
4093             addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
4094             addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4095             addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4096                                           e->Iex.Binop.op == Iop_I64StoF64,
4097                                           True/*fdst is 64 bit*/,
4098                                           fdst, fdst));
4099 
4100             add_to_sp( env, 16 );
4101 
4102             ///* Restore default FPU rounding. */
4103             //set_FPU_rounding_default( env );
4104             return fdst;
4105          } else {
4106             /* 32-bit mode */
4107             HReg fdst = newVRegF(env);
4108             HReg isrcHi, isrcLo;
4109             HReg r1   = StackFramePtr(env->mode64);
4110             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4111             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
4112 
4113             iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2,
4114                           IEndianess);
4115 
4116             /* Set host rounding mode */
4117             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4118 
4119             sub_from_sp( env, 16 );
4120 
4121             addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
4122             addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
4123             addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4124             addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4125                                           e->Iex.Binop.op == Iop_I64StoF64,
4126                                           True/*fdst is 64 bit*/,
4127                                           fdst, fdst));
4128 
4129             add_to_sp( env, 16 );
4130 
4131             ///* Restore default FPU rounding. */
4132             //set_FPU_rounding_default( env );
4133             return fdst;
4134          }
4135       }
4136 
4137    }
4138 
4139    if (e->tag == Iex_Unop) {
4140       PPCFpOp fpop = Pfp_INVALID;
4141       switch (e->Iex.Unop.op) {
4142          case Iop_NegF64:     fpop = Pfp_NEG; break;
4143          case Iop_AbsF64:     fpop = Pfp_ABS; break;
4144          case Iop_RSqrtEst5GoodF64:      fpop = Pfp_RSQRTE; break;
4145          case Iop_RoundF64toF64_NegINF:  fpop = Pfp_FRIM; break;
4146          case Iop_RoundF64toF64_PosINF:  fpop = Pfp_FRIP; break;
4147          case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
4148          case Iop_RoundF64toF64_ZERO:    fpop = Pfp_FRIZ; break;
4149          default: break;
4150       }
4151       if (fpop != Pfp_INVALID) {
4152          HReg fr_dst = newVRegF(env);
4153          HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4154          addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4155          return fr_dst;
4156       }
4157    }
4158 
4159    if (e->tag == Iex_Unop) {
4160       switch (e->Iex.Unop.op) {
4161          case Iop_ReinterpI64asF64: {
4162             /* Given an I64, produce an IEEE754 double with the same
4163                bit pattern. */
4164             if (!mode64) {
4165                HReg r_srcHi, r_srcLo;
4166                iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4167                                IEndianess);
4168                return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4169             } else {
4170                HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4171                return mk_LoadR64toFPR( env, r_src );
4172             }
4173          }
4174 
4175          case Iop_F32toF64: {
4176             if (e->Iex.Unop.arg->tag == Iex_Unop &&
4177                      e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) {
4178                e = e->Iex.Unop.arg;
4179 
4180                HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4181                HReg fr_dst = newVRegF(env);
4182                PPCAMode *am_addr;
4183 
4184                sub_from_sp( env, 16 );        // Move SP down 16 bytes
4185                am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4186 
4187                // store src as Ity_I32's
4188                addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 ));
4189 
4190                // load single precision float, but the end results loads into a
4191                // 64-bit FP register -- i.e., F64.
4192                addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr));
4193 
4194                add_to_sp( env, 16 );          // Reset SP
4195                return fr_dst;
4196             }
4197 
4198 
4199             /* this is a no-op */
4200             HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
4201             return res;
4202          }
4203          default:
4204             break;
4205       }
4206    }
4207 
4208    /* --------- MULTIPLEX --------- */
4209    if (e->tag == Iex_ITE) { // VFD
4210       if (ty == Ity_F64
4211           && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
4212          HReg fr1    = iselDblExpr(env, e->Iex.ITE.iftrue, IEndianess);
4213          HReg fr0    = iselDblExpr(env, e->Iex.ITE.iffalse, IEndianess);
4214          HReg fr_dst = newVRegF(env);
4215          addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, fr0 ));
4216          PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
4217          addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr1 ));
4218          return fr_dst;
4219       }
4220    }
4221 
4222    vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
4223    ppIRExpr(e);
4224    vpanic("iselDblExpr_wrk(ppc)");
4225 }
4226 
iselDfp32Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4227 static HReg iselDfp32Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4228 {
4229    HReg r = iselDfp32Expr_wrk( env, e, IEndianess );
4230    vassert(hregClass(r) == HRcFlt64);
4231    vassert( hregIsVirtual(r) );
4232    return r;
4233 }
4234 
4235 /* DO NOT CALL THIS DIRECTLY */
iselDfp32Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4236 static HReg iselDfp32Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4237 {
4238    Bool mode64 = env->mode64;
4239    IRType ty = typeOfIRExpr( env->type_env, e );
4240 
4241    vassert( e );
4242    vassert( ty == Ity_D32 );
4243 
4244    /* --------- GET --------- */
4245    if (e->tag == Iex_Get) {
4246       HReg r_dst = newVRegF( env );
4247       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4248                                        GuestStatePtr(mode64) );
4249       addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4250       return r_dst;
4251    }
4252 
4253    /* --------- LOAD --------- */
4254    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4255       PPCAMode* am_addr;
4256       HReg r_dst = newVRegF(env);
4257       vassert(e->Iex.Load.ty == Ity_D32);
4258       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D32/*xfer*/,
4259                                    IEndianess);
4260       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4261       return r_dst;
4262    }
4263 
4264    /* --------- OPS --------- */
4265    if (e->tag == Iex_Binop) {
4266       if (e->Iex.Binop.op == Iop_D64toD32) {
4267          HReg fr_dst = newVRegF(env);
4268          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4269          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4270          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DRSP, fr_dst, fr_src));
4271          return fr_dst;
4272       }
4273    }
4274 
4275    ppIRExpr( e );
4276    vpanic( "iselDfp32Expr_wrk(ppc)" );
4277 }
4278 
iselDfp64Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4279 static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4280 {
4281    HReg r = iselDfp64Expr_wrk( env, e, IEndianess );
4282    vassert(hregClass(r) == HRcFlt64);
4283    vassert( hregIsVirtual(r) );
4284    return r;
4285 }
4286 
4287 /* DO NOT CALL THIS DIRECTLY */
iselDfp64Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4288 static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4289 {
4290    Bool mode64 = env->mode64;
4291    IRType ty = typeOfIRExpr( env->type_env, e );
4292    HReg r_dstHi, r_dstLo;
4293 
4294    vassert( e );
4295    vassert( ty == Ity_D64 );
4296 
4297    if (e->tag == Iex_RdTmp) {
4298       return lookupIRTemp( env, e->Iex.RdTmp.tmp );
4299    }
4300 
4301    /* --------- GET --------- */
4302    if (e->tag == Iex_Get) {
4303       HReg r_dst = newVRegF( env );
4304       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4305                                        GuestStatePtr(mode64) );
4306       addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4307       return r_dst;
4308    }
4309 
4310    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4311       PPCAMode* am_addr;
4312       HReg r_dst = newVRegF(env);
4313       vassert(e->Iex.Load.ty == Ity_D64);
4314       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D64/*xfer*/,
4315                                    IEndianess);
4316       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4317       return r_dst;
4318    }
4319 
4320    /* --------- OPS --------- */
4321    if (e->tag == Iex_Qop) {
4322       HReg r_dst = newVRegF( env );
4323       return r_dst;
4324    }
4325 
4326    if (e->tag == Iex_Unop) {
4327       HReg fr_dst = newVRegF(env);
4328       switch (e->Iex.Unop.op) {
4329       case Iop_ReinterpI64asD64: {
4330          /* Given an I64, produce an IEEE754 DFP with the same
4331                bit pattern. */
4332          if (!mode64) {
4333             HReg r_srcHi, r_srcLo;
4334             iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4335                            IEndianess);
4336             return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4337          } else {
4338             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4339             return mk_LoadR64toFPR( env, r_src );
4340          }
4341       }
4342       case Iop_D32toD64: {
4343          HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg, IEndianess);
4344          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src));
4345          return fr_dst;
4346       }
4347       case Iop_D128HItoD64:
4348          iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4349                          IEndianess );
4350          return r_dstHi;
4351       case Iop_D128LOtoD64:
4352          iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4353                          IEndianess );
4354          return r_dstLo;
4355       case Iop_InsertExpD64: {
4356          HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
4357          HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4358 
4359          addInstr(env, PPCInstr_Dfp64Binary(Pfp_DIEX, fr_dst, fr_srcL,
4360 					    fr_srcR));
4361          return fr_dst;
4362        }
4363       default:
4364          vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
4365                      e->Iex.Unop.op );
4366       }
4367    }
4368 
4369    if (e->tag == Iex_Binop) {
4370       PPCFpOp fpop = Pfp_INVALID;
4371       HReg fr_dst = newVRegF(env);
4372 
4373       switch (e->Iex.Binop.op) {
4374       case Iop_D128toD64:     fpop = Pfp_DRDPQ;  break;
4375       case Iop_D64toD32:      fpop = Pfp_DRSP;   break;
4376       case Iop_I64StoD64:     fpop = Pfp_DCFFIX; break;
4377       case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break;
4378       default: break;
4379       }
4380       if (fpop == Pfp_DRDPQ) {
4381          HReg r_srcHi = newVRegF(env);
4382          HReg r_srcLo = newVRegF(env);
4383 
4384          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4385          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4386                         IEndianess);
4387          addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4388          return fr_dst;
4389 
4390       } else if (fpop == Pfp_DRINTN) {
4391          HReg fr_src = newVRegF(env);
4392          PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4393 
4394          /* NOTE, this IOP takes a DFP value and rounds to the
4395           * neares floating point integer value, i.e. fractional part
4396           * is zero.  The result is a decimal floating point number.
4397           * the INT in the name is a bit misleading.
4398           */
4399          fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4400          addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc));
4401          return fr_dst;
4402 
4403       } else if (fpop == Pfp_DRSP) {
4404          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4405          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4406          addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4407          return fr_dst;
4408 
4409       } else if (fpop == Pfp_DCFFIX) {
4410          HReg fr_src = newVRegF(env);
4411          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4412 
4413          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4414          sub_from_sp( env, 16 );
4415 
4416          // put the I64 value into a floating point register
4417          if (mode64) {
4418            HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4419 
4420            addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4421          } else {
4422             HReg tmpHi, tmpLo;
4423             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4424 
4425             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2,
4426                           IEndianess);
4427             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4428             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4429          }
4430 
4431          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8,  fr_src, zero_r1));
4432          addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4433          add_to_sp( env, 16 );
4434          return fr_dst;
4435       }
4436 
4437       switch (e->Iex.Binop.op) {
4438       /* shift instructions D64, I32 -> D64 */
4439       case Iop_ShlD64: fpop = Pfp_DSCLI; break;
4440       case Iop_ShrD64: fpop = Pfp_DSCRI; break;
4441       default: break;
4442       }
4443       if (fpop != Pfp_INVALID) {
4444          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
4445          PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4446 
4447          /* shift value must be an immediate value */
4448          vassert(shift->tag == Pri_Imm);
4449 
4450          addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift));
4451          return fr_dst;
4452       }
4453 
4454       switch (e->Iex.Binop.op) {
4455       case Iop_InsertExpD64:
4456          fpop = Pfp_DIEX;
4457          break;
4458       default: 	break;
4459       }
4460       if (fpop != Pfp_INVALID) {
4461          HReg fr_srcL = newVRegF(env);
4462          HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4463          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4464          sub_from_sp( env, 16 );
4465 
4466          if (env->mode64) {
4467             // put the I64 value into a floating point reg
4468             HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4469 
4470             addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4471          } else {
4472             // put the I64 register pair into a floating point reg
4473             HReg tmpHi;
4474             HReg tmpLo;
4475             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4476 
4477             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1,
4478                           IEndianess);
4479             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/));
4480             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/));
4481          }
4482          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1));
4483          addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL,
4484                                             fr_srcR));
4485          add_to_sp( env, 16 );
4486          return fr_dst;
4487       }
4488    }
4489 
4490    if (e->tag == Iex_Triop) {
4491       IRTriop *triop = e->Iex.Triop.details;
4492       PPCFpOp fpop = Pfp_INVALID;
4493 
4494       switch (triop->op) {
4495       case Iop_AddD64:
4496          fpop = Pfp_DFPADD;
4497          break;
4498       case Iop_SubD64:
4499          fpop = Pfp_DFPSUB;
4500          break;
4501       case Iop_MulD64:
4502          fpop = Pfp_DFPMUL;
4503          break;
4504       case Iop_DivD64:
4505          fpop = Pfp_DFPDIV;
4506          break;
4507       default:
4508          break;
4509       }
4510       if (fpop != Pfp_INVALID) {
4511          HReg r_dst = newVRegF( env );
4512          HReg r_srcL = iselDfp64Expr( env, triop->arg2, IEndianess );
4513          HReg r_srcR = iselDfp64Expr( env, triop->arg3, IEndianess );
4514 
4515          set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4516          addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) );
4517          return r_dst;
4518       }
4519 
4520       switch (triop->op) {
4521       case Iop_QuantizeD64:          fpop = Pfp_DQUA;  break;
4522       case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
4523       default: break;
4524       }
4525       if (fpop == Pfp_DQUA) {
4526          HReg r_dst = newVRegF(env);
4527          HReg r_srcL = iselDfp64Expr(env, triop->arg2, IEndianess);
4528          HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4529          PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1, IEndianess);
4530          addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR,
4531                                             rmc));
4532          return r_dst;
4533 
4534       } else if (fpop == Pfp_RRDTR) {
4535          HReg r_dst = newVRegF(env);
4536          HReg r_srcL = newVRegF(env);
4537          HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4538          PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1, IEndianess);
4539          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4540          HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4541 
4542          /* Move I8 to float register to issue instruction */
4543          sub_from_sp( env, 16 );
4544          if (mode64)
4545             addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
4546          else
4547             addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/));
4548 
4549          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4550          add_to_sp( env, 16 );
4551 
4552          // will set TE and RMC when issuing instruction
4553          addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
4554          return r_dst;
4555       }
4556    }
4557 
4558    ppIRExpr( e );
4559    vpanic( "iselDfp64Expr_wrk(ppc)" );
4560 }
4561 
iselDfp128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4562 static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e,
4563                            IREndness IEndianess)
4564 {
4565    iselDfp128Expr_wrk( rHi, rLo, env, e, IEndianess );
4566    vassert( hregIsVirtual(*rHi) );
4567    vassert( hregIsVirtual(*rLo) );
4568 }
4569 
4570 /* DO NOT CALL THIS DIRECTLY */
iselDfp128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4571 static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e,
4572                                IREndness IEndianess)
4573 {
4574    vassert( e );
4575    vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 );
4576 
4577    /* read 128-bit IRTemp */
4578    if (e->tag == Iex_RdTmp) {
4579       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
4580       return;
4581    }
4582 
4583    if (e->tag == Iex_Unop) {
4584       HReg r_dstHi = newVRegF(env);
4585       HReg r_dstLo = newVRegF(env);
4586 
4587       if (e->Iex.Unop.op == Iop_I64StoD128) {
4588          HReg fr_src = newVRegF(env);
4589          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4590 
4591          // put the I64 value into a floating point reg
4592          if (env->mode64) {
4593             HReg tmp   = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4594             addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4595          } else {
4596             HReg tmpHi, tmpLo;
4597             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4598 
4599             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4600                           IEndianess);
4601             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4602             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4603          }
4604 
4605          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
4606          addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo,
4607                                               fr_src));
4608       }
4609 
4610       if (e->Iex.Unop.op == Iop_D64toD128) {
4611          HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
4612 
4613          /* Source is 64bit, result is 128 bit.  High 64bit source arg,
4614           * is ignored by the instruction.  Set high arg to r_src just
4615           * to meet the vassert tests.
4616           */
4617          addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo,
4618                                             r_src, r_src));
4619       }
4620       *rHi = r_dstHi;
4621       *rLo = r_dstLo;
4622       return;
4623    }
4624 
4625    /* --------- OPS --------- */
4626    if (e->tag == Iex_Binop) {
4627       HReg r_srcHi;
4628       HReg r_srcLo;
4629 
4630       switch (e->Iex.Binop.op) {
4631       case Iop_D64HLtoD128:
4632          r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1, IEndianess );
4633          r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2, IEndianess );
4634          *rHi = r_srcHi;
4635          *rLo = r_srcLo;
4636          return;
4637          break;
4638       case Iop_D128toD64: {
4639          PPCFpOp fpop = Pfp_DRDPQ;
4640          HReg fr_dst  = newVRegF(env);
4641 
4642          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4643          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4644                         IEndianess);
4645          addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4646 
4647          /* Need to meet the interface spec but the result is
4648           * just 64-bits so send the result back in both halfs.
4649           */
4650          *rHi = fr_dst;
4651          *rLo = fr_dst;
4652          return;
4653       }
4654       case Iop_ShlD128:
4655       case Iop_ShrD128: {
4656          HReg fr_dst_hi = newVRegF(env);
4657          HReg fr_dst_lo = newVRegF(env);
4658          PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4659          PPCFpOp fpop = Pfp_DSCLIQ;  /* fix later if necessary */
4660 
4661          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1,
4662                         IEndianess);
4663 
4664          if (e->Iex.Binop.op == Iop_ShrD128)
4665             fpop = Pfp_DSCRIQ;
4666 
4667          addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo,
4668                                             r_srcHi, r_srcLo, shift));
4669 
4670          *rHi = fr_dst_hi;
4671          *rLo = fr_dst_lo;
4672          return;
4673       }
4674       case Iop_RoundD128toInt: {
4675          HReg r_dstHi = newVRegF(env);
4676          HReg r_dstLo = newVRegF(env);
4677          PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4678 
4679          // will set R and RMC when issuing instruction
4680          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4681                         IEndianess);
4682 
4683          addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo,
4684                                             r_srcHi, r_srcLo, r_rmc));
4685          *rHi = r_dstHi;
4686          *rLo = r_dstLo;
4687          return;
4688       }
4689       case Iop_InsertExpD128: {
4690          HReg r_dstHi = newVRegF(env);
4691          HReg r_dstLo = newVRegF(env);
4692          HReg r_srcL  = newVRegF(env);
4693          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4694          r_srcHi = newVRegF(env);
4695          r_srcLo = newVRegF(env);
4696 
4697          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4698                         IEndianess);
4699 
4700          /* Move I64 to float register to issue instruction */
4701          if (env->mode64) {
4702             HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4703             addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4704          } else {
4705             HReg tmpHi, tmpLo;
4706             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4707 
4708             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4709                           IEndianess);
4710             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4711             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4712          }
4713 
4714          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4715          addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ,
4716                                               r_dstHi, r_dstLo,
4717                                               r_srcL, r_srcHi, r_srcLo));
4718          *rHi = r_dstHi;
4719          *rLo = r_dstLo;
4720          return;
4721       }
4722       default:
4723          vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
4724                      e->Iex.Binop.op );
4725          break;
4726       }
4727    }
4728 
4729    if (e->tag == Iex_Triop) {
4730       IRTriop *triop = e->Iex.Triop.details;
4731       PPCFpOp fpop = Pfp_INVALID;
4732       HReg r_dstHi = newVRegF(env);
4733       HReg r_dstLo = newVRegF(env);
4734 
4735       switch (triop->op) {
4736       case Iop_AddD128:
4737          fpop = Pfp_DFPADDQ;
4738          break;
4739       case Iop_SubD128:
4740          fpop = Pfp_DFPSUBQ;
4741          break;
4742       case Iop_MulD128:
4743          fpop = Pfp_DFPMULQ;
4744          break;
4745       case Iop_DivD128:
4746          fpop = Pfp_DFPDIVQ;
4747          break;
4748       default:
4749          break;
4750       }
4751 
4752       if (fpop != Pfp_INVALID) {
4753          HReg r_srcRHi = newVRegV( env );
4754          HReg r_srcRLo = newVRegV( env );
4755 
4756          /* dst will be used to pass in the left operand and get the result. */
4757          iselDfp128Expr( &r_dstHi, &r_dstLo, env, triop->arg2, IEndianess );
4758          iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, triop->arg3, IEndianess );
4759          set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4760          addInstr( env,
4761                    PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
4762                                           r_srcRHi, r_srcRLo ) );
4763          *rHi = r_dstHi;
4764          *rLo = r_dstLo;
4765          return;
4766       }
4767       switch (triop->op) {
4768       case Iop_QuantizeD128:          fpop = Pfp_DQUAQ;  break;
4769       case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
4770       default: break;
4771       }
4772       if (fpop == Pfp_DQUAQ) {
4773          HReg r_srcHi = newVRegF(env);
4774          HReg r_srcLo = newVRegF(env);
4775          PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4776 
4777          /* dst will be used to pass in the left operand and get the result */
4778          iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2, IEndianess);
4779          iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4780 
4781          // will set RMC when issuing instruction
4782          addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4783                                                r_srcHi, r_srcLo, rmc));
4784         *rHi = r_dstHi;
4785         *rLo = r_dstLo;
4786          return;
4787 
4788       } else if (fpop == Pfp_DRRNDQ) {
4789          HReg r_srcHi = newVRegF(env);
4790          HReg r_srcLo = newVRegF(env);
4791          PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4792          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4793          PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4794          HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4795          HReg r_zero = newVRegI( env );
4796 
4797          iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4798 
4799          /* dst will be used to pass in the left operand and get the result */
4800          /* Move I8 to float register to issue instruction.  Note, the
4801           * instruction only looks at the bottom 6 bits so we really don't
4802           * have to clear the upper bits since the iselWordExpr_R sets the
4803           * bottom 8-bits.
4804           */
4805          sub_from_sp( env, 16 );
4806 
4807          if (env->mode64)
4808             addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
4809          else
4810             addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/));
4811 
4812          /* Have to write to the upper bits to ensure they have been
4813           * initialized. The instruction ignores all but the lower 6-bits.
4814           */
4815          addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
4816          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1));
4817          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1));
4818 
4819          add_to_sp( env, 16 );
4820 
4821          // will set RMC when issuing instruction
4822          addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4823                                                r_srcHi, r_srcLo, rmc));
4824          *rHi = r_dstHi;
4825          *rLo = r_dstLo;
4826          return;
4827       }
4828  }
4829 
4830    ppIRExpr( e );
4831    vpanic( "iselDfp128Expr(ppc64)" );
4832 }
4833 
4834 
4835 /*---------------------------------------------------------*/
4836 /*--- ISEL: SIMD (Vector) expressions, 128 bit.         ---*/
4837 /*---------------------------------------------------------*/
4838 
iselVecExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4839 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4840 {
4841    HReg r = iselVecExpr_wrk( env, e, IEndianess );
4842 #  if 0
4843    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4844 #  endif
4845    vassert(hregClass(r) == HRcVec128);
4846    vassert(hregIsVirtual(r));
4847    return r;
4848 }
4849 
4850 /* DO NOT CALL THIS DIRECTLY */
iselVecExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4851 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4852 {
4853    Bool mode64 = env->mode64;
4854    PPCAvOp op = Pav_INVALID;
4855    PPCAvFpOp fpop = Pavfp_INVALID;
4856    IRType  ty = typeOfIRExpr(env->type_env,e);
4857    vassert(e);
4858    vassert(ty == Ity_V128);
4859 
4860    if (e->tag == Iex_RdTmp) {
4861       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4862    }
4863 
4864    if (e->tag == Iex_Get) {
4865       /* Guest state vectors are 16byte aligned,
4866          so don't need to worry here */
4867       HReg dst = newVRegV(env);
4868       addInstr(env,
4869                PPCInstr_AvLdSt( True/*load*/, 16, dst,
4870                                 PPCAMode_IR( e->Iex.Get.offset,
4871                                              GuestStatePtr(mode64) )));
4872       return dst;
4873    }
4874 
4875    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4876       /* Need to be able to do V128 unaligned loads. The BE unaligned load
4877        * can be accomplised using the following code sequece from the ISA.
4878        * It uses the lvx instruction that does two aligned loads and then
4879        * permute the data to store the required data as if it had been an
4880        * unaligned load.
4881        *
4882        *   lvx  Vhi,0,Rb        # load MSQ, using the unaligned address in Rb
4883        *   lvsl Vp, 0,Rb        # Set permute control vector
4884        *   addi Rb,Rb,15        # Address of LSQ
4885        *   lvx  Vlo,0,Rb        # load LSQ
4886        *   vperm Vt,Vhi,Vlo,Vp  # align the data as requested
4887        */
4888 
4889       HReg Vhi   = newVRegV(env);
4890       HReg Vlo   = newVRegV(env);
4891       HReg Vp    = newVRegV(env);
4892       HReg v_dst = newVRegV(env);
4893       HReg rB;
4894       HReg rB_plus_15 = newVRegI(env);
4895 
4896       vassert(e->Iex.Load.ty == Ity_V128);
4897       rB = iselWordExpr_R( env, e->Iex.Load.addr, IEndianess );
4898 
4899       // lvx  Vhi, 0, Rb
4900       addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi,
4901                                      PPCAMode_IR(0, rB)) );
4902 
4903       if (IEndianess == Iend_LE)
4904          // lvsr Vp, 0, Rb
4905          addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp,
4906                                       PPCAMode_IR(0, rB)) );
4907       else
4908          // lvsl Vp, 0, Rb
4909          addInstr(env, PPCInstr_AvSh( True/*left shift*/, Vp,
4910                                       PPCAMode_IR(0, rB)) );
4911 
4912       // addi Rb_plus_15, Rb, 15
4913       addInstr(env, PPCInstr_Alu( Palu_ADD, rB_plus_15,
4914                                   rB, PPCRH_Imm(True, toUShort(15))) );
4915 
4916       // lvx  Vlo, 0, Rb_plus_15
4917       addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vlo,
4918                                      PPCAMode_IR(0, rB_plus_15)) );
4919 
4920       if (IEndianess == Iend_LE)
4921          // vperm Vt, Vhi, Vlo, Vp
4922          addInstr(env, PPCInstr_AvPerm( v_dst, Vlo, Vhi, Vp ));
4923       else
4924          // vperm Vt, Vhi, Vlo, Vp
4925          addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp ));
4926 
4927       return v_dst;
4928    }
4929 
4930    if (e->tag == Iex_Unop) {
4931       switch (e->Iex.Unop.op) {
4932 
4933       case Iop_NotV128: {
4934          HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4935          HReg dst = newVRegV(env);
4936          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
4937          return dst;
4938       }
4939 
4940       case Iop_CmpNEZ8x16: {
4941          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4942          HReg zero = newVRegV(env);
4943          HReg dst  = newVRegV(env);
4944          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4945          addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
4946          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4947          return dst;
4948       }
4949 
4950       case Iop_CmpNEZ16x8: {
4951          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4952          HReg zero = newVRegV(env);
4953          HReg dst  = newVRegV(env);
4954          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4955          addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
4956          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4957          return dst;
4958       }
4959 
4960       case Iop_CmpNEZ32x4: {
4961          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4962          HReg zero = newVRegV(env);
4963          HReg dst  = newVRegV(env);
4964          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4965          addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
4966          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4967          return dst;
4968       }
4969 
4970       case Iop_CmpNEZ64x2: {
4971          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4972          HReg zero = newVRegV(env);
4973          HReg dst  = newVRegV(env);
4974          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4975          addInstr(env, PPCInstr_AvBin64x2(Pav_CMPEQU, dst, arg, zero));
4976          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4977          return dst;
4978       }
4979 
4980       case Iop_RecipEst32Fx4: fpop = Pavfp_RCPF;    goto do_32Fx4_unary;
4981       case Iop_RSqrtEst32Fx4: fpop = Pavfp_RSQRTF;  goto do_32Fx4_unary;
4982       case Iop_I32UtoFx4:     fpop = Pavfp_CVTU2F;  goto do_32Fx4_unary;
4983       case Iop_I32StoFx4:     fpop = Pavfp_CVTS2F;  goto do_32Fx4_unary;
4984       case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
4985       case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
4986       case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM;  goto do_32Fx4_unary;
4987       case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP;  goto do_32Fx4_unary;
4988       case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN;  goto do_32Fx4_unary;
4989       case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ;  goto do_32Fx4_unary;
4990       do_32Fx4_unary:
4991       {
4992          HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4993          HReg dst = newVRegV(env);
4994          addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
4995          return dst;
4996       }
4997 
4998       case Iop_32UtoV128: {
4999          HReg r_aligned16, r_zeros;
5000          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5001          HReg   dst = newVRegV(env);
5002          PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5003          sub_from_sp( env, 32 );     // Move SP down
5004 
5005          /* Get a quadword aligned address within our stack space */
5006          r_aligned16 = get_sp_aligned16( env );
5007          am_off0  = PPCAMode_IR( 0,  r_aligned16 );
5008          am_off4  = PPCAMode_IR( 4,  r_aligned16 );
5009          am_off8  = PPCAMode_IR( 8,  r_aligned16 );
5010          am_off12 = PPCAMode_IR( 12, r_aligned16 );
5011 
5012          /* Store zeros */
5013          r_zeros = newVRegI(env);
5014          addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
5015          if (IEndianess == Iend_LE)
5016             addInstr(env, PPCInstr_Store( 4, am_off0, r_src, mode64 ));
5017          else
5018             addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
5019          addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
5020          addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
5021 
5022          /* Store r_src in low word of quadword-aligned mem */
5023          if (IEndianess == Iend_LE)
5024             addInstr(env, PPCInstr_Store( 4, am_off12, r_zeros, mode64 ));
5025          else
5026             addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
5027 
5028          /* Load word into low word of quadword vector reg */
5029          if (IEndianess == Iend_LE)
5030             addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off0 ));
5031          else
5032             addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
5033 
5034          add_to_sp( env, 32 );       // Reset SP
5035          return dst;
5036       }
5037 
5038       case Iop_Dup8x16:
5039       case Iop_Dup16x8:
5040       case Iop_Dup32x4:
5041          return mk_AvDuplicateRI(env, e->Iex.Unop.arg, IEndianess);
5042 
5043       case Iop_CipherSV128: op = Pav_CIPHERSUBV128; goto do_AvCipherV128Un;
5044       do_AvCipherV128Un: {
5045          HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5046          HReg dst = newVRegV(env);
5047          addInstr(env, PPCInstr_AvCipherV128Unary(op, dst, arg));
5048          return dst;
5049       }
5050 
5051       case Iop_Clz8x16: op = Pav_ZEROCNTBYTE;   goto do_zerocnt;
5052       case Iop_Clz16x8: op = Pav_ZEROCNTHALF;   goto do_zerocnt;
5053       case Iop_Clz32x4: op = Pav_ZEROCNTWORD;   goto do_zerocnt;
5054       case Iop_Clz64x2: op = Pav_ZEROCNTDBL;    goto do_zerocnt;
5055       case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE;  goto do_zerocnt;
5056       do_zerocnt:
5057       {
5058         HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5059         HReg dst = newVRegV(env);
5060         addInstr(env, PPCInstr_AvUnary(op, dst, arg));
5061         return dst;
5062       }
5063 
5064       default:
5065          break;
5066       } /* switch (e->Iex.Unop.op) */
5067    } /* if (e->tag == Iex_Unop) */
5068 
5069    if (e->tag == Iex_Binop) {
5070       switch (e->Iex.Binop.op) {
5071 
5072       case Iop_64HLtoV128: {
5073          if (!mode64) {
5074             HReg     r3, r2, r1, r0, r_aligned16;
5075             PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5076             HReg     dst = newVRegV(env);
5077             /* do this via the stack (easy, convenient, etc) */
5078             sub_from_sp( env, 32 );        // Move SP down
5079 
5080             // get a quadword aligned address within our stack space
5081             r_aligned16 = get_sp_aligned16( env );
5082             am_off0  = PPCAMode_IR( 0,  r_aligned16 );
5083             am_off4  = PPCAMode_IR( 4,  r_aligned16 );
5084             am_off8  = PPCAMode_IR( 8,  r_aligned16 );
5085             am_off12 = PPCAMode_IR( 12, r_aligned16 );
5086 
5087             /* Do the less significant 64 bits */
5088             iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2, IEndianess);
5089             addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
5090             addInstr(env, PPCInstr_Store( 4, am_off8,  r1, mode64 ));
5091             /* Do the more significant 64 bits */
5092             iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1, IEndianess);
5093             addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
5094             addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
5095 
5096             /* Fetch result back from stack. */
5097             addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5098 
5099             add_to_sp( env, 32 );          // Reset SP
5100             return dst;
5101          } else {
5102             HReg     rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5103             HReg     rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5104             HReg     dst = newVRegV(env);
5105             HReg     r_aligned16;
5106             PPCAMode *am_off0, *am_off8;
5107             /* do this via the stack (easy, convenient, etc) */
5108             sub_from_sp( env, 32 );        // Move SP down
5109 
5110             // get a quadword aligned address within our stack space
5111             r_aligned16 = get_sp_aligned16( env );
5112             am_off0  = PPCAMode_IR( 0,  r_aligned16 );
5113             am_off8  = PPCAMode_IR( 8,  r_aligned16 );
5114 
5115             /* Store 2*I64 to stack */
5116             if (IEndianess == Iend_LE) {
5117                addInstr(env, PPCInstr_Store( 8, am_off0, rLo, mode64 ));
5118                addInstr(env, PPCInstr_Store( 8, am_off8, rHi, mode64 ));
5119             } else {
5120                addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
5121                addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
5122             }
5123             /* Fetch result back from stack. */
5124             addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5125 
5126             add_to_sp( env, 32 );          // Reset SP
5127             return dst;
5128          }
5129       }
5130 
5131       case Iop_Max32Fx4:   fpop = Pavfp_MAXF;   goto do_32Fx4;
5132       case Iop_Min32Fx4:   fpop = Pavfp_MINF;   goto do_32Fx4;
5133       case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
5134       case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
5135       case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
5136       do_32Fx4:
5137       {
5138          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5139          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5140          HReg dst = newVRegV(env);
5141          addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5142          return dst;
5143       }
5144 
5145       case Iop_CmpLE32Fx4: {
5146          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5147          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5148          HReg dst = newVRegV(env);
5149 
5150          /* stay consistent with native ppc compares:
5151             if a left/right lane holds a nan, return zeros for that lane
5152             so: le == NOT(gt OR isNan)
5153           */
5154          HReg isNanLR = newVRegV(env);
5155          HReg isNanL = isNan(env, argL, IEndianess);
5156          HReg isNanR = isNan(env, argR, IEndianess);
5157          addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
5158                                          isNanL, isNanR));
5159 
5160          addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
5161                                            argL, argR));
5162          addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
5163          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5164          return dst;
5165       }
5166 
5167       case Iop_AndV128:    op = Pav_AND;      goto do_AvBin;
5168       case Iop_OrV128:     op = Pav_OR;       goto do_AvBin;
5169       case Iop_XorV128:    op = Pav_XOR;      goto do_AvBin;
5170       do_AvBin: {
5171          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5172          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5173          HReg dst  = newVRegV(env);
5174          addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
5175          return dst;
5176       }
5177 
5178       case Iop_Shl8x16:    op = Pav_SHL;    goto do_AvBin8x16;
5179       case Iop_Shr8x16:    op = Pav_SHR;    goto do_AvBin8x16;
5180       case Iop_Sar8x16:    op = Pav_SAR;    goto do_AvBin8x16;
5181       case Iop_Rol8x16:    op = Pav_ROTL;   goto do_AvBin8x16;
5182       case Iop_InterleaveHI8x16: op = Pav_MRGHI;  goto do_AvBin8x16;
5183       case Iop_InterleaveLO8x16: op = Pav_MRGLO;  goto do_AvBin8x16;
5184       case Iop_Add8x16:    op = Pav_ADDU;   goto do_AvBin8x16;
5185       case Iop_QAdd8Ux16:  op = Pav_QADDU;  goto do_AvBin8x16;
5186       case Iop_QAdd8Sx16:  op = Pav_QADDS;  goto do_AvBin8x16;
5187       case Iop_Sub8x16:    op = Pav_SUBU;   goto do_AvBin8x16;
5188       case Iop_QSub8Ux16:  op = Pav_QSUBU;  goto do_AvBin8x16;
5189       case Iop_QSub8Sx16:  op = Pav_QSUBS;  goto do_AvBin8x16;
5190       case Iop_Avg8Ux16:   op = Pav_AVGU;   goto do_AvBin8x16;
5191       case Iop_Avg8Sx16:   op = Pav_AVGS;   goto do_AvBin8x16;
5192       case Iop_Max8Ux16:   op = Pav_MAXU;   goto do_AvBin8x16;
5193       case Iop_Max8Sx16:   op = Pav_MAXS;   goto do_AvBin8x16;
5194       case Iop_Min8Ux16:   op = Pav_MINU;   goto do_AvBin8x16;
5195       case Iop_Min8Sx16:   op = Pav_MINS;   goto do_AvBin8x16;
5196       case Iop_MullEven8Ux16: op = Pav_OMULU;  goto do_AvBin8x16;
5197       case Iop_MullEven8Sx16: op = Pav_OMULS;  goto do_AvBin8x16;
5198       case Iop_CmpEQ8x16:  op = Pav_CMPEQU; goto do_AvBin8x16;
5199       case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
5200       case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
5201       case Iop_PolynomialMulAdd8x16: op = Pav_POLYMULADD; goto do_AvBin8x16;
5202       do_AvBin8x16: {
5203          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5204          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5205          HReg dst  = newVRegV(env);
5206          addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
5207          return dst;
5208       }
5209 
5210       case Iop_Shl16x8:    op = Pav_SHL;    goto do_AvBin16x8;
5211       case Iop_Shr16x8:    op = Pav_SHR;    goto do_AvBin16x8;
5212       case Iop_Sar16x8:    op = Pav_SAR;    goto do_AvBin16x8;
5213       case Iop_Rol16x8:    op = Pav_ROTL;   goto do_AvBin16x8;
5214       case Iop_NarrowBin16to8x16:    op = Pav_PACKUU;  goto do_AvBin16x8;
5215       case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8;
5216       case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8;
5217       case Iop_InterleaveHI16x8:  op = Pav_MRGHI;  goto do_AvBin16x8;
5218       case Iop_InterleaveLO16x8:  op = Pav_MRGLO;  goto do_AvBin16x8;
5219       case Iop_Add16x8:    op = Pav_ADDU;   goto do_AvBin16x8;
5220       case Iop_QAdd16Ux8:  op = Pav_QADDU;  goto do_AvBin16x8;
5221       case Iop_QAdd16Sx8:  op = Pav_QADDS;  goto do_AvBin16x8;
5222       case Iop_Sub16x8:    op = Pav_SUBU;   goto do_AvBin16x8;
5223       case Iop_QSub16Ux8:  op = Pav_QSUBU;  goto do_AvBin16x8;
5224       case Iop_QSub16Sx8:  op = Pav_QSUBS;  goto do_AvBin16x8;
5225       case Iop_Avg16Ux8:   op = Pav_AVGU;   goto do_AvBin16x8;
5226       case Iop_Avg16Sx8:   op = Pav_AVGS;   goto do_AvBin16x8;
5227       case Iop_Max16Ux8:   op = Pav_MAXU;   goto do_AvBin16x8;
5228       case Iop_Max16Sx8:   op = Pav_MAXS;   goto do_AvBin16x8;
5229       case Iop_Min16Ux8:   op = Pav_MINU;   goto do_AvBin16x8;
5230       case Iop_Min16Sx8:   op = Pav_MINS;   goto do_AvBin16x8;
5231       case Iop_MullEven16Ux8: op = Pav_OMULU;  goto do_AvBin16x8;
5232       case Iop_MullEven16Sx8: op = Pav_OMULS;  goto do_AvBin16x8;
5233       case Iop_CmpEQ16x8:  op = Pav_CMPEQU; goto do_AvBin16x8;
5234       case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
5235       case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
5236       case Iop_PolynomialMulAdd16x8: op = Pav_POLYMULADD; goto do_AvBin16x8;
5237       do_AvBin16x8: {
5238          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5239          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5240          HReg dst  = newVRegV(env);
5241          addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
5242          return dst;
5243       }
5244 
5245       case Iop_Shl32x4:    op = Pav_SHL;    goto do_AvBin32x4;
5246       case Iop_Shr32x4:    op = Pav_SHR;    goto do_AvBin32x4;
5247       case Iop_Sar32x4:    op = Pav_SAR;    goto do_AvBin32x4;
5248       case Iop_Rol32x4:    op = Pav_ROTL;   goto do_AvBin32x4;
5249       case Iop_NarrowBin32to16x8:    op = Pav_PACKUU;  goto do_AvBin32x4;
5250       case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4;
5251       case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4;
5252       case Iop_InterleaveHI32x4:  op = Pav_MRGHI;  goto do_AvBin32x4;
5253       case Iop_InterleaveLO32x4:  op = Pav_MRGLO;  goto do_AvBin32x4;
5254       case Iop_Add32x4:    op = Pav_ADDU;   goto do_AvBin32x4;
5255       case Iop_QAdd32Ux4:  op = Pav_QADDU;  goto do_AvBin32x4;
5256       case Iop_QAdd32Sx4:  op = Pav_QADDS;  goto do_AvBin32x4;
5257       case Iop_Sub32x4:    op = Pav_SUBU;   goto do_AvBin32x4;
5258       case Iop_QSub32Ux4:  op = Pav_QSUBU;  goto do_AvBin32x4;
5259       case Iop_QSub32Sx4:  op = Pav_QSUBS;  goto do_AvBin32x4;
5260       case Iop_Avg32Ux4:   op = Pav_AVGU;   goto do_AvBin32x4;
5261       case Iop_Avg32Sx4:   op = Pav_AVGS;   goto do_AvBin32x4;
5262       case Iop_Max32Ux4:   op = Pav_MAXU;   goto do_AvBin32x4;
5263       case Iop_Max32Sx4:   op = Pav_MAXS;   goto do_AvBin32x4;
5264       case Iop_Min32Ux4:   op = Pav_MINU;   goto do_AvBin32x4;
5265       case Iop_Min32Sx4:   op = Pav_MINS;   goto do_AvBin32x4;
5266       case Iop_Mul32x4:    op = Pav_MULU;   goto do_AvBin32x4;
5267       case Iop_MullEven32Ux4: op = Pav_OMULU;  goto do_AvBin32x4;
5268       case Iop_MullEven32Sx4: op = Pav_OMULS;  goto do_AvBin32x4;
5269       case Iop_CmpEQ32x4:  op = Pav_CMPEQU; goto do_AvBin32x4;
5270       case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
5271       case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
5272       case Iop_CatOddLanes32x4:  op = Pav_CATODD;  goto do_AvBin32x4;
5273       case Iop_CatEvenLanes32x4: op = Pav_CATEVEN; goto do_AvBin32x4;
5274       case Iop_PolynomialMulAdd32x4: op = Pav_POLYMULADD; goto do_AvBin32x4;
5275       do_AvBin32x4: {
5276          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5277          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5278          HReg dst  = newVRegV(env);
5279          addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
5280          return dst;
5281       }
5282 
5283       case Iop_Shl64x2:    op = Pav_SHL;    goto do_AvBin64x2;
5284       case Iop_Shr64x2:    op = Pav_SHR;    goto do_AvBin64x2;
5285       case Iop_Sar64x2:    op = Pav_SAR;    goto do_AvBin64x2;
5286       case Iop_Rol64x2:    op = Pav_ROTL;   goto do_AvBin64x2;
5287       case Iop_NarrowBin64to32x4:    op = Pav_PACKUU;  goto do_AvBin64x2;
5288       case Iop_QNarrowBin64Sto32Sx4: op = Pav_QPACKSS; goto do_AvBin64x2;
5289       case Iop_QNarrowBin64Uto32Ux4: op = Pav_QPACKUU; goto do_AvBin64x2;
5290       case Iop_InterleaveHI64x2:  op = Pav_MRGHI;  goto do_AvBin64x2;
5291       case Iop_InterleaveLO64x2:  op = Pav_MRGLO;  goto do_AvBin64x2;
5292       case Iop_Add64x2:    op = Pav_ADDU;   goto do_AvBin64x2;
5293       case Iop_Sub64x2:    op = Pav_SUBU;   goto do_AvBin64x2;
5294       case Iop_Max64Ux2:   op = Pav_MAXU;   goto do_AvBin64x2;
5295       case Iop_Max64Sx2:   op = Pav_MAXS;   goto do_AvBin64x2;
5296       case Iop_Min64Ux2:   op = Pav_MINU;   goto do_AvBin64x2;
5297       case Iop_Min64Sx2:   op = Pav_MINS;   goto do_AvBin64x2;
5298       case Iop_CmpEQ64x2:  op = Pav_CMPEQU; goto do_AvBin64x2;
5299       case Iop_CmpGT64Ux2: op = Pav_CMPGTU; goto do_AvBin64x2;
5300       case Iop_CmpGT64Sx2: op = Pav_CMPGTS; goto do_AvBin64x2;
5301       case Iop_PolynomialMulAdd64x2: op = Pav_POLYMULADD; goto do_AvBin64x2;
5302       do_AvBin64x2: {
5303          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5304          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5305          HReg dst  = newVRegV(env);
5306          addInstr(env, PPCInstr_AvBin64x2(op, dst, arg1, arg2));
5307          return dst;
5308       }
5309 
5310       case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
5311       case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
5312       do_AvShift8x16: {
5313          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5314          HReg dst    = newVRegV(env);
5315          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5316          addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
5317          return dst;
5318       }
5319 
5320       case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
5321       case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
5322       case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
5323       do_AvShift16x8: {
5324          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5325          HReg dst    = newVRegV(env);
5326          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5327          addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
5328          return dst;
5329       }
5330 
5331       case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
5332       case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
5333       case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
5334       do_AvShift32x4: {
5335          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5336          HReg dst    = newVRegV(env);
5337          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5338          addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
5339          return dst;
5340       }
5341 
5342       case Iop_ShlN64x2: op = Pav_SHL; goto do_AvShift64x2;
5343       case Iop_ShrN64x2: op = Pav_SHR; goto do_AvShift64x2;
5344       case Iop_SarN64x2: op = Pav_SAR; goto do_AvShift64x2;
5345       do_AvShift64x2: {
5346          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5347          HReg dst    = newVRegV(env);
5348          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5349          addInstr(env, PPCInstr_AvBin64x2(op, dst, r_src, v_shft));
5350          return dst;
5351       }
5352 
5353       case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
5354       case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
5355       do_AvShiftV128: {
5356          HReg dst    = newVRegV(env);
5357          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5358          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5359          /* Note: shift value gets masked by 127 */
5360          addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
5361          return dst;
5362       }
5363 
5364       case Iop_Perm8x16: {
5365          HReg dst   = newVRegV(env);
5366          HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5367          HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5368          addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
5369          return dst;
5370       }
5371 
5372       case Iop_CipherV128:  op = Pav_CIPHERV128;   goto do_AvCipherV128;
5373       case Iop_CipherLV128: op = Pav_CIPHERLV128;  goto do_AvCipherV128;
5374       case Iop_NCipherV128: op = Pav_NCIPHERV128;  goto do_AvCipherV128;
5375       case Iop_NCipherLV128:op = Pav_NCIPHERLV128; goto do_AvCipherV128;
5376       do_AvCipherV128: {
5377          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5378          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5379          HReg dst  = newVRegV(env);
5380          addInstr(env, PPCInstr_AvCipherV128Binary(op, dst, arg1, arg2));
5381          return dst;
5382       }
5383 
5384       case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128;
5385       case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128;
5386       do_AvHashV128: {
5387          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5388          HReg dst  = newVRegV(env);
5389          PPCRI* s_field = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
5390          addInstr(env, PPCInstr_AvHashV128Binary(op, dst, arg1, s_field));
5391          return dst;
5392       }
5393       default:
5394          break;
5395       } /* switch (e->Iex.Binop.op) */
5396    } /* if (e->tag == Iex_Binop) */
5397 
5398    if (e->tag == Iex_Triop) {
5399       IRTriop *triop = e->Iex.Triop.details;
5400       switch (triop->op) {
5401       case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
5402       case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
5403       do_AvBCDV128: {
5404          HReg arg1 = iselVecExpr(env, triop->arg1, IEndianess);
5405          HReg arg2 = iselVecExpr(env, triop->arg2, IEndianess);
5406          HReg dst  = newVRegV(env);
5407          PPCRI* ps = iselWordExpr_RI(env, triop->arg3, IEndianess);
5408          addInstr(env, PPCInstr_AvBCDV128Trinary(op, dst, arg1, arg2, ps));
5409          return dst;
5410       }
5411 
5412       case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4_with_rm;
5413       case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4_with_rm;
5414       case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4_with_rm;
5415       do_32Fx4_with_rm:
5416       {
5417          HReg argL = iselVecExpr(env, triop->arg2, IEndianess);
5418          HReg argR = iselVecExpr(env, triop->arg3, IEndianess);
5419          HReg dst  = newVRegV(env);
5420          /* FIXME: this is bogus, in the sense that Altivec ignores
5421             FPSCR.RM, at least for some FP operations.  So setting the
5422             RM is pointless.  This is only really correct in the case
5423             where the RM is known, at JIT time, to be Irrm_NEAREST,
5424             since -- at least for Altivec FP add/sub/mul -- the
5425             emitted insn is hardwired to round to nearest. */
5426          set_FPU_rounding_mode(env, triop->arg1, IEndianess);
5427          addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5428          return dst;
5429       }
5430 
5431       default:
5432          break;
5433       } /* switch (e->Iex.Triop.op) */
5434    } /* if (e->tag == Iex_Trinop) */
5435 
5436 
5437    if (e->tag == Iex_Const ) {
5438       vassert(e->Iex.Const.con->tag == Ico_V128);
5439       if (e->Iex.Const.con->Ico.V128 == 0x0000) {
5440          return generate_zeroes_V128(env);
5441       }
5442       else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
5443          return generate_ones_V128(env);
5444       }
5445    }
5446 
5447    vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
5448               LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
5449                                  env->hwcaps));
5450    ppIRExpr(e);
5451    vpanic("iselVecExpr_wrk(ppc)");
5452 }
5453 
5454 
5455 /*---------------------------------------------------------*/
5456 /*--- ISEL: Statements                                  ---*/
5457 /*---------------------------------------------------------*/
5458 
iselStmt(ISelEnv * env,IRStmt * stmt,IREndness IEndianess)5459 static void iselStmt ( ISelEnv* env, IRStmt* stmt, IREndness IEndianess )
5460 {
5461    Bool mode64 = env->mode64;
5462    if (vex_traceflags & VEX_TRACE_VCODE) {
5463       vex_printf("\n -- ");
5464       ppIRStmt(stmt);
5465       vex_printf("\n");
5466    }
5467 
5468    switch (stmt->tag) {
5469 
5470    /* --------- STORE --------- */
5471    case Ist_Store: {
5472       IRType    tya   = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
5473       IRType    tyd   = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
5474       IREndness end   = stmt->Ist.Store.end;
5475 
5476       if (end != IEndianess)
5477          goto stmt_fail;
5478       if (!mode64 && (tya != Ity_I32))
5479          goto stmt_fail;
5480       if (mode64 && (tya != Ity_I64))
5481          goto stmt_fail;
5482 
5483       if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
5484           (mode64 && (tyd == Ity_I64))) {
5485          PPCAMode* am_addr
5486             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5487                                  IEndianess);
5488          HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data, IEndianess);
5489          addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
5490                                        am_addr, r_src, mode64 ));
5491          return;
5492       }
5493       if (tyd == Ity_F64) {
5494          PPCAMode* am_addr
5495             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5496                                  IEndianess);
5497          HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess);
5498          addInstr(env,
5499                   PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5500          return;
5501       }
5502       if (tyd == Ity_F32) {
5503          PPCAMode* am_addr
5504             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5505                                  IEndianess);
5506          HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess);
5507          addInstr(env,
5508                   PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5509          return;
5510       }
5511       if (tyd == Ity_D64) {
5512          PPCAMode* am_addr
5513             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5514                                  IEndianess);
5515          HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess);
5516          addInstr(env,
5517                   PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5518          return;
5519       }
5520       if (tyd == Ity_D32) {
5521          PPCAMode* am_addr
5522             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5523                                  IEndianess);
5524          HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess);
5525          addInstr(env,
5526                   PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5527          return;
5528       }
5529       if (tyd == Ity_V128) {
5530          PPCAMode* am_addr
5531             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5532                                  IEndianess);
5533          HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess);
5534          addInstr(env,
5535                   PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5536          return;
5537       }
5538       if (tyd == Ity_I64 && !mode64) {
5539          /* Just calculate the address in the register.  Life is too
5540             short to arse around trying and possibly failing to adjust
5541             the offset in a 'reg+offset' style amode. */
5542          HReg rHi32, rLo32;
5543          HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess);
5544          iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data,
5545                         IEndianess );
5546          addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5547                                        PPCAMode_IR( 0, r_addr ),
5548                                        rHi32,
5549                                        False/*32-bit insn please*/) );
5550          addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5551                                        PPCAMode_IR( 4, r_addr ),
5552                                        rLo32,
5553                                        False/*32-bit insn please*/) );
5554          return;
5555       }
5556       break;
5557    }
5558 
5559    /* --------- PUT --------- */
5560    case Ist_Put: {
5561       IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
5562       if (ty == Ity_I8  || ty == Ity_I16 ||
5563           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5564          HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data, IEndianess);
5565          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5566                                           GuestStatePtr(mode64) );
5567          addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
5568                                        am_addr, r_src, mode64 ));
5569          return;
5570       }
5571       if (!mode64 && ty == Ity_I64) {
5572          HReg rHi, rLo;
5573          PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
5574                                            GuestStatePtr(mode64) );
5575          PPCAMode* am_addr4 = advance4(env, am_addr);
5576          iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
5577          addInstr(env, PPCInstr_Store( 4, am_addr,  rHi, mode64 ));
5578          addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
5579          return;
5580      }
5581      if (ty == Ity_V128) {
5582          /* Guest state vectors are 16byte aligned,
5583             so don't need to worry here */
5584          HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess);
5585          PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
5586                                            GuestStatePtr(mode64) );
5587          addInstr(env,
5588                   PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5589          return;
5590       }
5591       if (ty == Ity_F64) {
5592          HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data, IEndianess);
5593          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5594                                           GuestStatePtr(mode64) );
5595          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
5596                                         fr_src, am_addr ));
5597          return;
5598       }
5599       if (ty == Ity_D32) {
5600          /* The 32-bit value is stored in a 64-bit register */
5601          HReg fr_src = iselDfp32Expr( env, stmt->Ist.Put.data, IEndianess );
5602          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5603                                           GuestStatePtr(mode64) );
5604          addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8,
5605                                          fr_src, am_addr ) );
5606          return;
5607       }
5608       if (ty == Ity_D64) {
5609          HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data, IEndianess );
5610          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5611                                           GuestStatePtr(mode64) );
5612          addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) );
5613          return;
5614       }
5615       break;
5616    }
5617 
5618    /* --------- Indexed PUT --------- */
5619    case Ist_PutI: {
5620       IRPutI *puti = stmt->Ist.PutI.details;
5621 
5622       PPCAMode* dst_am
5623          = genGuestArrayOffset(
5624               env, puti->descr,
5625               puti->ix, puti->bias,
5626               IEndianess );
5627       IRType ty = typeOfIRExpr(env->type_env, puti->data);
5628       if (mode64 && ty == Ity_I64) {
5629          HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5630          addInstr(env, PPCInstr_Store( toUChar(8),
5631                                        dst_am, r_src, mode64 ));
5632          return;
5633       }
5634       if ((!mode64) && ty == Ity_I32) {
5635          HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5636          addInstr(env, PPCInstr_Store( toUChar(4),
5637                                        dst_am, r_src, mode64 ));
5638          return;
5639       }
5640       break;
5641    }
5642 
5643    /* --------- TMP --------- */
5644    case Ist_WrTmp: {
5645       IRTemp tmp = stmt->Ist.WrTmp.tmp;
5646       IRType ty = typeOfIRTemp(env->type_env, tmp);
5647       if (ty == Ity_I8  || ty == Ity_I16 ||
5648           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5649          HReg r_dst = lookupIRTemp(env, tmp);
5650          HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data, IEndianess);
5651          addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
5652          return;
5653       }
5654       if (!mode64 && ty == Ity_I64) {
5655          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5656 
5657          iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5658                        IEndianess);
5659          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5660          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5661          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5662          return;
5663       }
5664       if (mode64 && ty == Ity_I128) {
5665          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5666          iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5667                         IEndianess);
5668          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5669          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5670          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5671          return;
5672       }
5673       if (!mode64 && ty == Ity_I128) {
5674          HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo;
5675          HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo;
5676 
5677          iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi,
5678                                 &r_srcMedLo, &r_srcLo,
5679                                 env, stmt->Ist.WrTmp.data, IEndianess);
5680 
5681          lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo,
5682                            &r_dstLo, env, tmp);
5683 
5684          addInstr(env, mk_iMOVds_RR(r_dstHi,    r_srcHi) );
5685          addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) );
5686          addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) );
5687          addInstr(env, mk_iMOVds_RR(r_dstLo,    r_srcLo) );
5688          return;
5689       }
5690       if (ty == Ity_I1) {
5691          PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data,
5692                                          IEndianess);
5693          HReg r_dst = lookupIRTemp(env, tmp);
5694          addInstr(env, PPCInstr_Set(cond, r_dst));
5695          return;
5696       }
5697       if (ty == Ity_F64) {
5698          HReg fr_dst = lookupIRTemp(env, tmp);
5699          HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5700          addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5701          return;
5702       }
5703       if (ty == Ity_F32) {
5704          HReg fr_dst = lookupIRTemp(env, tmp);
5705          HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5706          addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5707          return;
5708       }
5709       if (ty == Ity_D32) {
5710          HReg fr_dst = lookupIRTemp(env, tmp);
5711          HReg fr_src = iselDfp32Expr(env, stmt->Ist.WrTmp.data, IEndianess);
5712          addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src));
5713          return;
5714       }
5715       if (ty == Ity_V128) {
5716          HReg v_dst = lookupIRTemp(env, tmp);
5717          HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5718          addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
5719          return;
5720       }
5721       if (ty == Ity_D64) {
5722          HReg fr_dst = lookupIRTemp( env, tmp );
5723          HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data, IEndianess );
5724          addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) );
5725          return;
5726       }
5727       if (ty == Ity_D128) {
5728          HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo;
5729 	 //         lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5730          lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5731          iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data,
5732                          IEndianess );
5733          addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
5734          addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
5735          return;
5736       }
5737       break;
5738    }
5739 
5740    /* --------- Load Linked or Store Conditional --------- */
5741    case Ist_LLSC: {
5742       IRTemp res    = stmt->Ist.LLSC.result;
5743       IRType tyRes  = typeOfIRTemp(env->type_env, res);
5744       IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
5745 
5746       if (stmt->Ist.LLSC.end != IEndianess)
5747          goto stmt_fail;
5748       if (!mode64 && (tyAddr != Ity_I32))
5749          goto stmt_fail;
5750       if (mode64 && (tyAddr != Ity_I64))
5751          goto stmt_fail;
5752 
5753       if (stmt->Ist.LLSC.storedata == NULL) {
5754          /* LL */
5755          HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr, IEndianess );
5756          HReg r_dst  = lookupIRTemp(env, res);
5757          if (tyRes == Ity_I8) {
5758             addInstr(env, PPCInstr_LoadL( 1, r_dst, r_addr, mode64 ));
5759             return;
5760          }
5761          if (tyRes == Ity_I16) {
5762             addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 ));
5763             return;
5764          }
5765          if (tyRes == Ity_I32) {
5766             addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
5767             return;
5768          }
5769          if (tyRes == Ity_I64 && mode64) {
5770             addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
5771             return;
5772          }
5773          /* fallthru */;
5774       } else {
5775          /* SC */
5776          HReg   r_res  = lookupIRTemp(env, res); /* :: Ity_I1 */
5777          HReg   r_a    = iselWordExpr_R(env, stmt->Ist.LLSC.addr, IEndianess);
5778          HReg   r_src  = iselWordExpr_R(env, stmt->Ist.LLSC.storedata,
5779                                         IEndianess);
5780          HReg   r_tmp  = newVRegI(env);
5781          IRType tyData = typeOfIRExpr(env->type_env,
5782                                       stmt->Ist.LLSC.storedata);
5783          vassert(tyRes == Ity_I1);
5784          if (tyData == Ity_I8 || tyData == Ity_I16 || tyData == Ity_I32 ||
5785             (tyData == Ity_I64 && mode64)) {
5786             int size = 0;
5787 
5788             if (tyData == Ity_I64)
5789                size = 8;
5790             else if (tyData == Ity_I32)
5791                size = 4;
5792             else if (tyData == Ity_I16)
5793                size = 2;
5794             else if (tyData == Ity_I8)
5795                size = 1;
5796 
5797             addInstr(env, PPCInstr_StoreC( size,
5798                                            r_a, r_src, mode64 ));
5799             addInstr(env, PPCInstr_MfCR( r_tmp ));
5800             addInstr(env, PPCInstr_Shft(
5801                              Pshft_SHR,
5802                              env->mode64 ? False : True
5803                                 /*F:64-bit, T:32-bit shift*/,
5804                              r_tmp, r_tmp,
5805                              PPCRH_Imm(False/*unsigned*/, 29)));
5806             /* Probably unnecessary, since the IR dest type is Ity_I1,
5807                and so we are entitled to leave whatever junk we like
5808                drifting round in the upper 31 or 63 bits of r_res.
5809                However, for the sake of conservativeness .. */
5810             addInstr(env, PPCInstr_Alu(
5811                              Palu_AND,
5812                              r_res, r_tmp,
5813                              PPCRH_Imm(False/*signed*/, 1)));
5814             return;
5815          }
5816          /* fallthru */
5817       }
5818       goto stmt_fail;
5819       /*NOTREACHED*/
5820    }
5821 
5822    /* --------- Call to DIRTY helper --------- */
5823    case Ist_Dirty: {
5824       IRDirty* d = stmt->Ist.Dirty.details;
5825 
5826       /* Figure out the return type, if any. */
5827       IRType retty = Ity_INVALID;
5828       if (d->tmp != IRTemp_INVALID)
5829          retty = typeOfIRTemp(env->type_env, d->tmp);
5830 
5831       /* Throw out any return types we don't know about.  The set of
5832          acceptable return types is the same in both 32- and 64-bit
5833          mode, so we don't need to inspect mode64 to make a
5834          decision. */
5835       Bool retty_ok = False;
5836       switch (retty) {
5837          case Ity_INVALID: /* function doesn't return anything */
5838          case Ity_V128:
5839          case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
5840             retty_ok = True; break;
5841          default:
5842             break;
5843       }
5844       if (!retty_ok)
5845          break; /* will go to stmt_fail: */
5846 
5847       /* Marshal args, do the call, clear stack, set the return value
5848          to 0x555..555 if this is a conditional call that returns a
5849          value and the call is skipped. */
5850       UInt   addToSp = 0;
5851       RetLoc rloc    = mk_RetLoc_INVALID();
5852       doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args,
5853                     IEndianess );
5854       vassert(is_sane_RetLoc(rloc));
5855 
5856       /* Now figure out what to do with the returned value, if any. */
5857       switch (retty) {
5858          case Ity_INVALID: {
5859             /* No return value.  Nothing to do. */
5860             vassert(d->tmp == IRTemp_INVALID);
5861             vassert(rloc.pri == RLPri_None);
5862             vassert(addToSp == 0);
5863             return;
5864          }
5865          case Ity_I32: case Ity_I16: case Ity_I8: {
5866             /* The returned value is in %r3.  Park it in the register
5867                associated with tmp. */
5868             HReg r_dst = lookupIRTemp(env, d->tmp);
5869             addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5870             vassert(rloc.pri == RLPri_Int);
5871             vassert(addToSp == 0);
5872             return;
5873          }
5874          case Ity_I64:
5875             if (mode64) {
5876                /* The returned value is in %r3.  Park it in the register
5877                   associated with tmp. */
5878                HReg r_dst = lookupIRTemp(env, d->tmp);
5879                addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5880                vassert(rloc.pri == RLPri_Int);
5881                vassert(addToSp == 0);
5882             } else {
5883                /* The returned value is in %r3:%r4.  Park it in the
5884                   register-pair associated with tmp. */
5885                HReg r_dstHi = INVALID_HREG;
5886                HReg r_dstLo = INVALID_HREG;
5887                lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
5888                addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
5889                addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
5890                vassert(rloc.pri == RLPri_2Int);
5891                vassert(addToSp == 0);
5892             }
5893             return;
5894          case Ity_V128: {
5895             /* The returned value is on the stack, and *retloc tells
5896                us where.  Fish it off the stack and then move the
5897                stack pointer upwards to clear it, as directed by
5898                doHelperCall. */
5899             vassert(rloc.pri == RLPri_V128SpRel);
5900             vassert(addToSp >= 16);
5901             HReg      dst = lookupIRTemp(env, d->tmp);
5902             PPCAMode* am  = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64));
5903             addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am ));
5904             add_to_sp(env, addToSp);
5905             return;
5906          }
5907          default:
5908             /*NOTREACHED*/
5909             vassert(0);
5910       }
5911    }
5912 
5913    /* --------- MEM FENCE --------- */
5914    case Ist_MBE:
5915       switch (stmt->Ist.MBE.event) {
5916          case Imbe_Fence:
5917             addInstr(env, PPCInstr_MFence());
5918             return;
5919          default:
5920             break;
5921       }
5922       break;
5923 
5924    /* --------- INSTR MARK --------- */
5925    /* Doesn't generate any executable code ... */
5926    case Ist_IMark:
5927        return;
5928 
5929    /* --------- ABI HINT --------- */
5930    /* These have no meaning (denotation in the IR) and so we ignore
5931       them ... if any actually made it this far. */
5932    case Ist_AbiHint:
5933        return;
5934 
5935    /* --------- NO-OP --------- */
5936    /* Fairly self-explanatory, wouldn't you say? */
5937    case Ist_NoOp:
5938        return;
5939 
5940    /* --------- EXIT --------- */
5941    case Ist_Exit: {
5942       IRConst* dst = stmt->Ist.Exit.dst;
5943       if (!mode64 && dst->tag != Ico_U32)
5944          vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
5945       if (mode64 && dst->tag != Ico_U64)
5946          vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
5947 
5948       PPCCondCode cc    = iselCondCode(env, stmt->Ist.Exit.guard, IEndianess);
5949       PPCAMode*   amCIA = PPCAMode_IR(stmt->Ist.Exit.offsIP,
5950                                       hregPPC_GPR31(mode64));
5951 
5952       /* Case: boring transfer to known address */
5953       if (stmt->Ist.Exit.jk == Ijk_Boring
5954           || stmt->Ist.Exit.jk == Ijk_Call
5955           /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
5956          if (env->chainingAllowed) {
5957             /* .. almost always true .. */
5958             /* Skip the event check at the dst if this is a forwards
5959                edge. */
5960             Bool toFastEP
5961                = mode64
5962                ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
5963                : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
5964             if (0) vex_printf("%s", toFastEP ? "Y" : ",");
5965             addInstr(env, PPCInstr_XDirect(
5966                              mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
5967                                     : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
5968                              amCIA, cc, toFastEP));
5969          } else {
5970             /* .. very occasionally .. */
5971             /* We can't use chaining, so ask for an assisted transfer,
5972                as that's the only alternative that is allowable. */
5973             HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5974                                     IEndianess);
5975             addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring));
5976          }
5977          return;
5978       }
5979 
5980       /* Case: assisted transfer to arbitrary address */
5981       switch (stmt->Ist.Exit.jk) {
5982          /* Keep this list in sync with that in iselNext below */
5983          case Ijk_ClientReq:
5984          case Ijk_EmFail:
5985          case Ijk_EmWarn:
5986          case Ijk_NoDecode:
5987          case Ijk_NoRedir:
5988          case Ijk_SigBUS:
5989          case Ijk_SigTRAP:
5990          case Ijk_Sys_syscall:
5991          case Ijk_InvalICache:
5992          {
5993             HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5994                                     IEndianess);
5995             addInstr(env, PPCInstr_XAssisted(r, amCIA, cc,
5996                                              stmt->Ist.Exit.jk));
5997             return;
5998          }
5999          default:
6000             break;
6001       }
6002 
6003       /* Do we ever expect to see any other kind? */
6004       goto stmt_fail;
6005    }
6006 
6007    default: break;
6008    }
6009   stmt_fail:
6010    ppIRStmt(stmt);
6011    vpanic("iselStmt(ppc)");
6012 }
6013 
6014 
6015 /*---------------------------------------------------------*/
6016 /*--- ISEL: Basic block terminators (Nexts)             ---*/
6017 /*---------------------------------------------------------*/
6018 
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP,IREndness IEndianess)6019 static void iselNext ( ISelEnv* env,
6020                        IRExpr* next, IRJumpKind jk, Int offsIP,
6021                        IREndness IEndianess)
6022 {
6023    if (vex_traceflags & VEX_TRACE_VCODE) {
6024       vex_printf( "\n-- PUT(%d) = ", offsIP);
6025       ppIRExpr( next );
6026       vex_printf( "; exit-");
6027       ppIRJumpKind(jk);
6028       vex_printf( "\n");
6029    }
6030 
6031    PPCCondCode always = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
6032 
6033    /* Case: boring transfer to known address */
6034    if (next->tag == Iex_Const) {
6035       IRConst* cdst = next->Iex.Const.con;
6036       vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
6037       if (jk == Ijk_Boring || jk == Ijk_Call) {
6038          /* Boring transfer to known address */
6039          PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6040          if (env->chainingAllowed) {
6041             /* .. almost always true .. */
6042             /* Skip the event check at the dst if this is a forwards
6043                edge. */
6044             Bool toFastEP
6045                = env->mode64
6046                ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
6047                : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
6048             if (0) vex_printf("%s", toFastEP ? "X" : ".");
6049             addInstr(env, PPCInstr_XDirect(
6050                              env->mode64 ? (Addr64)cdst->Ico.U64
6051                                          : (Addr64)cdst->Ico.U32,
6052                              amCIA, always, toFastEP));
6053          } else {
6054             /* .. very occasionally .. */
6055             /* We can't use chaining, so ask for an assisted transfer,
6056                as that's the only alternative that is allowable. */
6057             HReg r = iselWordExpr_R(env, next, IEndianess);
6058             addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6059                                              Ijk_Boring));
6060          }
6061          return;
6062       }
6063    }
6064 
6065    /* Case: call/return (==boring) transfer to any address */
6066    switch (jk) {
6067       case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
6068          HReg       r     = iselWordExpr_R(env, next, IEndianess);
6069          PPCAMode*  amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6070          if (env->chainingAllowed) {
6071             addInstr(env, PPCInstr_XIndir(r, amCIA, always));
6072          } else {
6073             addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6074                                              Ijk_Boring));
6075          }
6076          return;
6077       }
6078       default:
6079          break;
6080    }
6081 
6082    /* Case: assisted transfer to arbitrary address */
6083    switch (jk) {
6084       /* Keep this list in sync with that for Ist_Exit above */
6085       case Ijk_ClientReq:
6086       case Ijk_EmFail:
6087       case Ijk_EmWarn:
6088       case Ijk_NoDecode:
6089       case Ijk_NoRedir:
6090       case Ijk_SigBUS:
6091       case Ijk_SigTRAP:
6092       case Ijk_Sys_syscall:
6093       case Ijk_InvalICache:
6094       {
6095          HReg      r     = iselWordExpr_R(env, next, IEndianess);
6096          PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6097          addInstr(env, PPCInstr_XAssisted(r, amCIA, always, jk));
6098          return;
6099       }
6100       default:
6101          break;
6102    }
6103 
6104    vex_printf( "\n-- PUT(%d) = ", offsIP);
6105    ppIRExpr( next );
6106    vex_printf( "; exit-");
6107    ppIRJumpKind(jk);
6108    vex_printf( "\n");
6109    vassert(0); // are we expecting any other kind?
6110 }
6111 
6112 
6113 /*---------------------------------------------------------*/
6114 /*--- Insn selector top-level                           ---*/
6115 /*---------------------------------------------------------*/
6116 
6117 /* Translate an entire SB to ppc code. */
iselSB_PPC(const IRSB * bb,VexArch arch_host,const VexArchInfo * archinfo_host,const VexAbiInfo * vbi,Int offs_Host_EvC_Counter,Int offs_Host_EvC_FailAddr,Bool chainingAllowed,Bool addProfInc,Addr max_ga)6118 HInstrArray* iselSB_PPC ( const IRSB* bb,
6119                           VexArch      arch_host,
6120                           const VexArchInfo* archinfo_host,
6121                           const VexAbiInfo*  vbi,
6122                           Int offs_Host_EvC_Counter,
6123                           Int offs_Host_EvC_FailAddr,
6124                           Bool chainingAllowed,
6125                           Bool addProfInc,
6126                           Addr max_ga)
6127 
6128 {
6129    Int       i, j;
6130    HReg      hregLo, hregMedLo, hregMedHi, hregHi;
6131    ISelEnv*  env;
6132    UInt      hwcaps_host = archinfo_host->hwcaps;
6133    Bool      mode64 = False;
6134    UInt      mask32, mask64;
6135    PPCAMode *amCounter, *amFailAddr;
6136    IREndness IEndianess;
6137 
6138    vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
6139    mode64 = arch_host == VexArchPPC64;
6140 
6141    /* do some sanity checks */
6142    mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
6143             | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
6144             | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
6145 
6146 
6147    mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
6148             | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
6149             | VEX_HWCAPS_PPC64_ISA2_07;
6150 
6151    if (mode64) {
6152       vassert((hwcaps_host & mask32) == 0);
6153    } else {
6154       vassert((hwcaps_host & mask64) == 0);
6155    }
6156 
6157    /* Check that the host's endianness is as expected. */
6158    vassert((archinfo_host->endness == VexEndnessBE) ||
6159 	   (archinfo_host->endness == VexEndnessLE));
6160 
6161    if (archinfo_host->endness == VexEndnessBE)
6162      IEndianess = Iend_BE;
6163    else
6164      IEndianess = Iend_LE;
6165 
6166    /* Make up an initial environment to use. */
6167    env = LibVEX_Alloc_inline(sizeof(ISelEnv));
6168    env->vreg_ctr = 0;
6169 
6170    /* Are we being ppc32 or ppc64? */
6171    env->mode64 = mode64;
6172 
6173    /* Set up output code array. */
6174    env->code = newHInstrArray();
6175 
6176    /* Copy BB's type env. */
6177    env->type_env = bb->tyenv;
6178 
6179    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
6180     * change as we go along.
6181     *
6182     * vregmap2 and vregmap3 are only used in 32 bit mode
6183     * for supporting I128 in 32-bit mode
6184     */
6185    env->n_vregmap = bb->tyenv->types_used;
6186    env->vregmapLo    = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6187    env->vregmapMedLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6188    if (mode64) {
6189       env->vregmapMedHi = NULL;
6190       env->vregmapHi    = NULL;
6191    } else {
6192       env->vregmapMedHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6193       env->vregmapHi    = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6194    }
6195 
6196    /* and finally ... */
6197    env->chainingAllowed = chainingAllowed;
6198    env->max_ga          = max_ga;
6199    env->hwcaps          = hwcaps_host;
6200    env->previous_rm     = NULL;
6201    env->vbi             = vbi;
6202 
6203    /* For each IR temporary, allocate a suitably-kinded virtual
6204       register. */
6205    j = 0;
6206    for (i = 0; i < env->n_vregmap; i++) {
6207       hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
6208       switch (bb->tyenv->types[i]) {
6209       case Ity_I1:
6210       case Ity_I8:
6211       case Ity_I16:
6212       case Ity_I32:
6213          if (mode64) {
6214             hregLo = mkHReg(True, HRcInt64, 0, j++);
6215          } else {
6216             hregLo = mkHReg(True, HRcInt32, 0, j++);
6217          }
6218          break;
6219       case Ity_I64:
6220          if (mode64) {
6221             hregLo    = mkHReg(True, HRcInt64, 0, j++);
6222          } else {
6223             hregLo    = mkHReg(True, HRcInt32, 0, j++);
6224             hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6225          }
6226          break;
6227       case Ity_I128:
6228          if (mode64) {
6229             hregLo    = mkHReg(True, HRcInt64, 0, j++);
6230             hregMedLo = mkHReg(True, HRcInt64, 0, j++);
6231          } else {
6232             hregLo    = mkHReg(True, HRcInt32, 0, j++);
6233             hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6234             hregMedHi = mkHReg(True, HRcInt32, 0, j++);
6235             hregHi    = mkHReg(True, HRcInt32, 0, j++);
6236          }
6237          break;
6238       case Ity_F32:
6239       case Ity_F64:
6240          hregLo = mkHReg(True, HRcFlt64, 0, j++);
6241          break;
6242       case Ity_V128:
6243          hregLo = mkHReg(True, HRcVec128, 0, j++);
6244          break;
6245       case Ity_D32:
6246       case Ity_D64:
6247          hregLo = mkHReg(True, HRcFlt64, 0, j++);
6248          break;
6249       case Ity_D128:
6250          hregLo    = mkHReg(True, HRcFlt64, 0, j++);
6251          hregMedLo = mkHReg(True, HRcFlt64, 0, j++);
6252          break;
6253       default:
6254          ppIRType(bb->tyenv->types[i]);
6255          vpanic("iselBB(ppc): IRTemp type");
6256       }
6257       env->vregmapLo[i]    = hregLo;
6258       env->vregmapMedLo[i] = hregMedLo;
6259       if (!mode64) {
6260          env->vregmapMedHi[i] = hregMedHi;
6261          env->vregmapHi[i]    = hregHi;
6262       }
6263    }
6264    env->vreg_ctr = j;
6265 
6266    /* The very first instruction must be an event check. */
6267    amCounter  = PPCAMode_IR(offs_Host_EvC_Counter, hregPPC_GPR31(mode64));
6268    amFailAddr = PPCAMode_IR(offs_Host_EvC_FailAddr, hregPPC_GPR31(mode64));
6269    addInstr(env, PPCInstr_EvCheck(amCounter, amFailAddr));
6270 
6271    /* Possibly a block counter increment (for profiling).  At this
6272       point we don't know the address of the counter, so just pretend
6273       it is zero.  It will have to be patched later, but before this
6274       translation is used, by a call to LibVEX_patchProfCtr. */
6275    if (addProfInc) {
6276       addInstr(env, PPCInstr_ProfInc());
6277    }
6278 
6279    /* Ok, finally we can iterate over the statements. */
6280    for (i = 0; i < bb->stmts_used; i++)
6281       iselStmt(env, bb->stmts[i], IEndianess);
6282 
6283    iselNext(env, bb->next, bb->jumpkind, bb->offsIP, IEndianess);
6284 
6285    /* record the number of vregs we used. */
6286    env->code->n_vregs = env->vreg_ctr;
6287    return env->code;
6288 }
6289 
6290 
6291 /*---------------------------------------------------------------*/
6292 /*--- end                                     host_ppc_isel.c ---*/
6293 /*---------------------------------------------------------------*/
6294