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-2015 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    UInt v = u & 0xFFFF;
2479 
2480    v = (Int)(v << 16) >> 16;   /* sign extend */
2481 
2482    return u == v;
2483 }
2484 
uLong_fits_in_16_bits(ULong u)2485 static Bool uLong_fits_in_16_bits ( ULong u )
2486 {
2487    /* Is u the same as the sign-extend of its lower 16 bits? */
2488    ULong v = u & 0xFFFFULL;
2489 
2490    v = (Long)(v << 48) >> 48;   /* sign extend */
2491 
2492    return u == v;
2493 }
2494 
uLong_is_4_aligned(ULong u)2495 static Bool uLong_is_4_aligned ( ULong u )
2496 {
2497    return toBool((u & 3ULL) == 0);
2498 }
2499 
sane_AMode(ISelEnv * env,PPCAMode * am)2500 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2501 {
2502    Bool mode64 = env->mode64;
2503    switch (am->tag) {
2504    case Pam_IR:
2505       /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2506          somehow, but I think it's OK. */
2507       return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2508                      hregIsVirtual(am->Pam.IR.base) &&
2509                      uInt_fits_in_16_bits(am->Pam.IR.index) );
2510    case Pam_RR:
2511       return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2512                      hregIsVirtual(am->Pam.RR.base) &&
2513                      hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2514                      hregIsVirtual(am->Pam.RR.index) );
2515    default:
2516       vpanic("sane_AMode: unknown ppc amode tag");
2517    }
2518 }
2519 
2520 static
iselWordExpr_AMode(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2521 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy,
2522                                IREndness IEndianess )
2523 {
2524    PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy, IEndianess);
2525    vassert(sane_AMode(env, am));
2526    return am;
2527 }
2528 
2529 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_AMode_wrk(ISelEnv * env,IRExpr * e,IRType xferTy,IREndness IEndianess)2530 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e,
2531                                           IRType xferTy, IREndness IEndianess )
2532 {
2533    IRType ty = typeOfIRExpr(env->type_env,e);
2534 
2535    if (env->mode64) {
2536 
2537       /* If the data load/store type is I32 or I64, this amode might
2538          be destined for use in ld/ldu/lwa/st/stu.  In which case
2539          insist that if it comes out as an _IR, the immediate must
2540          have its bottom two bits be zero.  This does assume that for
2541          any other type (I8/I16/I128/F32/F64/V128) the amode will not
2542          be parked in any such instruction.  But that seems a
2543          reasonable assumption.  */
2544       Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2545 
2546       vassert(ty == Ity_I64);
2547 
2548       /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2549       if (e->tag == Iex_Binop
2550           && e->Iex.Binop.op == Iop_Add64
2551           && e->Iex.Binop.arg2->tag == Iex_Const
2552           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2553           && (aligned4imm  ? uLong_is_4_aligned(e->Iex.Binop.arg2
2554                                                  ->Iex.Const.con->Ico.U64)
2555                            : True)
2556           && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2557                                     ->Iex.Const.con->Ico.U64)) {
2558          return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2559                              iselWordExpr_R(env, e->Iex.Binop.arg1,
2560                                             IEndianess) );
2561       }
2562 
2563       /* Add64(expr,expr) */
2564       if (e->tag == Iex_Binop
2565           && e->Iex.Binop.op == Iop_Add64) {
2566          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2567          HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2568          return PPCAMode_RR( r_idx, r_base );
2569       }
2570 
2571    } else {
2572 
2573       vassert(ty == Ity_I32);
2574 
2575       /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2576       if (e->tag == Iex_Binop
2577           && e->Iex.Binop.op == Iop_Add32
2578           && e->Iex.Binop.arg2->tag == Iex_Const
2579           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2580           && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2581                                    ->Iex.Const.con->Ico.U32)) {
2582          return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2583                              iselWordExpr_R(env, e->Iex.Binop.arg1,
2584                                             IEndianess) );
2585       }
2586 
2587       /* Add32(expr,expr) */
2588       if (e->tag == Iex_Binop
2589           && e->Iex.Binop.op == Iop_Add32) {
2590          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2591          HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
2592          return PPCAMode_RR( r_idx, r_base );
2593       }
2594 
2595    }
2596 
2597    /* Doesn't match anything in particular.  Generate it into
2598       a register and use that. */
2599    return PPCAMode_IR( 0, iselWordExpr_R(env,e,IEndianess) );
2600 }
2601 
2602 
2603 /* --------------------- RH --------------------- */
2604 
2605 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2606    (reg-or-halfword-immediate).  It's important to specify whether the
2607    immediate is to be regarded as signed or not.  If yes, this will
2608    never return -32768 as an immediate; this guaranteed that all
2609    signed immediates that are return can have their sign inverted if
2610    need be. */
2611 
iselWordExpr_RH(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2612 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e,
2613                                 IREndness IEndianess )
2614 {
2615   PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e, IEndianess);
2616    /* sanity checks ... */
2617    switch (ri->tag) {
2618    case Prh_Imm:
2619       vassert(ri->Prh.Imm.syned == syned);
2620       if (syned)
2621          vassert(ri->Prh.Imm.imm16 != 0x8000);
2622       return ri;
2623    case Prh_Reg:
2624       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2625       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2626       return ri;
2627    default:
2628       vpanic("iselIntExpr_RH: unknown ppc RH tag");
2629    }
2630 }
2631 
2632 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH_wrk(ISelEnv * env,Bool syned,IRExpr * e,IREndness IEndianess)2633 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e,
2634                                     IREndness IEndianess )
2635 {
2636    ULong u;
2637    Long  l;
2638    IRType ty = typeOfIRExpr(env->type_env,e);
2639    vassert(ty == Ity_I8  || ty == Ity_I16 ||
2640            ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2641 
2642    /* special case: immediate */
2643    if (e->tag == Iex_Const) {
2644       IRConst* con = e->Iex.Const.con;
2645       /* What value are we aiming to generate? */
2646       switch (con->tag) {
2647       /* Note: Not sign-extending - we carry 'syned' around */
2648       case Ico_U64: vassert(env->mode64);
2649                     u =              con->Ico.U64; break;
2650       case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2651       case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2652       case Ico_U8:  u = 0x000000FF & con->Ico.U8; break;
2653       default:      vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2654       }
2655       l = (Long)u;
2656       /* Now figure out if it's representable. */
2657       if (!syned && u <= 65535) {
2658          return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2659       }
2660       if (syned && l >= -32767 && l <= 32767) {
2661          return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2662       }
2663       /* no luck; use the Slow Way. */
2664    }
2665 
2666    /* default case: calculate into a register and return that */
2667    return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2668 }
2669 
2670 
2671 /* --------------------- RIs --------------------- */
2672 
2673 /* Calculate an expression into an PPCRI operand.  As with
2674    iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2675    in 64-bit mode, 64 bits. */
2676 
iselWordExpr_RI(ISelEnv * env,IRExpr * e,IREndness IEndianess)2677 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
2678 {
2679    PPCRI* ri = iselWordExpr_RI_wrk(env, e, IEndianess);
2680    /* sanity checks ... */
2681    switch (ri->tag) {
2682    case Pri_Imm:
2683       return ri;
2684    case Pri_Reg:
2685       vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2686       vassert(hregIsVirtual(ri->Pri.Reg));
2687       return ri;
2688    default:
2689       vpanic("iselIntExpr_RI: unknown ppc RI tag");
2690    }
2691 }
2692 
2693 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RI_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2694 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e,
2695                                     IREndness IEndianess )
2696 {
2697    Long  l;
2698    IRType ty = typeOfIRExpr(env->type_env,e);
2699    vassert(ty == Ity_I8  || ty == Ity_I16 ||
2700            ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2701 
2702    /* special case: immediate */
2703    if (e->tag == Iex_Const) {
2704       IRConst* con = e->Iex.Const.con;
2705       switch (con->tag) {
2706       case Ico_U64: vassert(env->mode64);
2707                     l = (Long)            con->Ico.U64; break;
2708       case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
2709       case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2710       case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
2711       default:      vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2712       }
2713       return PPCRI_Imm((ULong)l);
2714    }
2715 
2716    /* default case: calculate into a register and return that */
2717    return PPCRI_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2718 }
2719 
2720 
2721 /* --------------------- RH5u --------------------- */
2722 
2723 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2724    being an immediate in the range 1 .. 31 inclusive.  Used for doing
2725    shift amounts.  Only used in 32-bit mode. */
2726 
iselWordExpr_RH5u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2727 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e,
2728                                   IREndness IEndianess )
2729 {
2730    PPCRH* ri;
2731    vassert(!env->mode64);
2732    ri = iselWordExpr_RH5u_wrk(env, e, IEndianess);
2733    /* sanity checks ... */
2734    switch (ri->tag) {
2735    case Prh_Imm:
2736       vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2737       vassert(!ri->Prh.Imm.syned);
2738       return ri;
2739    case Prh_Reg:
2740       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2741       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2742       return ri;
2743    default:
2744       vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2745    }
2746 }
2747 
2748 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH5u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2749 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e,
2750                                       IREndness IEndianess )
2751 {
2752    IRType ty = typeOfIRExpr(env->type_env,e);
2753    vassert(ty == Ity_I8);
2754 
2755    /* special case: immediate */
2756    if (e->tag == Iex_Const
2757        && e->Iex.Const.con->tag == Ico_U8
2758        && e->Iex.Const.con->Ico.U8 >= 1
2759        && e->Iex.Const.con->Ico.U8 <= 31) {
2760       return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2761    }
2762 
2763    /* default case: calculate into a register and return that */
2764    return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2765 }
2766 
2767 
2768 /* --------------------- RH6u --------------------- */
2769 
2770 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2771    being an immediate in the range 1 .. 63 inclusive.  Used for doing
2772    shift amounts.  Only used in 64-bit mode. */
2773 
iselWordExpr_RH6u(ISelEnv * env,IRExpr * e,IREndness IEndianess)2774 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e,
2775                                   IREndness IEndianess )
2776 {
2777    PPCRH* ri;
2778    vassert(env->mode64);
2779    ri = iselWordExpr_RH6u_wrk(env, e, IEndianess);
2780    /* sanity checks ... */
2781    switch (ri->tag) {
2782    case Prh_Imm:
2783       vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2784       vassert(!ri->Prh.Imm.syned);
2785       return ri;
2786    case Prh_Reg:
2787       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2788       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2789       return ri;
2790    default:
2791       vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2792    }
2793 }
2794 
2795 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH6u_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2796 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e,
2797                                       IREndness IEndianess )
2798 {
2799    IRType ty = typeOfIRExpr(env->type_env,e);
2800    vassert(ty == Ity_I8);
2801 
2802    /* special case: immediate */
2803    if (e->tag == Iex_Const
2804        && e->Iex.Const.con->tag == Ico_U8
2805        && e->Iex.Const.con->Ico.U8 >= 1
2806        && e->Iex.Const.con->Ico.U8 <= 63) {
2807       return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2808    }
2809 
2810    /* default case: calculate into a register and return that */
2811    return PPCRH_Reg( iselWordExpr_R ( env, e, IEndianess ) );
2812 }
2813 
2814 
2815 /* --------------------- CONDCODE --------------------- */
2816 
2817 /* Generate code to evaluated a bit-typed expression, returning the
2818    condition code which would correspond when the expression would
2819    notionally have returned 1. */
2820 
iselCondCode(ISelEnv * env,IRExpr * e,IREndness IEndianess)2821 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e,
2822                                   IREndness IEndianess )
2823 {
2824    /* Uh, there's nothing we can sanity check here, unfortunately. */
2825    return iselCondCode_wrk(env,e, IEndianess);
2826 }
2827 
2828 /* DO NOT CALL THIS DIRECTLY ! */
iselCondCode_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)2829 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e,
2830                                       IREndness IEndianess )
2831 {
2832    vassert(e);
2833    vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2834 
2835    /* Constant 1:Bit */
2836    if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2837       // Make a compare that will always be true:
2838       HReg r_zero = newVRegI(env);
2839       addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2840       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2841                                  7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2842       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2843    }
2844 
2845    /* Not1(...) */
2846    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2847       /* Generate code for the arg, and negate the test condition */
2848       PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
2849       cond.test = invertCondTest(cond.test);
2850       return cond;
2851    }
2852 
2853    /* --- patterns rooted at: 32to1 or 64to1 --- */
2854 
2855    /* 32to1, 64to1 */
2856    if (e->tag == Iex_Unop &&
2857        (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2858       HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2859       HReg tmp = newVRegI(env);
2860       /* could do better, probably -- andi. */
2861       addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2862                                  src, PPCRH_Imm(False,1)));
2863       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2864                                  7/*cr*/, tmp, PPCRH_Imm(False,1)));
2865       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2866    }
2867 
2868    /* --- patterns rooted at: CmpNEZ8 --- */
2869 
2870    /* CmpNEZ8(x) */
2871    /* Note this cloned as CmpNE8(x,0) below. */
2872    /* could do better -- andi. */
2873    if (e->tag == Iex_Unop
2874        && e->Iex.Unop.op == Iop_CmpNEZ8) {
2875       HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2876       HReg tmp = newVRegI(env);
2877       addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2878                                  PPCRH_Imm(False,0xFF)));
2879       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2880                                  7/*cr*/, tmp, PPCRH_Imm(False,0)));
2881       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2882    }
2883 
2884    /* --- patterns rooted at: CmpNEZ32 --- */
2885 
2886    /* CmpNEZ32(x) */
2887    if (e->tag == Iex_Unop
2888        && e->Iex.Unop.op == Iop_CmpNEZ32) {
2889       HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2890       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2891                                  7/*cr*/, r1, PPCRH_Imm(False,0)));
2892       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2893    }
2894 
2895    /* --- patterns rooted at: Cmp*32* --- */
2896 
2897    /* Cmp*32*(x,y) */
2898    if (e->tag == Iex_Binop
2899        && (e->Iex.Binop.op == Iop_CmpEQ32
2900            || e->Iex.Binop.op == Iop_CmpNE32
2901            || e->Iex.Binop.op == Iop_CmpLT32S
2902            || e->Iex.Binop.op == Iop_CmpLT32U
2903            || e->Iex.Binop.op == Iop_CmpLE32S
2904            || e->Iex.Binop.op == Iop_CmpLE32U)) {
2905       Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2906                     e->Iex.Binop.op == Iop_CmpLE32S);
2907       HReg   r1  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2908       PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2909       addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2910                                  7/*cr*/, r1, ri2));
2911 
2912       switch (e->Iex.Binop.op) {
2913       case Iop_CmpEQ32:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2914       case Iop_CmpNE32:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2915       case Iop_CmpLT32U: case Iop_CmpLT32S:
2916          return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2917       case Iop_CmpLE32U: case Iop_CmpLE32S:
2918          return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2919       default: vpanic("iselCondCode(ppc): CmpXX32");
2920       }
2921    }
2922 
2923    /* --- patterns rooted at: CmpNEZ64 --- */
2924 
2925    /* CmpNEZ64 */
2926    if (e->tag == Iex_Unop
2927        && e->Iex.Unop.op == Iop_CmpNEZ64) {
2928       if (!env->mode64) {
2929          HReg hi, lo;
2930          HReg tmp = newVRegI(env);
2931          iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg, IEndianess );
2932          addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2933          addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2934                                     7/*cr*/, tmp,PPCRH_Imm(False,0)));
2935          return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2936       } else {  // mode64
2937          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
2938          addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2939                                     7/*cr*/, r_src,PPCRH_Imm(False,0)));
2940          return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2941       }
2942    }
2943 
2944    /* --- patterns rooted at: Cmp*64* --- */
2945 
2946    /* Cmp*64*(x,y) */
2947    if (e->tag == Iex_Binop
2948        && (e->Iex.Binop.op == Iop_CmpEQ64
2949            || e->Iex.Binop.op == Iop_CmpNE64
2950            || e->Iex.Binop.op == Iop_CmpLT64S
2951            || e->Iex.Binop.op == Iop_CmpLT64U
2952            || e->Iex.Binop.op == Iop_CmpLE64S
2953            || e->Iex.Binop.op == Iop_CmpLE64U)) {
2954       Bool   syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2955                       e->Iex.Binop.op == Iop_CmpLE64S);
2956       HReg    r1 = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2957       PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2, IEndianess);
2958       vassert(env->mode64);
2959       addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2960                                  7/*cr*/, r1, ri2));
2961 
2962       switch (e->Iex.Binop.op) {
2963       case Iop_CmpEQ64:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2964       case Iop_CmpNE64:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2965       case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2966       case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2967       default: vpanic("iselCondCode(ppc): CmpXX64");
2968       }
2969    }
2970 
2971    /* --- patterns rooted at: CmpNE8 --- */
2972 
2973    /* CmpNE8(x,0) */
2974    /* Note this is a direct copy of CmpNEZ8 above. */
2975    /* could do better -- andi. */
2976    if (e->tag == Iex_Binop
2977        && e->Iex.Binop.op == Iop_CmpNE8
2978        && isZeroU8(e->Iex.Binop.arg2)) {
2979       HReg arg = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
2980       HReg tmp = newVRegI(env);
2981       addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2982                                  PPCRH_Imm(False,0xFF)));
2983       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2984                                  7/*cr*/, tmp, PPCRH_Imm(False,0)));
2985       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2986    }
2987 
2988    /* var */
2989    if (e->tag == Iex_RdTmp) {
2990       HReg r_src      = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2991       HReg src_masked = newVRegI(env);
2992       addInstr(env,
2993                PPCInstr_Alu(Palu_AND, src_masked,
2994                             r_src, PPCRH_Imm(False,1)));
2995       addInstr(env,
2996                PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2997                             7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2998       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2999    }
3000 
3001    vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
3002    ppIRExpr(e);
3003    vpanic("iselCondCode(ppc)");
3004 }
3005 
3006 
3007 /*---------------------------------------------------------*/
3008 /*--- ISEL: Integer expressions (128 bit)               ---*/
3009 /*---------------------------------------------------------*/
3010 
3011 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
3012    which is returned as the first two parameters.  As with
3013    iselWordExpr_R, these may be either real or virtual regs; in any
3014    case they must not be changed by subsequent code emitted by the
3015    caller.  */
3016 
iselInt128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3017 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
3018                              ISelEnv* env, IRExpr* e, IREndness IEndianess )
3019 {
3020    vassert(env->mode64);
3021    iselInt128Expr_wrk(rHi, rLo, env, e, IEndianess);
3022 #  if 0
3023    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3024 #  endif
3025    vassert(hregClass(*rHi) == HRcGPR(env->mode64));
3026    vassert(hregIsVirtual(*rHi));
3027    vassert(hregClass(*rLo) == HRcGPR(env->mode64));
3028    vassert(hregIsVirtual(*rLo));
3029 }
3030 
3031 /* DO NOT CALL THIS DIRECTLY ! */
iselInt128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3032 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
3033                                  ISelEnv* env, IRExpr* e, IREndness IEndianess )
3034 {
3035    vassert(e);
3036    vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3037 
3038    /* read 128-bit IRTemp */
3039    if (e->tag == Iex_RdTmp) {
3040       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3041       return;
3042    }
3043 
3044    /* --------- BINARY ops --------- */
3045    if (e->tag == Iex_Binop) {
3046       switch (e->Iex.Binop.op) {
3047       /* 64 x 64 -> 128 multiply */
3048       case Iop_MullU64:
3049       case Iop_MullS64: {
3050          HReg     tLo     = newVRegI(env);
3051          HReg     tHi     = newVRegI(env);
3052          Bool     syned   = toBool(e->Iex.Binop.op == Iop_MullS64);
3053          HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3054          HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3055          addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3056                                      False/*lo64*/, False/*64bit mul*/,
3057                                      tLo, r_srcL, r_srcR));
3058          addInstr(env, PPCInstr_MulL(syned,
3059                                      True/*hi64*/, False/*64bit mul*/,
3060                                      tHi, r_srcL, r_srcR));
3061          *rHi = tHi;
3062          *rLo = tLo;
3063          return;
3064       }
3065 
3066       /* 64HLto128(e1,e2) */
3067       case Iop_64HLto128:
3068          *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3069          *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3070          return;
3071       default:
3072          break;
3073       }
3074    } /* if (e->tag == Iex_Binop) */
3075 
3076 
3077    /* --------- UNARY ops --------- */
3078    if (e->tag == Iex_Unop) {
3079       switch (e->Iex.Unop.op) {
3080       default:
3081          break;
3082       }
3083    } /* if (e->tag == Iex_Unop) */
3084 
3085    vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
3086    ppIRExpr(e);
3087    vpanic("iselInt128Expr(ppc64)");
3088 }
3089 
3090 
3091 /*---------------------------------------------------------*/
3092 /*--- ISEL: Integer expressions (64 bit)                ---*/
3093 /*---------------------------------------------------------*/
3094 
3095 /* 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)3096 static void iselInt128Expr_to_32x4 ( HReg* rHi, HReg* rMedHi, HReg* rMedLo,
3097                                      HReg* rLo, ISelEnv* env, IRExpr* e,
3098                                      IREndness IEndianess )
3099 {
3100    vassert(!env->mode64);
3101    iselInt128Expr_to_32x4_wrk(rHi, rMedHi, rMedLo, rLo, env, e, IEndianess);
3102 #  if 0
3103    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3104 #  endif
3105    vassert(hregClass(*rHi) == HRcInt32);
3106    vassert(hregIsVirtual(*rHi));
3107    vassert(hregClass(*rMedHi) == HRcInt32);
3108    vassert(hregIsVirtual(*rMedHi));
3109    vassert(hregClass(*rMedLo) == HRcInt32);
3110    vassert(hregIsVirtual(*rMedLo));
3111    vassert(hregClass(*rLo) == HRcInt32);
3112    vassert(hregIsVirtual(*rLo));
3113 }
3114 
iselInt128Expr_to_32x4_wrk(HReg * rHi,HReg * rMedHi,HReg * rMedLo,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3115 static void iselInt128Expr_to_32x4_wrk ( HReg* rHi, HReg* rMedHi,
3116                                          HReg* rMedLo, HReg* rLo,
3117                                          ISelEnv* env, IRExpr* e,
3118                                          IREndness IEndianess )
3119 {
3120    vassert(e);
3121    vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
3122 
3123    /* read 128-bit IRTemp */
3124    if (e->tag == Iex_RdTmp) {
3125       lookupIRTempQuad( rHi, rMedHi, rMedLo, rLo, env, e->Iex.RdTmp.tmp);
3126       return;
3127    }
3128 
3129    if (e->tag == Iex_Binop) {
3130 
3131       IROp op_binop = e->Iex.Binop.op;
3132       switch (op_binop) {
3133       case Iop_64HLto128:
3134          iselInt64Expr(rHi, rMedHi, env, e->Iex.Binop.arg1, IEndianess);
3135          iselInt64Expr(rMedLo, rLo, env, e->Iex.Binop.arg2, IEndianess);
3136          return;
3137       default:
3138          vex_printf("iselInt128Expr_to_32x4_wrk: Binop case 0x%x not found\n",
3139                     op_binop);
3140          break;
3141       }
3142    }
3143 
3144    vex_printf("iselInt128Expr_to_32x4_wrk: e->tag 0x%x not found\n", e->tag);
3145    return;
3146 }
3147 
3148 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
3149    which is returned as the first two parameters.  As with
3150    iselIntExpr_R, these may be either real or virtual regs; in any
3151    case they must not be changed by subsequent code emitted by the
3152    caller.  */
3153 
iselInt64Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3154 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
3155                             ISelEnv* env, IRExpr* e,
3156                             IREndness IEndianess )
3157 {
3158    vassert(!env->mode64);
3159    iselInt64Expr_wrk(rHi, rLo, env, e, IEndianess);
3160 #  if 0
3161    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3162 #  endif
3163    vassert(hregClass(*rHi) == HRcInt32);
3164    vassert(hregIsVirtual(*rHi));
3165    vassert(hregClass(*rLo) == HRcInt32);
3166    vassert(hregIsVirtual(*rLo));
3167 }
3168 
3169 /* DO NOT CALL THIS DIRECTLY ! */
iselInt64Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)3170 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
3171                                 ISelEnv* env, IRExpr* e,
3172                                 IREndness IEndianess )
3173 {
3174    vassert(e);
3175    vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
3176 
3177    /* 64-bit load */
3178    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3179       HReg tLo    = newVRegI(env);
3180       HReg tHi    = newVRegI(env);
3181       HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr, IEndianess);
3182       vassert(!env->mode64);
3183       addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3184                                    tHi, PPCAMode_IR( 0, r_addr ),
3185                                    False/*32-bit insn please*/) );
3186       addInstr(env, PPCInstr_Load( 4/*byte-load*/,
3187                                    tLo, PPCAMode_IR( 4, r_addr ),
3188                                    False/*32-bit insn please*/) );
3189       *rHi = tHi;
3190       *rLo = tLo;
3191       return;
3192    }
3193 
3194    /* 64-bit literal */
3195    if (e->tag == Iex_Const) {
3196       ULong w64 = e->Iex.Const.con->Ico.U64;
3197       UInt  wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
3198       UInt  wLo = ((UInt)w64) & 0xFFFFFFFF;
3199       HReg  tLo = newVRegI(env);
3200       HReg  tHi = newVRegI(env);
3201       vassert(e->Iex.Const.con->tag == Ico_U64);
3202       addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
3203       addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
3204       *rHi = tHi;
3205       *rLo = tLo;
3206       return;
3207    }
3208 
3209    /* read 64-bit IRTemp */
3210    if (e->tag == Iex_RdTmp) {
3211       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
3212       return;
3213    }
3214 
3215    /* 64-bit GET */
3216    if (e->tag == Iex_Get) {
3217       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3218                                        GuestStatePtr(False/*mode32*/) );
3219       PPCAMode* am_addr4 = advance4(env, am_addr);
3220       HReg tLo = newVRegI(env);
3221       HReg tHi = newVRegI(env);
3222       addInstr(env, PPCInstr_Load( 4, tHi, am_addr,  False/*mode32*/ ));
3223       addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
3224       *rHi = tHi;
3225       *rLo = tLo;
3226       return;
3227    }
3228 
3229    /* 64-bit ITE */
3230    if (e->tag == Iex_ITE) { // VFD
3231       HReg e0Lo, e0Hi, eXLo, eXHi;
3232       iselInt64Expr(&eXHi, &eXLo, env, e->Iex.ITE.iftrue, IEndianess);
3233       iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.ITE.iffalse, IEndianess);
3234       HReg tLo = newVRegI(env);
3235       HReg tHi = newVRegI(env);
3236       addInstr(env, mk_iMOVds_RR(tHi,e0Hi));
3237       addInstr(env, mk_iMOVds_RR(tLo,e0Lo));
3238       PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
3239       addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(eXHi)));
3240       addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(eXLo)));
3241       *rHi = tHi;
3242       *rLo = tLo;
3243       return;
3244    }
3245 
3246    /* --------- BINARY ops --------- */
3247    if (e->tag == Iex_Binop) {
3248       IROp op_binop = e->Iex.Binop.op;
3249       switch (op_binop) {
3250          /* 32 x 32 -> 64 multiply */
3251          case Iop_MullU32:
3252          case Iop_MullS32: {
3253             HReg     tLo     = newVRegI(env);
3254             HReg     tHi     = newVRegI(env);
3255             Bool     syned   = toBool(op_binop == Iop_MullS32);
3256             HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1,
3257                                               IEndianess);
3258             HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2,
3259                                               IEndianess);
3260             addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
3261                                         False/*lo32*/, True/*32bit mul*/,
3262                                         tLo, r_srcL, r_srcR));
3263             addInstr(env, PPCInstr_MulL(syned,
3264                                         True/*hi32*/, True/*32bit mul*/,
3265                                         tHi, r_srcL, r_srcR));
3266             *rHi = tHi;
3267             *rLo = tLo;
3268             return;
3269          }
3270 
3271          /* Or64/And64/Xor64 */
3272          case Iop_Or64:
3273          case Iop_And64:
3274          case Iop_Xor64: {
3275             HReg xLo, xHi, yLo, yHi;
3276             HReg tLo = newVRegI(env);
3277             HReg tHi = newVRegI(env);
3278             PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
3279                           (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
3280             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3281             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3282             addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
3283             addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
3284             *rHi = tHi;
3285             *rLo = tLo;
3286             return;
3287          }
3288 
3289          /* Add64 */
3290          case Iop_Add64: {
3291             HReg xLo, xHi, yLo, yHi;
3292             HReg tLo = newVRegI(env);
3293             HReg tHi = newVRegI(env);
3294             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1, IEndianess);
3295             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2, IEndianess);
3296             addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
3297                                             tLo, xLo, yLo));
3298             addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
3299                                             tHi, xHi, yHi));
3300             *rHi = tHi;
3301             *rLo = tLo;
3302             return;
3303          }
3304 
3305          /* 32HLto64(e1,e2) */
3306          case Iop_32HLto64:
3307             *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
3308             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3309             return;
3310 
3311          /* F64toI64[S|U] */
3312          case Iop_F64toI64S: case Iop_F64toI64U: {
3313             HReg      tLo     = newVRegI(env);
3314             HReg      tHi     = newVRegI(env);
3315             HReg      r1      = StackFramePtr(env->mode64);
3316             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3317             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3318             HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2,
3319                                             IEndianess);
3320             HReg      ftmp    = newVRegF(env);
3321 
3322             vassert(!env->mode64);
3323             /* Set host rounding mode */
3324             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3325 
3326             sub_from_sp( env, 16 );
3327             addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
3328                                           (op_binop == Iop_F64toI64S) ? True : False,
3329                                           True, ftmp, fsrc));
3330             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3331             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3332             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3333             add_to_sp( env, 16 );
3334 
3335             ///* Restore default FPU rounding. */
3336             //set_FPU_rounding_default( env );
3337             *rHi = tHi;
3338             *rLo = tLo;
3339             return;
3340          }
3341          case Iop_D64toI64S: {
3342             HReg      tLo     = newVRegI(env);
3343             HReg      tHi     = newVRegI(env);
3344             HReg      r1      = StackFramePtr(env->mode64);
3345             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3346             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3347             HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
3348             HReg tmp    = newVRegF(env);
3349 
3350             vassert(!env->mode64);
3351             set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3352             addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTFIX, tmp, fr_src));
3353 
3354             sub_from_sp( env, 16 );
3355             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3356             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3357             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3358             add_to_sp( env, 16 );
3359             *rHi = tHi;
3360             *rLo = tLo;
3361             return;
3362          }
3363          case Iop_D128toI64S: {
3364             PPCFpOp fpop = Pfp_DCTFIXQ;
3365             HReg r_srcHi = newVRegF(env);
3366             HReg r_srcLo = newVRegF(env);
3367             HReg tLo     = newVRegI(env);
3368             HReg tHi     = newVRegI(env);
3369             HReg ftmp    = newVRegF(env);
3370             PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3371             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3372 
3373             set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3374             iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
3375                            IEndianess);
3376             addInstr(env, PPCInstr_DfpD128toD64(fpop, ftmp, r_srcHi, r_srcLo));
3377 
3378             // put the D64 result into an integer register pair
3379             sub_from_sp( env, 16 );
3380             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
3381             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3382             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3383             add_to_sp( env, 16 );
3384             *rHi = tHi;
3385             *rLo = tLo;
3386             return;
3387          }
3388          default:
3389             break;
3390       }
3391    } /* if (e->tag == Iex_Binop) */
3392 
3393 
3394    /* --------- UNARY ops --------- */
3395    if (e->tag == Iex_Unop) {
3396       switch (e->Iex.Unop.op) {
3397 
3398       /* CmpwNEZ64(e) */
3399       case Iop_CmpwNEZ64: {
3400          HReg argHi, argLo;
3401          HReg tmp1  = newVRegI(env);
3402          HReg tmp2  = newVRegI(env);
3403          iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3404          /* tmp1 = argHi | argLo */
3405          addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
3406          /* tmp2 = (tmp1 | -tmp1) >>s 31 */
3407          addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
3408          addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
3409          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3410                                      tmp2, tmp2, PPCRH_Imm(False, 31)));
3411          *rHi = tmp2;
3412          *rLo = tmp2; /* yes, really tmp2 */
3413          return;
3414       }
3415 
3416       /* Left64 */
3417       case Iop_Left64: {
3418          HReg argHi, argLo;
3419          HReg zero32 = newVRegI(env);
3420          HReg resHi  = newVRegI(env);
3421          HReg resLo  = newVRegI(env);
3422          iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg, IEndianess);
3423          vassert(env->mode64 == False);
3424          addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
3425          /* resHi:resLo = - argHi:argLo */
3426          addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
3427                                          resLo, zero32, argLo ));
3428          addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
3429                                          resHi, zero32, argHi ));
3430          /* resHi:resLo |= srcHi:srcLo */
3431          addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
3432          addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
3433          *rHi = resHi;
3434          *rLo = resLo;
3435          return;
3436       }
3437 
3438       /* 32Sto64(e) */
3439       case Iop_32Sto64: {
3440          HReg tHi = newVRegI(env);
3441          HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3442          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3443                                      tHi, src, PPCRH_Imm(False,31)));
3444          *rHi = tHi;
3445          *rLo = src;
3446          return;
3447       }
3448       case Iop_ExtractExpD64: {
3449          HReg tmp    = newVRegF(env);
3450          HReg fr_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3451          HReg      tLo     = newVRegI(env);
3452          HReg      tHi     = newVRegI(env);
3453          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3454          PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3455 
3456          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DXEX, tmp, fr_src));
3457 
3458          // put the D64 result into a integer register pair
3459          sub_from_sp( env, 16 );
3460          addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3461          addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3462          addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3463          add_to_sp( env, 16 );
3464          *rHi = tHi;
3465          *rLo = tLo;
3466          return;
3467       }
3468       case Iop_ExtractExpD128: {
3469          HReg      r_srcHi;
3470          HReg      r_srcLo;
3471          HReg      tmp     = newVRegF(env);
3472          HReg      tLo     = newVRegI(env);
3473          HReg      tHi     = newVRegI(env);
3474          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3475          PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
3476 
3477          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Unop.arg, IEndianess);
3478          addInstr(env, PPCInstr_ExtractExpD128(Pfp_DXEXQ, tmp,
3479                                                   r_srcHi, r_srcLo));
3480 
3481          // put the D64 result into a integer register pair
3482          sub_from_sp( env, 16 );
3483          addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, tmp, zero_r1));
3484          addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
3485          addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
3486          add_to_sp( env, 16 );
3487          *rHi = tHi;
3488          *rLo = tLo;
3489          return;
3490       }
3491 
3492       /* 32Uto64(e) */
3493       case Iop_32Uto64: {
3494          HReg tHi = newVRegI(env);
3495          HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
3496          addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
3497          *rHi = tHi;
3498          *rLo = tLo;
3499          return;
3500       }
3501 
3502       case Iop_128to64: {
3503          /* Narrow, return the low 64-bit half as a 32-bit
3504           * register pair */
3505          HReg r_Hi    = INVALID_HREG;
3506          HReg r_MedHi = INVALID_HREG;
3507          HReg r_MedLo = INVALID_HREG;
3508          HReg r_Lo    = INVALID_HREG;
3509 
3510          iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3511                                 env, e->Iex.Unop.arg, IEndianess);
3512          *rHi = r_MedLo;
3513          *rLo = r_Lo;
3514          return;
3515       }
3516 
3517       case Iop_128HIto64: {
3518          /* Narrow, return the high 64-bit half as a 32-bit
3519           *  register pair */
3520          HReg r_Hi    = INVALID_HREG;
3521          HReg r_MedHi = INVALID_HREG;
3522          HReg r_MedLo = INVALID_HREG;
3523          HReg r_Lo    = INVALID_HREG;
3524 
3525          iselInt128Expr_to_32x4(&r_Hi, &r_MedHi, &r_MedLo, &r_Lo,
3526                                 env, e->Iex.Unop.arg, IEndianess);
3527          *rHi = r_Hi;
3528          *rLo = r_MedHi;
3529          return;
3530       }
3531 
3532       /* V128{HI}to64 */
3533       case Iop_V128HIto64:
3534       case Iop_V128to64: {
3535          HReg r_aligned16;
3536          Int  off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
3537          HReg tLo = newVRegI(env);
3538          HReg tHi = newVRegI(env);
3539          HReg vec = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
3540          PPCAMode *am_off0, *am_offLO, *am_offHI;
3541          sub_from_sp( env, 32 );     // Move SP down 32 bytes
3542 
3543          // get a quadword aligned address within our stack space
3544          r_aligned16 = get_sp_aligned16( env );
3545          am_off0  = PPCAMode_IR( 0,     r_aligned16 );
3546          am_offHI = PPCAMode_IR( off,   r_aligned16 );
3547          am_offLO = PPCAMode_IR( off+4, r_aligned16 );
3548 
3549          // store as Vec128
3550          addInstr(env,
3551                   PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
3552 
3553          // load hi,lo words (of hi/lo half of vec) as Ity_I32's
3554          addInstr(env,
3555                   PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
3556          addInstr(env,
3557                   PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
3558 
3559          add_to_sp( env, 32 );       // Reset SP
3560          *rHi = tHi;
3561          *rLo = tLo;
3562          return;
3563       }
3564 
3565       /* could do better than this, but for now ... */
3566       case Iop_1Sto64: {
3567          HReg tLo = newVRegI(env);
3568          HReg tHi = newVRegI(env);
3569          PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg, IEndianess);
3570          addInstr(env, PPCInstr_Set(cond,tLo));
3571          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
3572                                      tLo, tLo, PPCRH_Imm(False,31)));
3573          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
3574                                      tLo, tLo, PPCRH_Imm(False,31)));
3575          addInstr(env, mk_iMOVds_RR(tHi, tLo));
3576          *rHi = tHi;
3577          *rLo = tLo;
3578          return;
3579       }
3580 
3581       case Iop_Not64: {
3582          HReg xLo, xHi;
3583          HReg tmpLo = newVRegI(env);
3584          HReg tmpHi = newVRegI(env);
3585          iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg, IEndianess);
3586          addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
3587          addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
3588          *rHi = tmpHi;
3589          *rLo = tmpLo;
3590          return;
3591       }
3592 
3593       /* ReinterpF64asI64(e) */
3594       /* Given an IEEE754 double, produce an I64 with the same bit
3595          pattern. */
3596       case Iop_ReinterpF64asI64: {
3597          PPCAMode *am_addr0, *am_addr1;
3598          HReg fr_src  = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3599          HReg r_dstLo = newVRegI(env);
3600          HReg r_dstHi = newVRegI(env);
3601 
3602          sub_from_sp( env, 16 );     // Move SP down 16 bytes
3603          am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3604          am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3605 
3606          // store as F64
3607          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3608                                         fr_src, am_addr0 ));
3609 
3610          // load hi,lo as Ity_I32's
3611          addInstr(env, PPCInstr_Load( 4, r_dstHi,
3612                                       am_addr0, False/*mode32*/ ));
3613          addInstr(env, PPCInstr_Load( 4, r_dstLo,
3614                                       am_addr1, False/*mode32*/ ));
3615          *rHi = r_dstHi;
3616          *rLo = r_dstLo;
3617 
3618          add_to_sp( env, 16 );       // Reset SP
3619          return;
3620       }
3621 
3622       case Iop_ReinterpD64asI64: {
3623          HReg fr_src  = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
3624          PPCAMode *am_addr0, *am_addr1;
3625          HReg r_dstLo = newVRegI(env);
3626          HReg r_dstHi = newVRegI(env);
3627 
3628 
3629          sub_from_sp( env, 16 );     // Move SP down 16 bytes
3630          am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
3631          am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
3632 
3633          // store as D64
3634          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3635                                         fr_src, am_addr0 ));
3636 
3637          // load hi,lo as Ity_I32's
3638          addInstr(env, PPCInstr_Load( 4, r_dstHi,
3639                                       am_addr0, False/*mode32*/ ));
3640          addInstr(env, PPCInstr_Load( 4, r_dstLo,
3641                                       am_addr1, False/*mode32*/ ));
3642          *rHi = r_dstHi;
3643          *rLo = r_dstLo;
3644 
3645          add_to_sp( env, 16 );       // Reset SP
3646 
3647          return;
3648       }
3649 
3650       case Iop_BCDtoDPB: {
3651          PPCCondCode cc;
3652          UInt        argiregs;
3653          HReg        argregs[2];
3654          Int         argreg;
3655          HReg        tLo = newVRegI(env);
3656          HReg        tHi = newVRegI(env);
3657          HReg        tmpHi;
3658          HReg        tmpLo;
3659          Bool        mode64 = env->mode64;
3660 
3661          argregs[0] = hregPPC_GPR3(mode64);
3662          argregs[1] = hregPPC_GPR4(mode64);
3663 
3664          argiregs = 0;
3665          argreg = 0;
3666 
3667          iselInt64Expr( &tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess );
3668 
3669          argiregs |= ( 1 << (argreg+3 ) );
3670          addInstr( env, mk_iMOVds_RR( argregs[argreg++], tmpHi ) );
3671 
3672          argiregs |= ( 1 << (argreg+3 ) );
3673          addInstr( env, mk_iMOVds_RR( argregs[argreg], tmpLo ) );
3674 
3675          cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3676 
3677          if (IEndianess == Iend_LE) {
3678              addInstr( env, PPCInstr_Call( cc, (Addr)h_calc_BCDtoDPB,
3679                                            argiregs,
3680                                            mk_RetLoc_simple(RLPri_2Int) ) );
3681          } else {
3682              Addr64 target;
3683              target = mode64 ? (Addr)h_calc_BCDtoDPB :
3684                toUInt( (Addr)h_calc_BCDtoDPB );
3685              addInstr( env, PPCInstr_Call( cc, target,
3686                                            argiregs,
3687                                            mk_RetLoc_simple(RLPri_2Int) ) );
3688          }
3689 
3690          addInstr( env, mk_iMOVds_RR( tHi, argregs[argreg-1] ) );
3691          addInstr( env, mk_iMOVds_RR( tLo, argregs[argreg] ) );
3692 
3693          *rHi = tHi;
3694          *rLo = tLo;
3695          return;
3696       }
3697 
3698       case Iop_DPBtoBCD: {
3699          PPCCondCode cc;
3700          UInt        argiregs;
3701          HReg        argregs[2];
3702          Int         argreg;
3703          HReg        tLo = newVRegI(env);
3704          HReg        tHi = newVRegI(env);
3705          HReg        tmpHi;
3706          HReg        tmpLo;
3707          Bool        mode64 = env->mode64;
3708 
3709          argregs[0] = hregPPC_GPR3(mode64);
3710          argregs[1] = hregPPC_GPR4(mode64);
3711 
3712          argiregs = 0;
3713          argreg = 0;
3714 
3715          iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg, IEndianess);
3716 
3717          argiregs |= (1 << (argreg+3));
3718          addInstr(env, mk_iMOVds_RR( argregs[argreg++], tmpHi ));
3719 
3720          argiregs |= (1 << (argreg+3));
3721          addInstr(env, mk_iMOVds_RR( argregs[argreg], tmpLo));
3722 
3723          cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
3724 
3725          if (IEndianess == Iend_LE) {
3726              addInstr(env, PPCInstr_Call( cc, (Addr)h_calc_DPBtoBCD,
3727                                           argiregs,
3728                                           mk_RetLoc_simple(RLPri_2Int) ) );
3729          } else {
3730              Addr64 target;
3731              target = mode64 ? (Addr)h_calc_DPBtoBCD :
3732                toUInt( (Addr)h_calc_DPBtoBCD );
3733              addInstr(env, PPCInstr_Call( cc, target, argiregs,
3734                                           mk_RetLoc_simple(RLPri_2Int) ) );
3735          }
3736 
3737          addInstr(env, mk_iMOVds_RR(tHi, argregs[argreg-1]));
3738          addInstr(env, mk_iMOVds_RR(tLo, argregs[argreg]));
3739 
3740          *rHi = tHi;
3741          *rLo = tLo;
3742          return;
3743       }
3744 
3745       default:
3746          break;
3747       }
3748    } /* if (e->tag == Iex_Unop) */
3749 
3750    vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
3751    ppIRExpr(e);
3752    vpanic("iselInt64Expr(ppc)");
3753 }
3754 
3755 
3756 /*---------------------------------------------------------*/
3757 /*--- ISEL: Floating point expressions (32 bit)         ---*/
3758 /*---------------------------------------------------------*/
3759 
3760 /* Nothing interesting here; really just wrappers for
3761    64-bit stuff. */
3762 
iselFltExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3763 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3764 {
3765   HReg r = iselFltExpr_wrk( env, e, IEndianess );
3766 #  if 0
3767    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3768 #  endif
3769    vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
3770    vassert(hregIsVirtual(r));
3771    return r;
3772 }
3773 
3774 /* DO NOT CALL THIS DIRECTLY */
iselFltExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3775 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3776 {
3777    Bool        mode64 = env->mode64;
3778 
3779    IRType ty = typeOfIRExpr(env->type_env,e);
3780    vassert(ty == Ity_F32);
3781 
3782    if (e->tag == Iex_RdTmp) {
3783       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3784    }
3785 
3786    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3787       PPCAMode* am_addr;
3788       HReg r_dst = newVRegF(env);
3789       vassert(e->Iex.Load.ty == Ity_F32);
3790       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/,
3791                                    IEndianess);
3792       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
3793       return r_dst;
3794    }
3795 
3796    if (e->tag == Iex_Get) {
3797       HReg r_dst = newVRegF(env);
3798       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3799                                        GuestStatePtr(env->mode64) );
3800       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
3801       return r_dst;
3802    }
3803 
3804    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3805       /* This is quite subtle.  The only way to do the relevant
3806          truncation is to do a single-precision store and then a
3807          double precision load to get it back into a register.  The
3808          problem is, if the data is then written to memory a second
3809          time, as in
3810 
3811             STbe(...) = TruncF64asF32(...)
3812 
3813          then will the second truncation further alter the value?  The
3814          answer is no: flds (as generated here) followed by fsts
3815          (generated for the STbe) is the identity function on 32-bit
3816          floats, so we are safe.
3817 
3818          Another upshot of this is that if iselStmt can see the
3819          entirety of
3820 
3821             STbe(...) = TruncF64asF32(arg)
3822 
3823          then it can short circuit having to deal with TruncF64asF32
3824          individually; instead just compute arg into a 64-bit FP
3825          register and do 'fsts' (since that itself does the
3826          truncation).
3827 
3828          We generate pretty poor code here (should be ok both for
3829          32-bit and 64-bit mode); but it is expected that for the most
3830          part the latter optimisation will apply and hence this code
3831          will not often be used.
3832       */
3833       HReg      fsrc    = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
3834       HReg      fdst    = newVRegF(env);
3835       PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3836 
3837       sub_from_sp( env, 16 );
3838       // store as F32, hence truncating
3839       addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3840                                      fsrc, zero_r1 ));
3841       // and reload.  Good huh?! (sigh)
3842       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3843                                      fdst, zero_r1 ));
3844       add_to_sp( env, 16 );
3845       return fdst;
3846    }
3847 
3848    if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3849       if (mode64) {
3850          HReg fdst = newVRegF(env);
3851          HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
3852          HReg r1   = StackFramePtr(env->mode64);
3853          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3854 
3855          /* Set host rounding mode */
3856          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3857 
3858          sub_from_sp( env, 16 );
3859 
3860          addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3861          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3862          addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3863                                        False, False,
3864                                        fdst, fdst));
3865 
3866          add_to_sp( env, 16 );
3867 
3868          ///* Restore default FPU rounding. */
3869          //set_FPU_rounding_default( env );
3870          return fdst;
3871       } else {
3872          /* 32-bit mode */
3873          HReg fdst = newVRegF(env);
3874          HReg isrcHi, isrcLo;
3875          HReg r1   = StackFramePtr(env->mode64);
3876          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3877          PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3878 
3879          iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2, IEndianess);
3880 
3881          /* Set host rounding mode */
3882          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
3883 
3884          sub_from_sp( env, 16 );
3885 
3886          addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3887          addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3888          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3889          addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3890                                        False, False,
3891                                        fdst, fdst));
3892 
3893          add_to_sp( env, 16 );
3894 
3895          ///* Restore default FPU rounding. */
3896          //set_FPU_rounding_default( env );
3897          return fdst;
3898       }
3899 
3900    }
3901 
3902    vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3903    ppIRExpr(e);
3904    vpanic("iselFltExpr_wrk(ppc)");
3905 }
3906 
3907 
3908 /*---------------------------------------------------------*/
3909 /*--- ISEL: Floating point expressions (64 bit)         ---*/
3910 /*---------------------------------------------------------*/
3911 
3912 /* Compute a 64-bit floating point value into a register, the identity
3913    of which is returned.  As with iselIntExpr_R, the reg may be either
3914    real or virtual; in any case it must not be changed by subsequent
3915    code emitted by the caller.  */
3916 
3917 /* IEEE 754 formats.  From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3918 
3919     Type                  S (1 bit)   E (11 bits)   F (52 bits)
3920     ----                  ---------   -----------   -----------
3921     signalling NaN        u           2047 (max)    .0uuuuu---u
3922                                                     (with at least
3923                                                      one 1 bit)
3924     quiet NaN             u           2047 (max)    .1uuuuu---u
3925 
3926     negative infinity     1           2047 (max)    .000000---0
3927 
3928     positive infinity     0           2047 (max)    .000000---0
3929 
3930     negative zero         1           0             .000000---0
3931 
3932     positive zero         0           0             .000000---0
3933 */
3934 
iselDblExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)3935 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3936 {
3937    HReg r = iselDblExpr_wrk( env, e, IEndianess );
3938 #  if 0
3939    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3940 #  endif
3941    vassert(hregClass(r) == HRcFlt64);
3942    vassert(hregIsVirtual(r));
3943    return r;
3944 }
3945 
3946 /* DO NOT CALL THIS DIRECTLY */
iselDblExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)3947 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
3948 {
3949    Bool mode64 = env->mode64;
3950    IRType ty = typeOfIRExpr(env->type_env,e);
3951    vassert(e);
3952    vassert(ty == Ity_F64);
3953 
3954    if (e->tag == Iex_RdTmp) {
3955       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3956    }
3957 
3958    /* --------- LITERAL --------- */
3959    if (e->tag == Iex_Const) {
3960       union { UInt u32x2[2]; ULong u64; Double f64; } u;
3961       vassert(sizeof(u) == 8);
3962       vassert(sizeof(u.u64) == 8);
3963       vassert(sizeof(u.f64) == 8);
3964       vassert(sizeof(u.u32x2) == 8);
3965 
3966       if (e->Iex.Const.con->tag == Ico_F64) {
3967          u.f64 = e->Iex.Const.con->Ico.F64;
3968       }
3969       else if (e->Iex.Const.con->tag == Ico_F64i) {
3970          u.u64 = e->Iex.Const.con->Ico.F64i;
3971       }
3972       else
3973          vpanic("iselDblExpr(ppc): const");
3974 
3975       if (!mode64) {
3976          HReg r_srcHi = newVRegI(env);
3977          HReg r_srcLo = newVRegI(env);
3978          addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3979          addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3980          return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3981       } else { // mode64
3982          HReg r_src = newVRegI(env);
3983          addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3984          return mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
3985       }
3986    }
3987 
3988    /* --------- LOAD --------- */
3989    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
3990       HReg r_dst = newVRegF(env);
3991       PPCAMode* am_addr;
3992       vassert(e->Iex.Load.ty == Ity_F64);
3993       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/,
3994                                    IEndianess);
3995       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3996       return r_dst;
3997    }
3998 
3999    /* --------- GET --------- */
4000    if (e->tag == Iex_Get) {
4001       HReg r_dst = newVRegF(env);
4002       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4003                                        GuestStatePtr(mode64) );
4004       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
4005       return r_dst;
4006    }
4007 
4008    /* --------- OPS --------- */
4009    if (e->tag == Iex_Qop) {
4010       PPCFpOp fpop = Pfp_INVALID;
4011       switch (e->Iex.Qop.details->op) {
4012          case Iop_MAddF64:    fpop = Pfp_MADDD; break;
4013          case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
4014          case Iop_MSubF64:    fpop = Pfp_MSUBD; break;
4015          case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
4016          default: break;
4017       }
4018       if (fpop != Pfp_INVALID) {
4019          HReg r_dst  = newVRegF(env);
4020          HReg r_srcML  = iselDblExpr(env, e->Iex.Qop.details->arg2,
4021                                      IEndianess);
4022          HReg r_srcMR  = iselDblExpr(env, e->Iex.Qop.details->arg3,
4023                                      IEndianess);
4024          HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.details->arg4,
4025                                      IEndianess);
4026          set_FPU_rounding_mode( env, e->Iex.Qop.details->arg1, IEndianess );
4027          addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
4028                                                r_srcML, r_srcMR, r_srcAcc));
4029          return r_dst;
4030       }
4031    }
4032 
4033    if (e->tag == Iex_Triop) {
4034       IRTriop *triop = e->Iex.Triop.details;
4035       PPCFpOp fpop = Pfp_INVALID;
4036       switch (triop->op) {
4037          case Iop_AddF64:    fpop = Pfp_ADDD; break;
4038          case Iop_SubF64:    fpop = Pfp_SUBD; break;
4039          case Iop_MulF64:    fpop = Pfp_MULD; break;
4040          case Iop_DivF64:    fpop = Pfp_DIVD; break;
4041          case Iop_AddF64r32: fpop = Pfp_ADDS; break;
4042          case Iop_SubF64r32: fpop = Pfp_SUBS; break;
4043          case Iop_MulF64r32: fpop = Pfp_MULS; break;
4044          case Iop_DivF64r32: fpop = Pfp_DIVS; break;
4045          default: break;
4046       }
4047       if (fpop != Pfp_INVALID) {
4048          HReg r_dst  = newVRegF(env);
4049          HReg r_srcL = iselDblExpr(env, triop->arg2, IEndianess);
4050          HReg r_srcR = iselDblExpr(env, triop->arg3, IEndianess);
4051          set_FPU_rounding_mode( env, triop->arg1, IEndianess );
4052          addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
4053          return r_dst;
4054       }
4055    }
4056 
4057    if (e->tag == Iex_Binop) {
4058       PPCFpOp fpop = Pfp_INVALID;
4059       switch (e->Iex.Binop.op) {
4060       case Iop_SqrtF64:   fpop = Pfp_SQRT;   break;
4061       default: break;
4062       }
4063       if (fpop == Pfp_SQRT) {
4064          HReg fr_dst = newVRegF(env);
4065          HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4066          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4067          addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4068          return fr_dst;
4069       }
4070    }
4071 
4072    if (e->tag == Iex_Binop) {
4073 
4074       if (e->Iex.Binop.op == Iop_RoundF64toF32) {
4075          HReg r_dst = newVRegF(env);
4076          HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4077          set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4078          addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
4079          //set_FPU_rounding_default( env );
4080          return r_dst;
4081       }
4082 
4083       if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
4084          if (mode64) {
4085             HReg fdst = newVRegF(env);
4086             HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4087             HReg r1   = StackFramePtr(env->mode64);
4088             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4089 
4090             /* Set host rounding mode */
4091             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4092 
4093             sub_from_sp( env, 16 );
4094 
4095             addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
4096             addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4097             addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4098                                           e->Iex.Binop.op == Iop_I64StoF64,
4099                                           True/*fdst is 64 bit*/,
4100                                           fdst, fdst));
4101 
4102             add_to_sp( env, 16 );
4103 
4104             ///* Restore default FPU rounding. */
4105             //set_FPU_rounding_default( env );
4106             return fdst;
4107          } else {
4108             /* 32-bit mode */
4109             HReg fdst = newVRegF(env);
4110             HReg isrcHi, isrcLo;
4111             HReg r1   = StackFramePtr(env->mode64);
4112             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
4113             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
4114 
4115             iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2,
4116                           IEndianess);
4117 
4118             /* Set host rounding mode */
4119             set_FPU_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4120 
4121             sub_from_sp( env, 16 );
4122 
4123             addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
4124             addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
4125             addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
4126             addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
4127                                           e->Iex.Binop.op == Iop_I64StoF64,
4128                                           True/*fdst is 64 bit*/,
4129                                           fdst, fdst));
4130 
4131             add_to_sp( env, 16 );
4132 
4133             ///* Restore default FPU rounding. */
4134             //set_FPU_rounding_default( env );
4135             return fdst;
4136          }
4137       }
4138 
4139    }
4140 
4141    if (e->tag == Iex_Unop) {
4142       PPCFpOp fpop = Pfp_INVALID;
4143       switch (e->Iex.Unop.op) {
4144          case Iop_NegF64:     fpop = Pfp_NEG; break;
4145          case Iop_AbsF64:     fpop = Pfp_ABS; break;
4146          case Iop_RSqrtEst5GoodF64:      fpop = Pfp_RSQRTE; break;
4147          case Iop_RoundF64toF64_NegINF:  fpop = Pfp_FRIM; break;
4148          case Iop_RoundF64toF64_PosINF:  fpop = Pfp_FRIP; break;
4149          case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
4150          case Iop_RoundF64toF64_ZERO:    fpop = Pfp_FRIZ; break;
4151          default: break;
4152       }
4153       if (fpop != Pfp_INVALID) {
4154          HReg fr_dst = newVRegF(env);
4155          HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg, IEndianess);
4156          addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
4157          return fr_dst;
4158       }
4159    }
4160 
4161    if (e->tag == Iex_Unop) {
4162       switch (e->Iex.Unop.op) {
4163          case Iop_ReinterpI64asF64: {
4164             /* Given an I64, produce an IEEE754 double with the same
4165                bit pattern. */
4166             if (!mode64) {
4167                HReg r_srcHi, r_srcLo;
4168                iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4169                                IEndianess);
4170                return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4171             } else {
4172                HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4173                return mk_LoadR64toFPR( env, r_src );
4174             }
4175          }
4176 
4177          case Iop_F32toF64: {
4178             if (e->Iex.Unop.arg->tag == Iex_Unop &&
4179                      e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) {
4180                e = e->Iex.Unop.arg;
4181 
4182                HReg src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4183                HReg fr_dst = newVRegF(env);
4184                PPCAMode *am_addr;
4185 
4186                sub_from_sp( env, 16 );        // Move SP down 16 bytes
4187                am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4188 
4189                // store src as Ity_I32's
4190                addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 ));
4191 
4192                // load single precision float, but the end results loads into a
4193                // 64-bit FP register -- i.e., F64.
4194                addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr));
4195 
4196                add_to_sp( env, 16 );          // Reset SP
4197                return fr_dst;
4198             }
4199 
4200 
4201             /* this is a no-op */
4202             HReg res = iselFltExpr(env, e->Iex.Unop.arg, IEndianess);
4203             return res;
4204          }
4205          default:
4206             break;
4207       }
4208    }
4209 
4210    /* --------- MULTIPLEX --------- */
4211    if (e->tag == Iex_ITE) { // VFD
4212       if (ty == Ity_F64
4213           && typeOfIRExpr(env->type_env,e->Iex.ITE.cond) == Ity_I1) {
4214          HReg fr1    = iselDblExpr(env, e->Iex.ITE.iftrue, IEndianess);
4215          HReg fr0    = iselDblExpr(env, e->Iex.ITE.iffalse, IEndianess);
4216          HReg fr_dst = newVRegF(env);
4217          addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, fr0 ));
4218          PPCCondCode cc = iselCondCode(env, e->Iex.ITE.cond, IEndianess);
4219          addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr1 ));
4220          return fr_dst;
4221       }
4222    }
4223 
4224    vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
4225    ppIRExpr(e);
4226    vpanic("iselDblExpr_wrk(ppc)");
4227 }
4228 
iselDfp32Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4229 static HReg iselDfp32Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4230 {
4231    HReg r = iselDfp32Expr_wrk( env, e, IEndianess );
4232    vassert(hregClass(r) == HRcFlt64);
4233    vassert( hregIsVirtual(r) );
4234    return r;
4235 }
4236 
4237 /* DO NOT CALL THIS DIRECTLY */
iselDfp32Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4238 static HReg iselDfp32Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4239 {
4240    Bool mode64 = env->mode64;
4241    IRType ty = typeOfIRExpr( env->type_env, e );
4242 
4243    vassert( e );
4244    vassert( ty == Ity_D32 );
4245 
4246    /* --------- GET --------- */
4247    if (e->tag == Iex_Get) {
4248       HReg r_dst = newVRegF( env );
4249       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4250                                        GuestStatePtr(mode64) );
4251       addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4252       return r_dst;
4253    }
4254 
4255    /* --------- LOAD --------- */
4256    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4257       PPCAMode* am_addr;
4258       HReg r_dst = newVRegF(env);
4259       vassert(e->Iex.Load.ty == Ity_D32);
4260       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D32/*xfer*/,
4261                                    IEndianess);
4262       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
4263       return r_dst;
4264    }
4265 
4266    /* --------- OPS --------- */
4267    if (e->tag == Iex_Binop) {
4268       if (e->Iex.Binop.op == Iop_D64toD32) {
4269          HReg fr_dst = newVRegF(env);
4270          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4271          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4272          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DRSP, fr_dst, fr_src));
4273          return fr_dst;
4274       }
4275    }
4276 
4277    ppIRExpr( e );
4278    vpanic( "iselDfp32Expr_wrk(ppc)" );
4279 }
4280 
iselDfp64Expr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4281 static HReg iselDfp64Expr(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4282 {
4283    HReg r = iselDfp64Expr_wrk( env, e, IEndianess );
4284    vassert(hregClass(r) == HRcFlt64);
4285    vassert( hregIsVirtual(r) );
4286    return r;
4287 }
4288 
4289 /* DO NOT CALL THIS DIRECTLY */
iselDfp64Expr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4290 static HReg iselDfp64Expr_wrk(ISelEnv* env, IRExpr* e, IREndness IEndianess)
4291 {
4292    Bool mode64 = env->mode64;
4293    IRType ty = typeOfIRExpr( env->type_env, e );
4294    HReg r_dstHi, r_dstLo;
4295 
4296    vassert( e );
4297    vassert( ty == Ity_D64 );
4298 
4299    if (e->tag == Iex_RdTmp) {
4300       return lookupIRTemp( env, e->Iex.RdTmp.tmp );
4301    }
4302 
4303    /* --------- GET --------- */
4304    if (e->tag == Iex_Get) {
4305       HReg r_dst = newVRegF( env );
4306       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
4307                                        GuestStatePtr(mode64) );
4308       addInstr( env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ) );
4309       return r_dst;
4310    }
4311 
4312    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4313       PPCAMode* am_addr;
4314       HReg r_dst = newVRegF(env);
4315       vassert(e->Iex.Load.ty == Ity_D64);
4316       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_D64/*xfer*/,
4317                                    IEndianess);
4318       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
4319       return r_dst;
4320    }
4321 
4322    /* --------- OPS --------- */
4323    if (e->tag == Iex_Qop) {
4324       HReg r_dst = newVRegF( env );
4325       return r_dst;
4326    }
4327 
4328    if (e->tag == Iex_Unop) {
4329       HReg fr_dst = newVRegF(env);
4330       switch (e->Iex.Unop.op) {
4331       case Iop_ReinterpI64asD64: {
4332          /* Given an I64, produce an IEEE754 DFP with the same
4333                bit pattern. */
4334          if (!mode64) {
4335             HReg r_srcHi, r_srcLo;
4336             iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg,
4337                            IEndianess);
4338             return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
4339          } else {
4340             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4341             return mk_LoadR64toFPR( env, r_src );
4342          }
4343       }
4344       case Iop_D32toD64: {
4345          HReg fr_src = iselDfp32Expr(env, e->Iex.Unop.arg, IEndianess);
4346          addInstr(env, PPCInstr_Dfp64Unary(Pfp_DCTDP, fr_dst, fr_src));
4347          return fr_dst;
4348       }
4349       case Iop_D128HItoD64:
4350          iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4351                          IEndianess );
4352          return r_dstHi;
4353       case Iop_D128LOtoD64:
4354          iselDfp128Expr( &r_dstHi, &r_dstLo, env, e->Iex.Unop.arg,
4355                          IEndianess );
4356          return r_dstLo;
4357       case Iop_InsertExpD64: {
4358          HReg fr_srcL = iselDblExpr(env, e->Iex.Binop.arg1, IEndianess);
4359          HReg fr_srcR = iselDblExpr(env, e->Iex.Binop.arg2, IEndianess);
4360 
4361          addInstr(env, PPCInstr_Dfp64Binary(Pfp_DIEX, fr_dst, fr_srcL,
4362 					    fr_srcR));
4363          return fr_dst;
4364        }
4365       default:
4366          vex_printf( "ERROR: iselDfp64Expr_wrk, UNKNOWN unop case %d\n",
4367                      (Int)e->Iex.Unop.op );
4368       }
4369    }
4370 
4371    if (e->tag == Iex_Binop) {
4372       PPCFpOp fpop = Pfp_INVALID;
4373       HReg fr_dst = newVRegF(env);
4374 
4375       switch (e->Iex.Binop.op) {
4376       case Iop_D128toD64:     fpop = Pfp_DRDPQ;  break;
4377       case Iop_D64toD32:      fpop = Pfp_DRSP;   break;
4378       case Iop_I64StoD64:     fpop = Pfp_DCFFIX; break;
4379       case Iop_RoundD64toInt: fpop = Pfp_DRINTN; break;
4380       default: break;
4381       }
4382       if (fpop == Pfp_DRDPQ) {
4383          HReg r_srcHi = newVRegF(env);
4384          HReg r_srcLo = newVRegF(env);
4385 
4386          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4387          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4388                         IEndianess);
4389          addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4390          return fr_dst;
4391 
4392       } else if (fpop == Pfp_DRINTN) {
4393          HReg fr_src = newVRegF(env);
4394          PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4395 
4396          /* NOTE, this IOP takes a DFP value and rounds to the
4397           * neares floating point integer value, i.e. fractional part
4398           * is zero.  The result is a decimal floating point number.
4399           * the INT in the name is a bit misleading.
4400           */
4401          fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4402          addInstr(env, PPCInstr_DfpRound(fr_dst, fr_src, r_rmc));
4403          return fr_dst;
4404 
4405       } else if (fpop == Pfp_DRSP) {
4406          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4407          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4408          addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4409          return fr_dst;
4410 
4411       } else if (fpop == Pfp_DCFFIX) {
4412          HReg fr_src = newVRegF(env);
4413          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4414 
4415          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4416          sub_from_sp( env, 16 );
4417 
4418          // put the I64 value into a floating point register
4419          if (mode64) {
4420            HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
4421 
4422            addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4423          } else {
4424             HReg tmpHi, tmpLo;
4425             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4426 
4427             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg2,
4428                           IEndianess);
4429             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4430             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4431          }
4432 
4433          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8,  fr_src, zero_r1));
4434          addInstr(env, PPCInstr_Dfp64Unary(fpop, fr_dst, fr_src));
4435          add_to_sp( env, 16 );
4436          return fr_dst;
4437       }
4438 
4439       switch (e->Iex.Binop.op) {
4440       /* shift instructions D64, I32 -> D64 */
4441       case Iop_ShlD64: fpop = Pfp_DSCLI; break;
4442       case Iop_ShrD64: fpop = Pfp_DSCRI; break;
4443       default: break;
4444       }
4445       if (fpop != Pfp_INVALID) {
4446          HReg fr_src = iselDfp64Expr(env, e->Iex.Binop.arg1, IEndianess);
4447          PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4448 
4449          /* shift value must be an immediate value */
4450          vassert(shift->tag == Pri_Imm);
4451 
4452          addInstr(env, PPCInstr_DfpShift(fpop, fr_dst, fr_src, shift));
4453          return fr_dst;
4454       }
4455 
4456       switch (e->Iex.Binop.op) {
4457       case Iop_InsertExpD64:
4458          fpop = Pfp_DIEX;
4459          break;
4460       default: 	break;
4461       }
4462       if (fpop != Pfp_INVALID) {
4463          HReg fr_srcL = newVRegF(env);
4464          HReg fr_srcR = iselDfp64Expr(env, e->Iex.Binop.arg2, IEndianess);
4465          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4466          sub_from_sp( env, 16 );
4467 
4468          if (env->mode64) {
4469             // put the I64 value into a floating point reg
4470             HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4471 
4472             addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4473          } else {
4474             // put the I64 register pair into a floating point reg
4475             HReg tmpHi;
4476             HReg tmpLo;
4477             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4478 
4479             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Binop.arg1,
4480                           IEndianess);
4481             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*!mode64*/));
4482             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*!mode64*/));
4483          }
4484          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_srcL, zero_r1));
4485          addInstr(env, PPCInstr_Dfp64Binary(fpop, fr_dst, fr_srcL,
4486                                             fr_srcR));
4487          add_to_sp( env, 16 );
4488          return fr_dst;
4489       }
4490    }
4491 
4492    if (e->tag == Iex_Triop) {
4493       IRTriop *triop = e->Iex.Triop.details;
4494       PPCFpOp fpop = Pfp_INVALID;
4495 
4496       switch (triop->op) {
4497       case Iop_AddD64:
4498          fpop = Pfp_DFPADD;
4499          break;
4500       case Iop_SubD64:
4501          fpop = Pfp_DFPSUB;
4502          break;
4503       case Iop_MulD64:
4504          fpop = Pfp_DFPMUL;
4505          break;
4506       case Iop_DivD64:
4507          fpop = Pfp_DFPDIV;
4508          break;
4509       default:
4510          break;
4511       }
4512       if (fpop != Pfp_INVALID) {
4513          HReg r_dst = newVRegF( env );
4514          HReg r_srcL = iselDfp64Expr( env, triop->arg2, IEndianess );
4515          HReg r_srcR = iselDfp64Expr( env, triop->arg3, IEndianess );
4516 
4517          set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4518          addInstr( env, PPCInstr_Dfp64Binary( fpop, r_dst, r_srcL, r_srcR ) );
4519          return r_dst;
4520       }
4521 
4522       switch (triop->op) {
4523       case Iop_QuantizeD64:          fpop = Pfp_DQUA;  break;
4524       case Iop_SignificanceRoundD64: fpop = Pfp_RRDTR; break;
4525       default: break;
4526       }
4527       if (fpop == Pfp_DQUA) {
4528          HReg r_dst = newVRegF(env);
4529          HReg r_srcL = iselDfp64Expr(env, triop->arg2, IEndianess);
4530          HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4531          PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1, IEndianess);
4532          addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR,
4533                                             rmc));
4534          return r_dst;
4535 
4536       } else if (fpop == Pfp_RRDTR) {
4537          HReg r_dst = newVRegF(env);
4538          HReg r_srcL = newVRegF(env);
4539          HReg r_srcR = iselDfp64Expr(env, triop->arg3, IEndianess);
4540          PPCRI* rmc  = iselWordExpr_RI(env, triop->arg1, IEndianess);
4541          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4542          HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4543 
4544          /* Move I8 to float register to issue instruction */
4545          sub_from_sp( env, 16 );
4546          if (mode64)
4547             addInstr(env, PPCInstr_Store(8, zero_r1, i8_val, True/*mode64*/));
4548          else
4549             addInstr(env, PPCInstr_Store(4, zero_r1, i8_val, False/*mode32*/));
4550 
4551          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4552          add_to_sp( env, 16 );
4553 
4554          // will set TE and RMC when issuing instruction
4555          addInstr(env, PPCInstr_DfpQuantize(fpop, r_dst, r_srcL, r_srcR, rmc));
4556          return r_dst;
4557       }
4558    }
4559 
4560    ppIRExpr( e );
4561    vpanic( "iselDfp64Expr_wrk(ppc)" );
4562 }
4563 
iselDfp128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4564 static void iselDfp128Expr(HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e,
4565                            IREndness IEndianess)
4566 {
4567    iselDfp128Expr_wrk( rHi, rLo, env, e, IEndianess );
4568    vassert( hregIsVirtual(*rHi) );
4569    vassert( hregIsVirtual(*rLo) );
4570 }
4571 
4572 /* DO NOT CALL THIS DIRECTLY */
iselDfp128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e,IREndness IEndianess)4573 static void iselDfp128Expr_wrk(HReg* rHi, HReg *rLo, ISelEnv* env, IRExpr* e,
4574                                IREndness IEndianess)
4575 {
4576    vassert( e );
4577    vassert( typeOfIRExpr(env->type_env,e) == Ity_D128 );
4578 
4579    /* read 128-bit IRTemp */
4580    if (e->tag == Iex_RdTmp) {
4581       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp );
4582       return;
4583    }
4584 
4585    if (e->tag == Iex_Unop) {
4586       HReg r_dstHi = newVRegF(env);
4587       HReg r_dstLo = newVRegF(env);
4588 
4589       if (e->Iex.Unop.op == Iop_I64StoD128) {
4590          HReg fr_src = newVRegF(env);
4591          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4592 
4593          // put the I64 value into a floating point reg
4594          if (env->mode64) {
4595             HReg tmp   = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
4596             addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4597          } else {
4598             HReg tmpHi, tmpLo;
4599             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4600 
4601             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4602                           IEndianess);
4603             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4604             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4605          }
4606 
4607          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_src, zero_r1));
4608          addInstr(env, PPCInstr_DfpI64StoD128(Pfp_DCFFIXQ, r_dstHi, r_dstLo,
4609                                               fr_src));
4610       }
4611 
4612       if (e->Iex.Unop.op == Iop_D64toD128) {
4613          HReg r_src = iselDfp64Expr(env, e->Iex.Unop.arg, IEndianess);
4614 
4615          /* Source is 64bit, result is 128 bit.  High 64bit source arg,
4616           * is ignored by the instruction.  Set high arg to r_src just
4617           * to meet the vassert tests.
4618           */
4619          addInstr(env, PPCInstr_Dfp128Unary(Pfp_DCTQPQ, r_dstHi, r_dstLo,
4620                                             r_src, r_src));
4621       }
4622       *rHi = r_dstHi;
4623       *rLo = r_dstLo;
4624       return;
4625    }
4626 
4627    /* --------- OPS --------- */
4628    if (e->tag == Iex_Binop) {
4629       HReg r_srcHi;
4630       HReg r_srcLo;
4631 
4632       switch (e->Iex.Binop.op) {
4633       case Iop_D64HLtoD128:
4634          r_srcHi = iselDfp64Expr( env, e->Iex.Binop.arg1, IEndianess );
4635          r_srcLo = iselDfp64Expr( env, e->Iex.Binop.arg2, IEndianess );
4636          *rHi = r_srcHi;
4637          *rLo = r_srcLo;
4638          return;
4639          break;
4640       case Iop_D128toD64: {
4641          PPCFpOp fpop = Pfp_DRDPQ;
4642          HReg fr_dst  = newVRegF(env);
4643 
4644          set_FPU_DFP_rounding_mode( env, e->Iex.Binop.arg1, IEndianess );
4645          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4646                         IEndianess);
4647          addInstr(env, PPCInstr_DfpD128toD64(fpop, fr_dst, r_srcHi, r_srcLo));
4648 
4649          /* Need to meet the interface spec but the result is
4650           * just 64-bits so send the result back in both halfs.
4651           */
4652          *rHi = fr_dst;
4653          *rLo = fr_dst;
4654          return;
4655       }
4656       case Iop_ShlD128:
4657       case Iop_ShrD128: {
4658          HReg fr_dst_hi = newVRegF(env);
4659          HReg fr_dst_lo = newVRegF(env);
4660          PPCRI* shift = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
4661          PPCFpOp fpop = Pfp_DSCLIQ;  /* fix later if necessary */
4662 
4663          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1,
4664                         IEndianess);
4665 
4666          if (e->Iex.Binop.op == Iop_ShrD128)
4667             fpop = Pfp_DSCRIQ;
4668 
4669          addInstr(env, PPCInstr_DfpShift128(fpop, fr_dst_hi, fr_dst_lo,
4670                                             r_srcHi, r_srcLo, shift));
4671 
4672          *rHi = fr_dst_hi;
4673          *rLo = fr_dst_lo;
4674          return;
4675       }
4676       case Iop_RoundD128toInt: {
4677          HReg r_dstHi = newVRegF(env);
4678          HReg r_dstLo = newVRegF(env);
4679          PPCRI* r_rmc = iselWordExpr_RI(env, e->Iex.Binop.arg1, IEndianess);
4680 
4681          // will set R and RMC when issuing instruction
4682          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4683                         IEndianess);
4684 
4685          addInstr(env, PPCInstr_DfpRound128(r_dstHi, r_dstLo,
4686                                             r_srcHi, r_srcLo, r_rmc));
4687          *rHi = r_dstHi;
4688          *rLo = r_dstLo;
4689          return;
4690       }
4691       case Iop_InsertExpD128: {
4692          HReg r_dstHi = newVRegF(env);
4693          HReg r_dstLo = newVRegF(env);
4694          HReg r_srcL  = newVRegF(env);
4695          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4696          r_srcHi = newVRegF(env);
4697          r_srcLo = newVRegF(env);
4698 
4699          iselDfp128Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg2,
4700                         IEndianess);
4701 
4702          /* Move I64 to float register to issue instruction */
4703          if (env->mode64) {
4704             HReg tmp = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
4705             addInstr(env, PPCInstr_Store(8, zero_r1, tmp, True/*mode64*/));
4706          } else {
4707             HReg tmpHi, tmpLo;
4708             PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4709 
4710             iselInt64Expr(&tmpHi, &tmpLo, env, e->Iex.Unop.arg,
4711                           IEndianess);
4712             addInstr(env, PPCInstr_Store(4, zero_r1, tmpHi, False/*mode32*/));
4713             addInstr(env, PPCInstr_Store(4, four_r1, tmpLo, False/*mode32*/));
4714          }
4715 
4716          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_srcL, zero_r1));
4717          addInstr(env, PPCInstr_InsertExpD128(Pfp_DIEXQ,
4718                                               r_dstHi, r_dstLo,
4719                                               r_srcL, r_srcHi, r_srcLo));
4720          *rHi = r_dstHi;
4721          *rLo = r_dstLo;
4722          return;
4723       }
4724       default:
4725          vex_printf( "ERROR: iselDfp128Expr_wrk, UNKNOWN binop case %d\n",
4726                      (Int)e->Iex.Binop.op );
4727          break;
4728       }
4729    }
4730 
4731    if (e->tag == Iex_Triop) {
4732       IRTriop *triop = e->Iex.Triop.details;
4733       PPCFpOp fpop = Pfp_INVALID;
4734       HReg r_dstHi = newVRegF(env);
4735       HReg r_dstLo = newVRegF(env);
4736 
4737       switch (triop->op) {
4738       case Iop_AddD128:
4739          fpop = Pfp_DFPADDQ;
4740          break;
4741       case Iop_SubD128:
4742          fpop = Pfp_DFPSUBQ;
4743          break;
4744       case Iop_MulD128:
4745          fpop = Pfp_DFPMULQ;
4746          break;
4747       case Iop_DivD128:
4748          fpop = Pfp_DFPDIVQ;
4749          break;
4750       default:
4751          break;
4752       }
4753 
4754       if (fpop != Pfp_INVALID) {
4755          HReg r_srcRHi = newVRegV( env );
4756          HReg r_srcRLo = newVRegV( env );
4757 
4758          /* dst will be used to pass in the left operand and get the result. */
4759          iselDfp128Expr( &r_dstHi, &r_dstLo, env, triop->arg2, IEndianess );
4760          iselDfp128Expr( &r_srcRHi, &r_srcRLo, env, triop->arg3, IEndianess );
4761          set_FPU_DFP_rounding_mode( env, triop->arg1, IEndianess );
4762          addInstr( env,
4763                    PPCInstr_Dfp128Binary( fpop, r_dstHi, r_dstLo,
4764                                           r_srcRHi, r_srcRLo ) );
4765          *rHi = r_dstHi;
4766          *rLo = r_dstLo;
4767          return;
4768       }
4769       switch (triop->op) {
4770       case Iop_QuantizeD128:          fpop = Pfp_DQUAQ;  break;
4771       case Iop_SignificanceRoundD128: fpop = Pfp_DRRNDQ; break;
4772       default: break;
4773       }
4774       if (fpop == Pfp_DQUAQ) {
4775          HReg r_srcHi = newVRegF(env);
4776          HReg r_srcLo = newVRegF(env);
4777          PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4778 
4779          /* dst will be used to pass in the left operand and get the result */
4780          iselDfp128Expr(&r_dstHi, &r_dstLo, env, triop->arg2, IEndianess);
4781          iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4782 
4783          // will set RMC when issuing instruction
4784          addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4785                                                r_srcHi, r_srcLo, rmc));
4786         *rHi = r_dstHi;
4787         *rLo = r_dstLo;
4788          return;
4789 
4790       } else if (fpop == Pfp_DRRNDQ) {
4791          HReg r_srcHi = newVRegF(env);
4792          HReg r_srcLo = newVRegF(env);
4793          PPCRI* rmc = iselWordExpr_RI(env, triop->arg1, IEndianess);
4794          PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
4795          PPCAMode* four_r1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
4796          HReg i8_val = iselWordExpr_R(env, triop->arg2, IEndianess);
4797          HReg r_zero = newVRegI( env );
4798 
4799          iselDfp128Expr(&r_srcHi, &r_srcLo, env, triop->arg3, IEndianess);
4800 
4801          /* dst will be used to pass in the left operand and get the result */
4802          /* Move I8 to float register to issue instruction.  Note, the
4803           * instruction only looks at the bottom 6 bits so we really don't
4804           * have to clear the upper bits since the iselWordExpr_R sets the
4805           * bottom 8-bits.
4806           */
4807          sub_from_sp( env, 16 );
4808 
4809          if (env->mode64)
4810             addInstr(env, PPCInstr_Store(4, four_r1, i8_val, True/*mode64*/));
4811          else
4812             addInstr(env, PPCInstr_Store(4, four_r1, i8_val, False/*mode32*/));
4813 
4814          /* Have to write to the upper bits to ensure they have been
4815           * initialized. The instruction ignores all but the lower 6-bits.
4816           */
4817          addInstr( env, PPCInstr_LI( r_zero, 0, env->mode64 ) );
4818          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstHi, zero_r1));
4819          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dstLo, zero_r1));
4820 
4821          add_to_sp( env, 16 );
4822 
4823          // will set RMC when issuing instruction
4824          addInstr(env, PPCInstr_DfpQuantize128(fpop, r_dstHi, r_dstLo,
4825                                                r_srcHi, r_srcLo, rmc));
4826          *rHi = r_dstHi;
4827          *rLo = r_dstLo;
4828          return;
4829       }
4830  }
4831 
4832    ppIRExpr( e );
4833    vpanic( "iselDfp128Expr(ppc64)" );
4834 }
4835 
4836 
4837 /*---------------------------------------------------------*/
4838 /*--- ISEL: SIMD (Vector) expressions, 128 bit.         ---*/
4839 /*---------------------------------------------------------*/
4840 
iselVecExpr(ISelEnv * env,IRExpr * e,IREndness IEndianess)4841 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4842 {
4843    HReg r = iselVecExpr_wrk( env, e, IEndianess );
4844 #  if 0
4845    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
4846 #  endif
4847    vassert(hregClass(r) == HRcVec128);
4848    vassert(hregIsVirtual(r));
4849    return r;
4850 }
4851 
4852 /* DO NOT CALL THIS DIRECTLY */
iselVecExpr_wrk(ISelEnv * env,IRExpr * e,IREndness IEndianess)4853 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e, IREndness IEndianess )
4854 {
4855    Bool mode64 = env->mode64;
4856    PPCAvOp op = Pav_INVALID;
4857    PPCAvFpOp fpop = Pavfp_INVALID;
4858    IRType  ty = typeOfIRExpr(env->type_env,e);
4859    vassert(e);
4860    vassert(ty == Ity_V128);
4861 
4862    if (e->tag == Iex_RdTmp) {
4863       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
4864    }
4865 
4866    if (e->tag == Iex_Get) {
4867       /* Guest state vectors are 16byte aligned,
4868          so don't need to worry here */
4869       HReg dst = newVRegV(env);
4870       addInstr(env,
4871                PPCInstr_AvLdSt( True/*load*/, 16, dst,
4872                                 PPCAMode_IR( e->Iex.Get.offset,
4873                                              GuestStatePtr(mode64) )));
4874       return dst;
4875    }
4876 
4877    if (e->tag == Iex_Load && e->Iex.Load.end == IEndianess) {
4878       /* Need to be able to do V128 unaligned loads. The BE unaligned load
4879        * can be accomplised using the following code sequece from the ISA.
4880        * It uses the lvx instruction that does two aligned loads and then
4881        * permute the data to store the required data as if it had been an
4882        * unaligned load.
4883        *
4884        *   lvx  Vhi,0,Rb        # load MSQ, using the unaligned address in Rb
4885        *   lvsl Vp, 0,Rb        # Set permute control vector
4886        *   addi Rb,Rb,15        # Address of LSQ
4887        *   lvx  Vlo,0,Rb        # load LSQ
4888        *   vperm Vt,Vhi,Vlo,Vp  # align the data as requested
4889        */
4890 
4891       HReg Vhi   = newVRegV(env);
4892       HReg Vlo   = newVRegV(env);
4893       HReg Vp    = newVRegV(env);
4894       HReg v_dst = newVRegV(env);
4895       HReg rB;
4896       HReg rB_plus_15 = newVRegI(env);
4897 
4898       vassert(e->Iex.Load.ty == Ity_V128);
4899       rB = iselWordExpr_R( env, e->Iex.Load.addr, IEndianess );
4900 
4901       // lvx  Vhi, 0, Rb
4902       addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vhi,
4903                                      PPCAMode_IR(0, rB)) );
4904 
4905       if (IEndianess == Iend_LE)
4906          // lvsr Vp, 0, Rb
4907          addInstr(env, PPCInstr_AvSh( False/*right shift*/, Vp,
4908                                       PPCAMode_IR(0, rB)) );
4909       else
4910          // lvsl Vp, 0, Rb
4911          addInstr(env, PPCInstr_AvSh( True/*left shift*/, Vp,
4912                                       PPCAMode_IR(0, rB)) );
4913 
4914       // addi Rb_plus_15, Rb, 15
4915       addInstr(env, PPCInstr_Alu( Palu_ADD, rB_plus_15,
4916                                   rB, PPCRH_Imm(True, toUShort(15))) );
4917 
4918       // lvx  Vlo, 0, Rb_plus_15
4919       addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, Vlo,
4920                                      PPCAMode_IR(0, rB_plus_15)) );
4921 
4922       if (IEndianess == Iend_LE)
4923          // vperm Vt, Vhi, Vlo, Vp
4924          addInstr(env, PPCInstr_AvPerm( v_dst, Vlo, Vhi, Vp ));
4925       else
4926          // vperm Vt, Vhi, Vlo, Vp
4927          addInstr(env, PPCInstr_AvPerm( v_dst, Vhi, Vlo, Vp ));
4928 
4929       return v_dst;
4930    }
4931 
4932    if (e->tag == Iex_Unop) {
4933       switch (e->Iex.Unop.op) {
4934 
4935       case Iop_NotV128: {
4936          HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4937          HReg dst = newVRegV(env);
4938          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
4939          return dst;
4940       }
4941 
4942       case Iop_CmpNEZ8x16: {
4943          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4944          HReg zero = newVRegV(env);
4945          HReg dst  = newVRegV(env);
4946          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4947          addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
4948          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4949          return dst;
4950       }
4951 
4952       case Iop_CmpNEZ16x8: {
4953          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4954          HReg zero = newVRegV(env);
4955          HReg dst  = newVRegV(env);
4956          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4957          addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
4958          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4959          return dst;
4960       }
4961 
4962       case Iop_CmpNEZ32x4: {
4963          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4964          HReg zero = newVRegV(env);
4965          HReg dst  = newVRegV(env);
4966          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4967          addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
4968          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4969          return dst;
4970       }
4971 
4972       case Iop_CmpNEZ64x2: {
4973          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4974          HReg zero = newVRegV(env);
4975          HReg dst  = newVRegV(env);
4976          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
4977          addInstr(env, PPCInstr_AvBin64x2(Pav_CMPEQU, dst, arg, zero));
4978          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
4979          return dst;
4980       }
4981 
4982       case Iop_RecipEst32Fx4: fpop = Pavfp_RCPF;    goto do_32Fx4_unary;
4983       case Iop_RSqrtEst32Fx4: fpop = Pavfp_RSQRTF;  goto do_32Fx4_unary;
4984       case Iop_I32UtoFx4:     fpop = Pavfp_CVTU2F;  goto do_32Fx4_unary;
4985       case Iop_I32StoFx4:     fpop = Pavfp_CVTS2F;  goto do_32Fx4_unary;
4986       case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
4987       case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
4988       case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM;  goto do_32Fx4_unary;
4989       case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP;  goto do_32Fx4_unary;
4990       case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN;  goto do_32Fx4_unary;
4991       case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ;  goto do_32Fx4_unary;
4992       do_32Fx4_unary:
4993       {
4994          HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
4995          HReg dst = newVRegV(env);
4996          addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
4997          return dst;
4998       }
4999 
5000       case Iop_32UtoV128: {
5001          HReg r_aligned16, r_zeros;
5002          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg, IEndianess);
5003          HReg   dst = newVRegV(env);
5004          PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5005          sub_from_sp( env, 32 );     // Move SP down
5006 
5007          /* Get a quadword aligned address within our stack space */
5008          r_aligned16 = get_sp_aligned16( env );
5009          am_off0  = PPCAMode_IR( 0,  r_aligned16 );
5010          am_off4  = PPCAMode_IR( 4,  r_aligned16 );
5011          am_off8  = PPCAMode_IR( 8,  r_aligned16 );
5012          am_off12 = PPCAMode_IR( 12, r_aligned16 );
5013 
5014          /* Store zeros */
5015          r_zeros = newVRegI(env);
5016          addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
5017          if (IEndianess == Iend_LE)
5018             addInstr(env, PPCInstr_Store( 4, am_off0, r_src, mode64 ));
5019          else
5020             addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
5021          addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
5022          addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
5023 
5024          /* Store r_src in low word of quadword-aligned mem */
5025          if (IEndianess == Iend_LE)
5026             addInstr(env, PPCInstr_Store( 4, am_off12, r_zeros, mode64 ));
5027          else
5028             addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
5029 
5030          /* Load word into low word of quadword vector reg */
5031          if (IEndianess == Iend_LE)
5032             addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off0 ));
5033          else
5034             addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
5035 
5036          add_to_sp( env, 32 );       // Reset SP
5037          return dst;
5038       }
5039 
5040       case Iop_Dup8x16:
5041       case Iop_Dup16x8:
5042       case Iop_Dup32x4:
5043          return mk_AvDuplicateRI(env, e->Iex.Unop.arg, IEndianess);
5044 
5045       case Iop_CipherSV128: op = Pav_CIPHERSUBV128; goto do_AvCipherV128Un;
5046       do_AvCipherV128Un: {
5047          HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5048          HReg dst = newVRegV(env);
5049          addInstr(env, PPCInstr_AvCipherV128Unary(op, dst, arg));
5050          return dst;
5051       }
5052 
5053       case Iop_Clz8x16: op = Pav_ZEROCNTBYTE;   goto do_zerocnt;
5054       case Iop_Clz16x8: op = Pav_ZEROCNTHALF;   goto do_zerocnt;
5055       case Iop_Clz32x4: op = Pav_ZEROCNTWORD;   goto do_zerocnt;
5056       case Iop_Clz64x2: op = Pav_ZEROCNTDBL;    goto do_zerocnt;
5057       case Iop_PwBitMtxXpose64x2: op = Pav_BITMTXXPOSE;  goto do_zerocnt;
5058       do_zerocnt:
5059       {
5060         HReg arg = iselVecExpr(env, e->Iex.Unop.arg, IEndianess);
5061         HReg dst = newVRegV(env);
5062         addInstr(env, PPCInstr_AvUnary(op, dst, arg));
5063         return dst;
5064       }
5065 
5066       default:
5067          break;
5068       } /* switch (e->Iex.Unop.op) */
5069    } /* if (e->tag == Iex_Unop) */
5070 
5071    if (e->tag == Iex_Binop) {
5072       switch (e->Iex.Binop.op) {
5073 
5074       case Iop_64HLtoV128: {
5075          if (!mode64) {
5076             HReg     r3, r2, r1, r0, r_aligned16;
5077             PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
5078             HReg     dst = newVRegV(env);
5079             /* do this via the stack (easy, convenient, etc) */
5080             sub_from_sp( env, 32 );        // Move SP down
5081 
5082             // get a quadword aligned address within our stack space
5083             r_aligned16 = get_sp_aligned16( env );
5084             am_off0  = PPCAMode_IR( 0,  r_aligned16 );
5085             am_off4  = PPCAMode_IR( 4,  r_aligned16 );
5086             am_off8  = PPCAMode_IR( 8,  r_aligned16 );
5087             am_off12 = PPCAMode_IR( 12, r_aligned16 );
5088 
5089             /* Do the less significant 64 bits */
5090             iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2, IEndianess);
5091             addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
5092             addInstr(env, PPCInstr_Store( 4, am_off8,  r1, mode64 ));
5093             /* Do the more significant 64 bits */
5094             iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1, IEndianess);
5095             addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
5096             addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
5097 
5098             /* Fetch result back from stack. */
5099             addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5100 
5101             add_to_sp( env, 32 );          // Reset SP
5102             return dst;
5103          } else {
5104             HReg     rHi = iselWordExpr_R(env, e->Iex.Binop.arg1, IEndianess);
5105             HReg     rLo = iselWordExpr_R(env, e->Iex.Binop.arg2, IEndianess);
5106             HReg     dst = newVRegV(env);
5107             HReg     r_aligned16;
5108             PPCAMode *am_off0, *am_off8;
5109             /* do this via the stack (easy, convenient, etc) */
5110             sub_from_sp( env, 32 );        // Move SP down
5111 
5112             // get a quadword aligned address within our stack space
5113             r_aligned16 = get_sp_aligned16( env );
5114             am_off0  = PPCAMode_IR( 0,  r_aligned16 );
5115             am_off8  = PPCAMode_IR( 8,  r_aligned16 );
5116 
5117             /* Store 2*I64 to stack */
5118             if (IEndianess == Iend_LE) {
5119                addInstr(env, PPCInstr_Store( 8, am_off0, rLo, mode64 ));
5120                addInstr(env, PPCInstr_Store( 8, am_off8, rHi, mode64 ));
5121             } else {
5122                addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
5123                addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
5124             }
5125             /* Fetch result back from stack. */
5126             addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
5127 
5128             add_to_sp( env, 32 );          // Reset SP
5129             return dst;
5130          }
5131       }
5132 
5133       case Iop_Max32Fx4:   fpop = Pavfp_MAXF;   goto do_32Fx4;
5134       case Iop_Min32Fx4:   fpop = Pavfp_MINF;   goto do_32Fx4;
5135       case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
5136       case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
5137       case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
5138       do_32Fx4:
5139       {
5140          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5141          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5142          HReg dst = newVRegV(env);
5143          addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5144          return dst;
5145       }
5146 
5147       case Iop_CmpLE32Fx4: {
5148          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5149          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5150          HReg dst = newVRegV(env);
5151 
5152          /* stay consistent with native ppc compares:
5153             if a left/right lane holds a nan, return zeros for that lane
5154             so: le == NOT(gt OR isNan)
5155           */
5156          HReg isNanLR = newVRegV(env);
5157          HReg isNanL = isNan(env, argL, IEndianess);
5158          HReg isNanR = isNan(env, argR, IEndianess);
5159          addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
5160                                          isNanL, isNanR));
5161 
5162          addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
5163                                            argL, argR));
5164          addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
5165          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
5166          return dst;
5167       }
5168 
5169       case Iop_AndV128:    op = Pav_AND;      goto do_AvBin;
5170       case Iop_OrV128:     op = Pav_OR;       goto do_AvBin;
5171       case Iop_XorV128:    op = Pav_XOR;      goto do_AvBin;
5172       do_AvBin: {
5173          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5174          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5175          HReg dst  = newVRegV(env);
5176          addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
5177          return dst;
5178       }
5179 
5180       case Iop_Shl8x16:    op = Pav_SHL;    goto do_AvBin8x16;
5181       case Iop_Shr8x16:    op = Pav_SHR;    goto do_AvBin8x16;
5182       case Iop_Sar8x16:    op = Pav_SAR;    goto do_AvBin8x16;
5183       case Iop_Rol8x16:    op = Pav_ROTL;   goto do_AvBin8x16;
5184       case Iop_InterleaveHI8x16: op = Pav_MRGHI;  goto do_AvBin8x16;
5185       case Iop_InterleaveLO8x16: op = Pav_MRGLO;  goto do_AvBin8x16;
5186       case Iop_Add8x16:    op = Pav_ADDU;   goto do_AvBin8x16;
5187       case Iop_QAdd8Ux16:  op = Pav_QADDU;  goto do_AvBin8x16;
5188       case Iop_QAdd8Sx16:  op = Pav_QADDS;  goto do_AvBin8x16;
5189       case Iop_Sub8x16:    op = Pav_SUBU;   goto do_AvBin8x16;
5190       case Iop_QSub8Ux16:  op = Pav_QSUBU;  goto do_AvBin8x16;
5191       case Iop_QSub8Sx16:  op = Pav_QSUBS;  goto do_AvBin8x16;
5192       case Iop_Avg8Ux16:   op = Pav_AVGU;   goto do_AvBin8x16;
5193       case Iop_Avg8Sx16:   op = Pav_AVGS;   goto do_AvBin8x16;
5194       case Iop_Max8Ux16:   op = Pav_MAXU;   goto do_AvBin8x16;
5195       case Iop_Max8Sx16:   op = Pav_MAXS;   goto do_AvBin8x16;
5196       case Iop_Min8Ux16:   op = Pav_MINU;   goto do_AvBin8x16;
5197       case Iop_Min8Sx16:   op = Pav_MINS;   goto do_AvBin8x16;
5198       case Iop_MullEven8Ux16: op = Pav_OMULU;  goto do_AvBin8x16;
5199       case Iop_MullEven8Sx16: op = Pav_OMULS;  goto do_AvBin8x16;
5200       case Iop_CmpEQ8x16:  op = Pav_CMPEQU; goto do_AvBin8x16;
5201       case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
5202       case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
5203       case Iop_PolynomialMulAdd8x16: op = Pav_POLYMULADD; goto do_AvBin8x16;
5204       do_AvBin8x16: {
5205          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5206          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5207          HReg dst  = newVRegV(env);
5208          addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
5209          return dst;
5210       }
5211 
5212       case Iop_Shl16x8:    op = Pav_SHL;    goto do_AvBin16x8;
5213       case Iop_Shr16x8:    op = Pav_SHR;    goto do_AvBin16x8;
5214       case Iop_Sar16x8:    op = Pav_SAR;    goto do_AvBin16x8;
5215       case Iop_Rol16x8:    op = Pav_ROTL;   goto do_AvBin16x8;
5216       case Iop_NarrowBin16to8x16:    op = Pav_PACKUU;  goto do_AvBin16x8;
5217       case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8;
5218       case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8;
5219       case Iop_InterleaveHI16x8:  op = Pav_MRGHI;  goto do_AvBin16x8;
5220       case Iop_InterleaveLO16x8:  op = Pav_MRGLO;  goto do_AvBin16x8;
5221       case Iop_Add16x8:    op = Pav_ADDU;   goto do_AvBin16x8;
5222       case Iop_QAdd16Ux8:  op = Pav_QADDU;  goto do_AvBin16x8;
5223       case Iop_QAdd16Sx8:  op = Pav_QADDS;  goto do_AvBin16x8;
5224       case Iop_Sub16x8:    op = Pav_SUBU;   goto do_AvBin16x8;
5225       case Iop_QSub16Ux8:  op = Pav_QSUBU;  goto do_AvBin16x8;
5226       case Iop_QSub16Sx8:  op = Pav_QSUBS;  goto do_AvBin16x8;
5227       case Iop_Avg16Ux8:   op = Pav_AVGU;   goto do_AvBin16x8;
5228       case Iop_Avg16Sx8:   op = Pav_AVGS;   goto do_AvBin16x8;
5229       case Iop_Max16Ux8:   op = Pav_MAXU;   goto do_AvBin16x8;
5230       case Iop_Max16Sx8:   op = Pav_MAXS;   goto do_AvBin16x8;
5231       case Iop_Min16Ux8:   op = Pav_MINU;   goto do_AvBin16x8;
5232       case Iop_Min16Sx8:   op = Pav_MINS;   goto do_AvBin16x8;
5233       case Iop_MullEven16Ux8: op = Pav_OMULU;  goto do_AvBin16x8;
5234       case Iop_MullEven16Sx8: op = Pav_OMULS;  goto do_AvBin16x8;
5235       case Iop_CmpEQ16x8:  op = Pav_CMPEQU; goto do_AvBin16x8;
5236       case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
5237       case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
5238       case Iop_PolynomialMulAdd16x8: op = Pav_POLYMULADD; goto do_AvBin16x8;
5239       do_AvBin16x8: {
5240          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5241          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5242          HReg dst  = newVRegV(env);
5243          addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
5244          return dst;
5245       }
5246 
5247       case Iop_Shl32x4:    op = Pav_SHL;    goto do_AvBin32x4;
5248       case Iop_Shr32x4:    op = Pav_SHR;    goto do_AvBin32x4;
5249       case Iop_Sar32x4:    op = Pav_SAR;    goto do_AvBin32x4;
5250       case Iop_Rol32x4:    op = Pav_ROTL;   goto do_AvBin32x4;
5251       case Iop_NarrowBin32to16x8:    op = Pav_PACKUU;  goto do_AvBin32x4;
5252       case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4;
5253       case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4;
5254       case Iop_InterleaveHI32x4:  op = Pav_MRGHI;  goto do_AvBin32x4;
5255       case Iop_InterleaveLO32x4:  op = Pav_MRGLO;  goto do_AvBin32x4;
5256       case Iop_Add32x4:    op = Pav_ADDU;   goto do_AvBin32x4;
5257       case Iop_QAdd32Ux4:  op = Pav_QADDU;  goto do_AvBin32x4;
5258       case Iop_QAdd32Sx4:  op = Pav_QADDS;  goto do_AvBin32x4;
5259       case Iop_Sub32x4:    op = Pav_SUBU;   goto do_AvBin32x4;
5260       case Iop_QSub32Ux4:  op = Pav_QSUBU;  goto do_AvBin32x4;
5261       case Iop_QSub32Sx4:  op = Pav_QSUBS;  goto do_AvBin32x4;
5262       case Iop_Avg32Ux4:   op = Pav_AVGU;   goto do_AvBin32x4;
5263       case Iop_Avg32Sx4:   op = Pav_AVGS;   goto do_AvBin32x4;
5264       case Iop_Max32Ux4:   op = Pav_MAXU;   goto do_AvBin32x4;
5265       case Iop_Max32Sx4:   op = Pav_MAXS;   goto do_AvBin32x4;
5266       case Iop_Min32Ux4:   op = Pav_MINU;   goto do_AvBin32x4;
5267       case Iop_Min32Sx4:   op = Pav_MINS;   goto do_AvBin32x4;
5268       case Iop_Mul32x4:    op = Pav_MULU;   goto do_AvBin32x4;
5269       case Iop_MullEven32Ux4: op = Pav_OMULU;  goto do_AvBin32x4;
5270       case Iop_MullEven32Sx4: op = Pav_OMULS;  goto do_AvBin32x4;
5271       case Iop_CmpEQ32x4:  op = Pav_CMPEQU; goto do_AvBin32x4;
5272       case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
5273       case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
5274       case Iop_CatOddLanes32x4:  op = Pav_CATODD;  goto do_AvBin32x4;
5275       case Iop_CatEvenLanes32x4: op = Pav_CATEVEN; goto do_AvBin32x4;
5276       case Iop_PolynomialMulAdd32x4: op = Pav_POLYMULADD; goto do_AvBin32x4;
5277       do_AvBin32x4: {
5278          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5279          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5280          HReg dst  = newVRegV(env);
5281          addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
5282          return dst;
5283       }
5284 
5285       case Iop_Shl64x2:    op = Pav_SHL;    goto do_AvBin64x2;
5286       case Iop_Shr64x2:    op = Pav_SHR;    goto do_AvBin64x2;
5287       case Iop_Sar64x2:    op = Pav_SAR;    goto do_AvBin64x2;
5288       case Iop_Rol64x2:    op = Pav_ROTL;   goto do_AvBin64x2;
5289       case Iop_NarrowBin64to32x4:    op = Pav_PACKUU;  goto do_AvBin64x2;
5290       case Iop_QNarrowBin64Sto32Sx4: op = Pav_QPACKSS; goto do_AvBin64x2;
5291       case Iop_QNarrowBin64Uto32Ux4: op = Pav_QPACKUU; goto do_AvBin64x2;
5292       case Iop_InterleaveHI64x2:  op = Pav_MRGHI;  goto do_AvBin64x2;
5293       case Iop_InterleaveLO64x2:  op = Pav_MRGLO;  goto do_AvBin64x2;
5294       case Iop_Add64x2:    op = Pav_ADDU;   goto do_AvBin64x2;
5295       case Iop_Sub64x2:    op = Pav_SUBU;   goto do_AvBin64x2;
5296       case Iop_Max64Ux2:   op = Pav_MAXU;   goto do_AvBin64x2;
5297       case Iop_Max64Sx2:   op = Pav_MAXS;   goto do_AvBin64x2;
5298       case Iop_Min64Ux2:   op = Pav_MINU;   goto do_AvBin64x2;
5299       case Iop_Min64Sx2:   op = Pav_MINS;   goto do_AvBin64x2;
5300       case Iop_CmpEQ64x2:  op = Pav_CMPEQU; goto do_AvBin64x2;
5301       case Iop_CmpGT64Ux2: op = Pav_CMPGTU; goto do_AvBin64x2;
5302       case Iop_CmpGT64Sx2: op = Pav_CMPGTS; goto do_AvBin64x2;
5303       case Iop_PolynomialMulAdd64x2: op = Pav_POLYMULADD; goto do_AvBin64x2;
5304       do_AvBin64x2: {
5305          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5306          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5307          HReg dst  = newVRegV(env);
5308          addInstr(env, PPCInstr_AvBin64x2(op, dst, arg1, arg2));
5309          return dst;
5310       }
5311 
5312       case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
5313       case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
5314       do_AvShift8x16: {
5315          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5316          HReg dst    = newVRegV(env);
5317          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5318          addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
5319          return dst;
5320       }
5321 
5322       case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
5323       case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
5324       case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
5325       do_AvShift16x8: {
5326          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5327          HReg dst    = newVRegV(env);
5328          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5329          addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
5330          return dst;
5331       }
5332 
5333       case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
5334       case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
5335       case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
5336       do_AvShift32x4: {
5337          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5338          HReg dst    = newVRegV(env);
5339          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5340          addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
5341          return dst;
5342       }
5343 
5344       case Iop_ShlN64x2: op = Pav_SHL; goto do_AvShift64x2;
5345       case Iop_ShrN64x2: op = Pav_SHR; goto do_AvShift64x2;
5346       case Iop_SarN64x2: op = Pav_SAR; goto do_AvShift64x2;
5347       do_AvShift64x2: {
5348          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5349          HReg dst    = newVRegV(env);
5350          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5351          addInstr(env, PPCInstr_AvBin64x2(op, dst, r_src, v_shft));
5352          return dst;
5353       }
5354 
5355       case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
5356       case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
5357       do_AvShiftV128: {
5358          HReg dst    = newVRegV(env);
5359          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5360          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2, IEndianess);
5361          /* Note: shift value gets masked by 127 */
5362          addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
5363          return dst;
5364       }
5365 
5366       case Iop_Perm8x16: {
5367          HReg dst   = newVRegV(env);
5368          HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5369          HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5370          addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
5371          return dst;
5372       }
5373 
5374       case Iop_CipherV128:  op = Pav_CIPHERV128;   goto do_AvCipherV128;
5375       case Iop_CipherLV128: op = Pav_CIPHERLV128;  goto do_AvCipherV128;
5376       case Iop_NCipherV128: op = Pav_NCIPHERV128;  goto do_AvCipherV128;
5377       case Iop_NCipherLV128:op = Pav_NCIPHERLV128; goto do_AvCipherV128;
5378       do_AvCipherV128: {
5379          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5380          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2, IEndianess);
5381          HReg dst  = newVRegV(env);
5382          addInstr(env, PPCInstr_AvCipherV128Binary(op, dst, arg1, arg2));
5383          return dst;
5384       }
5385 
5386       case Iop_SHA256:op = Pav_SHA256; goto do_AvHashV128;
5387       case Iop_SHA512:op = Pav_SHA512; goto do_AvHashV128;
5388       do_AvHashV128: {
5389          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1, IEndianess);
5390          HReg dst  = newVRegV(env);
5391          PPCRI* s_field = iselWordExpr_RI(env, e->Iex.Binop.arg2, IEndianess);
5392          addInstr(env, PPCInstr_AvHashV128Binary(op, dst, arg1, s_field));
5393          return dst;
5394       }
5395       default:
5396          break;
5397       } /* switch (e->Iex.Binop.op) */
5398    } /* if (e->tag == Iex_Binop) */
5399 
5400    if (e->tag == Iex_Triop) {
5401       IRTriop *triop = e->Iex.Triop.details;
5402       switch (triop->op) {
5403       case Iop_BCDAdd:op = Pav_BCDAdd; goto do_AvBCDV128;
5404       case Iop_BCDSub:op = Pav_BCDSub; goto do_AvBCDV128;
5405       do_AvBCDV128: {
5406          HReg arg1 = iselVecExpr(env, triop->arg1, IEndianess);
5407          HReg arg2 = iselVecExpr(env, triop->arg2, IEndianess);
5408          HReg dst  = newVRegV(env);
5409          PPCRI* ps = iselWordExpr_RI(env, triop->arg3, IEndianess);
5410          addInstr(env, PPCInstr_AvBCDV128Trinary(op, dst, arg1, arg2, ps));
5411          return dst;
5412       }
5413 
5414       case Iop_Add32Fx4: fpop = Pavfp_ADDF; goto do_32Fx4_with_rm;
5415       case Iop_Sub32Fx4: fpop = Pavfp_SUBF; goto do_32Fx4_with_rm;
5416       case Iop_Mul32Fx4: fpop = Pavfp_MULF; goto do_32Fx4_with_rm;
5417       do_32Fx4_with_rm:
5418       {
5419          HReg argL = iselVecExpr(env, triop->arg2, IEndianess);
5420          HReg argR = iselVecExpr(env, triop->arg3, IEndianess);
5421          HReg dst  = newVRegV(env);
5422          /* FIXME: this is bogus, in the sense that Altivec ignores
5423             FPSCR.RM, at least for some FP operations.  So setting the
5424             RM is pointless.  This is only really correct in the case
5425             where the RM is known, at JIT time, to be Irrm_NEAREST,
5426             since -- at least for Altivec FP add/sub/mul -- the
5427             emitted insn is hardwired to round to nearest. */
5428          set_FPU_rounding_mode(env, triop->arg1, IEndianess);
5429          addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
5430          return dst;
5431       }
5432 
5433       default:
5434          break;
5435       } /* switch (e->Iex.Triop.op) */
5436    } /* if (e->tag == Iex_Trinop) */
5437 
5438 
5439    if (e->tag == Iex_Const ) {
5440       vassert(e->Iex.Const.con->tag == Ico_V128);
5441       if (e->Iex.Const.con->Ico.V128 == 0x0000) {
5442          return generate_zeroes_V128(env);
5443       }
5444       else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
5445          return generate_ones_V128(env);
5446       }
5447    }
5448 
5449    vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
5450               LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
5451                                  env->hwcaps));
5452    ppIRExpr(e);
5453    vpanic("iselVecExpr_wrk(ppc)");
5454 }
5455 
5456 
5457 /*---------------------------------------------------------*/
5458 /*--- ISEL: Statements                                  ---*/
5459 /*---------------------------------------------------------*/
5460 
iselStmt(ISelEnv * env,IRStmt * stmt,IREndness IEndianess)5461 static void iselStmt ( ISelEnv* env, IRStmt* stmt, IREndness IEndianess )
5462 {
5463    Bool mode64 = env->mode64;
5464    if (vex_traceflags & VEX_TRACE_VCODE) {
5465       vex_printf("\n -- ");
5466       ppIRStmt(stmt);
5467       vex_printf("\n");
5468    }
5469 
5470    switch (stmt->tag) {
5471 
5472    /* --------- STORE --------- */
5473    case Ist_Store: {
5474       IRType    tya   = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
5475       IRType    tyd   = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
5476       IREndness end   = stmt->Ist.Store.end;
5477 
5478       if (end != IEndianess)
5479          goto stmt_fail;
5480       if (!mode64 && (tya != Ity_I32))
5481          goto stmt_fail;
5482       if (mode64 && (tya != Ity_I64))
5483          goto stmt_fail;
5484 
5485       if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
5486           (mode64 && (tyd == Ity_I64))) {
5487          PPCAMode* am_addr
5488             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5489                                  IEndianess);
5490          HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data, IEndianess);
5491          addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
5492                                        am_addr, r_src, mode64 ));
5493          return;
5494       }
5495       if (tyd == Ity_F64) {
5496          PPCAMode* am_addr
5497             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5498                                  IEndianess);
5499          HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data, IEndianess);
5500          addInstr(env,
5501                   PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5502          return;
5503       }
5504       if (tyd == Ity_F32) {
5505          PPCAMode* am_addr
5506             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5507                                  IEndianess);
5508          HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data, IEndianess);
5509          addInstr(env,
5510                   PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5511          return;
5512       }
5513       if (tyd == Ity_D64) {
5514          PPCAMode* am_addr
5515             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5516                                  IEndianess);
5517          HReg fr_src = iselDfp64Expr(env, stmt->Ist.Store.data, IEndianess);
5518          addInstr(env,
5519                   PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
5520          return;
5521       }
5522       if (tyd == Ity_D32) {
5523          PPCAMode* am_addr
5524             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5525                                  IEndianess);
5526          HReg fr_src = iselDfp32Expr(env, stmt->Ist.Store.data, IEndianess);
5527          addInstr(env,
5528                   PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
5529          return;
5530       }
5531       if (tyd == Ity_V128) {
5532          PPCAMode* am_addr
5533             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/,
5534                                  IEndianess);
5535          HReg v_src = iselVecExpr(env, stmt->Ist.Store.data, IEndianess);
5536          addInstr(env,
5537                   PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5538          return;
5539       }
5540       if (tyd == Ity_I64 && !mode64) {
5541          /* Just calculate the address in the register.  Life is too
5542             short to arse around trying and possibly failing to adjust
5543             the offset in a 'reg+offset' style amode. */
5544          HReg rHi32, rLo32;
5545          HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr, IEndianess);
5546          iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data,
5547                         IEndianess );
5548          addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5549                                        PPCAMode_IR( 0, r_addr ),
5550                                        rHi32,
5551                                        False/*32-bit insn please*/) );
5552          addInstr(env, PPCInstr_Store( 4/*byte-store*/,
5553                                        PPCAMode_IR( 4, r_addr ),
5554                                        rLo32,
5555                                        False/*32-bit insn please*/) );
5556          return;
5557       }
5558       break;
5559    }
5560 
5561    /* --------- PUT --------- */
5562    case Ist_Put: {
5563       IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
5564       if (ty == Ity_I8  || ty == Ity_I16 ||
5565           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5566          HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data, IEndianess);
5567          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5568                                           GuestStatePtr(mode64) );
5569          addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
5570                                        am_addr, r_src, mode64 ));
5571          return;
5572       }
5573       if (!mode64 && ty == Ity_I64) {
5574          HReg rHi, rLo;
5575          PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
5576                                            GuestStatePtr(mode64) );
5577          PPCAMode* am_addr4 = advance4(env, am_addr);
5578          iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data, IEndianess);
5579          addInstr(env, PPCInstr_Store( 4, am_addr,  rHi, mode64 ));
5580          addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
5581          return;
5582      }
5583      if (ty == Ity_V128) {
5584          /* Guest state vectors are 16byte aligned,
5585             so don't need to worry here */
5586          HReg v_src = iselVecExpr(env, stmt->Ist.Put.data, IEndianess);
5587          PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
5588                                            GuestStatePtr(mode64) );
5589          addInstr(env,
5590                   PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
5591          return;
5592       }
5593       if (ty == Ity_F64) {
5594          HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data, IEndianess);
5595          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5596                                           GuestStatePtr(mode64) );
5597          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
5598                                         fr_src, am_addr ));
5599          return;
5600       }
5601       if (ty == Ity_D32) {
5602          /* The 32-bit value is stored in a 64-bit register */
5603          HReg fr_src = iselDfp32Expr( env, stmt->Ist.Put.data, IEndianess );
5604          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5605                                           GuestStatePtr(mode64) );
5606          addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8,
5607                                          fr_src, am_addr ) );
5608          return;
5609       }
5610       if (ty == Ity_D64) {
5611          HReg fr_src = iselDfp64Expr( env, stmt->Ist.Put.data, IEndianess );
5612          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
5613                                           GuestStatePtr(mode64) );
5614          addInstr( env, PPCInstr_FpLdSt( False/*store*/, 8, fr_src, am_addr ) );
5615          return;
5616       }
5617       break;
5618    }
5619 
5620    /* --------- Indexed PUT --------- */
5621    case Ist_PutI: {
5622       IRPutI *puti = stmt->Ist.PutI.details;
5623 
5624       PPCAMode* dst_am
5625          = genGuestArrayOffset(
5626               env, puti->descr,
5627               puti->ix, puti->bias,
5628               IEndianess );
5629       IRType ty = typeOfIRExpr(env->type_env, puti->data);
5630       if (mode64 && ty == Ity_I64) {
5631          HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5632          addInstr(env, PPCInstr_Store( toUChar(8),
5633                                        dst_am, r_src, mode64 ));
5634          return;
5635       }
5636       if ((!mode64) && ty == Ity_I32) {
5637          HReg r_src = iselWordExpr_R(env, puti->data, IEndianess);
5638          addInstr(env, PPCInstr_Store( toUChar(4),
5639                                        dst_am, r_src, mode64 ));
5640          return;
5641       }
5642       break;
5643    }
5644 
5645    /* --------- TMP --------- */
5646    case Ist_WrTmp: {
5647       IRTemp tmp = stmt->Ist.WrTmp.tmp;
5648       IRType ty = typeOfIRTemp(env->type_env, tmp);
5649       if (ty == Ity_I8  || ty == Ity_I16 ||
5650           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
5651          HReg r_dst = lookupIRTemp(env, tmp);
5652          HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data, IEndianess);
5653          addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
5654          return;
5655       }
5656       if (!mode64 && ty == Ity_I64) {
5657          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5658 
5659          iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5660                        IEndianess);
5661          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5662          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5663          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5664          return;
5665       }
5666       if (mode64 && ty == Ity_I128) {
5667          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
5668          iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data,
5669                         IEndianess);
5670          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
5671          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
5672          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
5673          return;
5674       }
5675       if (!mode64 && ty == Ity_I128) {
5676          HReg r_srcHi, r_srcMedHi, r_srcMedLo, r_srcLo;
5677          HReg r_dstHi, r_dstMedHi, r_dstMedLo, r_dstLo;
5678 
5679          iselInt128Expr_to_32x4(&r_srcHi, &r_srcMedHi,
5680                                 &r_srcMedLo, &r_srcLo,
5681                                 env, stmt->Ist.WrTmp.data, IEndianess);
5682 
5683          lookupIRTempQuad( &r_dstHi, &r_dstMedHi, &r_dstMedLo,
5684                            &r_dstLo, env, tmp);
5685 
5686          addInstr(env, mk_iMOVds_RR(r_dstHi,    r_srcHi) );
5687          addInstr(env, mk_iMOVds_RR(r_dstMedHi, r_srcMedHi) );
5688          addInstr(env, mk_iMOVds_RR(r_dstMedLo, r_srcMedLo) );
5689          addInstr(env, mk_iMOVds_RR(r_dstLo,    r_srcLo) );
5690          return;
5691       }
5692       if (ty == Ity_I1) {
5693          PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data,
5694                                          IEndianess);
5695          HReg r_dst = lookupIRTemp(env, tmp);
5696          addInstr(env, PPCInstr_Set(cond, r_dst));
5697          return;
5698       }
5699       if (ty == Ity_F64) {
5700          HReg fr_dst = lookupIRTemp(env, tmp);
5701          HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5702          addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5703          return;
5704       }
5705       if (ty == Ity_F32) {
5706          HReg fr_dst = lookupIRTemp(env, tmp);
5707          HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5708          addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
5709          return;
5710       }
5711       if (ty == Ity_D32) {
5712          HReg fr_dst = lookupIRTemp(env, tmp);
5713          HReg fr_src = iselDfp32Expr(env, stmt->Ist.WrTmp.data, IEndianess);
5714          addInstr(env, PPCInstr_Dfp64Unary(Pfp_MOV, fr_dst, fr_src));
5715          return;
5716       }
5717       if (ty == Ity_V128) {
5718          HReg v_dst = lookupIRTemp(env, tmp);
5719          HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data, IEndianess);
5720          addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
5721          return;
5722       }
5723       if (ty == Ity_D64) {
5724          HReg fr_dst = lookupIRTemp( env, tmp );
5725          HReg fr_src = iselDfp64Expr( env, stmt->Ist.WrTmp.data, IEndianess );
5726          addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dst, fr_src ) );
5727          return;
5728       }
5729       if (ty == Ity_D128) {
5730          HReg fr_srcHi, fr_srcLo, fr_dstHi, fr_dstLo;
5731 	 //         lookupDfp128IRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5732          lookupIRTempPair( &fr_dstHi, &fr_dstLo, env, tmp );
5733          iselDfp128Expr( &fr_srcHi, &fr_srcLo, env, stmt->Ist.WrTmp.data,
5734                          IEndianess );
5735          addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstHi, fr_srcHi ) );
5736          addInstr( env, PPCInstr_Dfp64Unary( Pfp_MOV, fr_dstLo, fr_srcLo ) );
5737          return;
5738       }
5739       break;
5740    }
5741 
5742    /* --------- Load Linked or Store Conditional --------- */
5743    case Ist_LLSC: {
5744       IRTemp res    = stmt->Ist.LLSC.result;
5745       IRType tyRes  = typeOfIRTemp(env->type_env, res);
5746       IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
5747 
5748       if (stmt->Ist.LLSC.end != IEndianess)
5749          goto stmt_fail;
5750       if (!mode64 && (tyAddr != Ity_I32))
5751          goto stmt_fail;
5752       if (mode64 && (tyAddr != Ity_I64))
5753          goto stmt_fail;
5754 
5755       if (stmt->Ist.LLSC.storedata == NULL) {
5756          /* LL */
5757          HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr, IEndianess );
5758          HReg r_dst  = lookupIRTemp(env, res);
5759          if (tyRes == Ity_I8) {
5760             addInstr(env, PPCInstr_LoadL( 1, r_dst, r_addr, mode64 ));
5761             return;
5762          }
5763          if (tyRes == Ity_I16) {
5764             addInstr(env, PPCInstr_LoadL( 2, r_dst, r_addr, mode64 ));
5765             return;
5766          }
5767          if (tyRes == Ity_I32) {
5768             addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
5769             return;
5770          }
5771          if (tyRes == Ity_I64 && mode64) {
5772             addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
5773             return;
5774          }
5775          /* fallthru */;
5776       } else {
5777          /* SC */
5778          HReg   r_res  = lookupIRTemp(env, res); /* :: Ity_I1 */
5779          HReg   r_a    = iselWordExpr_R(env, stmt->Ist.LLSC.addr, IEndianess);
5780          HReg   r_src  = iselWordExpr_R(env, stmt->Ist.LLSC.storedata,
5781                                         IEndianess);
5782          HReg   r_tmp  = newVRegI(env);
5783          IRType tyData = typeOfIRExpr(env->type_env,
5784                                       stmt->Ist.LLSC.storedata);
5785          vassert(tyRes == Ity_I1);
5786          if (tyData == Ity_I8 || tyData == Ity_I16 || tyData == Ity_I32 ||
5787             (tyData == Ity_I64 && mode64)) {
5788             int size = 0;
5789 
5790             if (tyData == Ity_I64)
5791                size = 8;
5792             else if (tyData == Ity_I32)
5793                size = 4;
5794             else if (tyData == Ity_I16)
5795                size = 2;
5796             else if (tyData == Ity_I8)
5797                size = 1;
5798 
5799             addInstr(env, PPCInstr_StoreC( size,
5800                                            r_a, r_src, mode64 ));
5801             addInstr(env, PPCInstr_MfCR( r_tmp ));
5802             addInstr(env, PPCInstr_Shft(
5803                              Pshft_SHR,
5804                              env->mode64 ? False : True
5805                                 /*F:64-bit, T:32-bit shift*/,
5806                              r_tmp, r_tmp,
5807                              PPCRH_Imm(False/*unsigned*/, 29)));
5808             /* Probably unnecessary, since the IR dest type is Ity_I1,
5809                and so we are entitled to leave whatever junk we like
5810                drifting round in the upper 31 or 63 bits of r_res.
5811                However, for the sake of conservativeness .. */
5812             addInstr(env, PPCInstr_Alu(
5813                              Palu_AND,
5814                              r_res, r_tmp,
5815                              PPCRH_Imm(False/*signed*/, 1)));
5816             return;
5817          }
5818          /* fallthru */
5819       }
5820       goto stmt_fail;
5821       /*NOTREACHED*/
5822    }
5823 
5824    /* --------- Call to DIRTY helper --------- */
5825    case Ist_Dirty: {
5826       IRDirty* d = stmt->Ist.Dirty.details;
5827 
5828       /* Figure out the return type, if any. */
5829       IRType retty = Ity_INVALID;
5830       if (d->tmp != IRTemp_INVALID)
5831          retty = typeOfIRTemp(env->type_env, d->tmp);
5832 
5833       /* Throw out any return types we don't know about.  The set of
5834          acceptable return types is the same in both 32- and 64-bit
5835          mode, so we don't need to inspect mode64 to make a
5836          decision. */
5837       Bool retty_ok = False;
5838       switch (retty) {
5839          case Ity_INVALID: /* function doesn't return anything */
5840          case Ity_V128:
5841          case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
5842             retty_ok = True; break;
5843          default:
5844             break;
5845       }
5846       if (!retty_ok)
5847          break; /* will go to stmt_fail: */
5848 
5849       /* Marshal args, do the call, clear stack, set the return value
5850          to 0x555..555 if this is a conditional call that returns a
5851          value and the call is skipped. */
5852       UInt   addToSp = 0;
5853       RetLoc rloc    = mk_RetLoc_INVALID();
5854       doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args,
5855                     IEndianess );
5856       vassert(is_sane_RetLoc(rloc));
5857 
5858       /* Now figure out what to do with the returned value, if any. */
5859       switch (retty) {
5860          case Ity_INVALID: {
5861             /* No return value.  Nothing to do. */
5862             vassert(d->tmp == IRTemp_INVALID);
5863             vassert(rloc.pri == RLPri_None);
5864             vassert(addToSp == 0);
5865             return;
5866          }
5867          case Ity_I32: case Ity_I16: case Ity_I8: {
5868             /* The returned value is in %r3.  Park it in the register
5869                associated with tmp. */
5870             HReg r_dst = lookupIRTemp(env, d->tmp);
5871             addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5872             vassert(rloc.pri == RLPri_Int);
5873             vassert(addToSp == 0);
5874             return;
5875          }
5876          case Ity_I64:
5877             if (mode64) {
5878                /* The returned value is in %r3.  Park it in the register
5879                   associated with tmp. */
5880                HReg r_dst = lookupIRTemp(env, d->tmp);
5881                addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
5882                vassert(rloc.pri == RLPri_Int);
5883                vassert(addToSp == 0);
5884             } else {
5885                /* The returned value is in %r3:%r4.  Park it in the
5886                   register-pair associated with tmp. */
5887                HReg r_dstHi = INVALID_HREG;
5888                HReg r_dstLo = INVALID_HREG;
5889                lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
5890                addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
5891                addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
5892                vassert(rloc.pri == RLPri_2Int);
5893                vassert(addToSp == 0);
5894             }
5895             return;
5896          case Ity_V128: {
5897             /* The returned value is on the stack, and *retloc tells
5898                us where.  Fish it off the stack and then move the
5899                stack pointer upwards to clear it, as directed by
5900                doHelperCall. */
5901             vassert(rloc.pri == RLPri_V128SpRel);
5902             vassert(addToSp >= 16);
5903             HReg      dst = lookupIRTemp(env, d->tmp);
5904             PPCAMode* am  = PPCAMode_IR(rloc.spOff, StackFramePtr(mode64));
5905             addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, dst, am ));
5906             add_to_sp(env, addToSp);
5907             return;
5908          }
5909          default:
5910             /*NOTREACHED*/
5911             vassert(0);
5912       }
5913    }
5914 
5915    /* --------- MEM FENCE --------- */
5916    case Ist_MBE:
5917       switch (stmt->Ist.MBE.event) {
5918          case Imbe_Fence:
5919             addInstr(env, PPCInstr_MFence());
5920             return;
5921          default:
5922             break;
5923       }
5924       break;
5925 
5926    /* --------- INSTR MARK --------- */
5927    /* Doesn't generate any executable code ... */
5928    case Ist_IMark:
5929        return;
5930 
5931    /* --------- ABI HINT --------- */
5932    /* These have no meaning (denotation in the IR) and so we ignore
5933       them ... if any actually made it this far. */
5934    case Ist_AbiHint:
5935        return;
5936 
5937    /* --------- NO-OP --------- */
5938    /* Fairly self-explanatory, wouldn't you say? */
5939    case Ist_NoOp:
5940        return;
5941 
5942    /* --------- EXIT --------- */
5943    case Ist_Exit: {
5944       IRConst* dst = stmt->Ist.Exit.dst;
5945       if (!mode64 && dst->tag != Ico_U32)
5946          vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
5947       if (mode64 && dst->tag != Ico_U64)
5948          vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
5949 
5950       PPCCondCode cc    = iselCondCode(env, stmt->Ist.Exit.guard, IEndianess);
5951       PPCAMode*   amCIA = PPCAMode_IR(stmt->Ist.Exit.offsIP,
5952                                       hregPPC_GPR31(mode64));
5953 
5954       /* Case: boring transfer to known address */
5955       if (stmt->Ist.Exit.jk == Ijk_Boring
5956           || stmt->Ist.Exit.jk == Ijk_Call
5957           /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
5958          if (env->chainingAllowed) {
5959             /* .. almost always true .. */
5960             /* Skip the event check at the dst if this is a forwards
5961                edge. */
5962             Bool toFastEP
5963                = mode64
5964                ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
5965                : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
5966             if (0) vex_printf("%s", toFastEP ? "Y" : ",");
5967             addInstr(env, PPCInstr_XDirect(
5968                              mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
5969                                     : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
5970                              amCIA, cc, toFastEP));
5971          } else {
5972             /* .. very occasionally .. */
5973             /* We can't use chaining, so ask for an assisted transfer,
5974                as that's the only alternative that is allowable. */
5975             HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5976                                     IEndianess);
5977             addInstr(env, PPCInstr_XAssisted(r, amCIA, cc, Ijk_Boring));
5978          }
5979          return;
5980       }
5981 
5982       /* Case: assisted transfer to arbitrary address */
5983       switch (stmt->Ist.Exit.jk) {
5984          /* Keep this list in sync with that in iselNext below */
5985          case Ijk_ClientReq:
5986          case Ijk_EmFail:
5987          case Ijk_EmWarn:
5988          case Ijk_NoDecode:
5989          case Ijk_NoRedir:
5990          case Ijk_SigBUS:
5991          case Ijk_SigTRAP:
5992          case Ijk_Sys_syscall:
5993          case Ijk_InvalICache:
5994          {
5995             HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst),
5996                                     IEndianess);
5997             addInstr(env, PPCInstr_XAssisted(r, amCIA, cc,
5998                                              stmt->Ist.Exit.jk));
5999             return;
6000          }
6001          default:
6002             break;
6003       }
6004 
6005       /* Do we ever expect to see any other kind? */
6006       goto stmt_fail;
6007    }
6008 
6009    default: break;
6010    }
6011   stmt_fail:
6012    ppIRStmt(stmt);
6013    vpanic("iselStmt(ppc)");
6014 }
6015 
6016 
6017 /*---------------------------------------------------------*/
6018 /*--- ISEL: Basic block terminators (Nexts)             ---*/
6019 /*---------------------------------------------------------*/
6020 
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP,IREndness IEndianess)6021 static void iselNext ( ISelEnv* env,
6022                        IRExpr* next, IRJumpKind jk, Int offsIP,
6023                        IREndness IEndianess)
6024 {
6025    if (vex_traceflags & VEX_TRACE_VCODE) {
6026       vex_printf( "\n-- PUT(%d) = ", offsIP);
6027       ppIRExpr( next );
6028       vex_printf( "; exit-");
6029       ppIRJumpKind(jk);
6030       vex_printf( "\n");
6031    }
6032 
6033    PPCCondCode always = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
6034 
6035    /* Case: boring transfer to known address */
6036    if (next->tag == Iex_Const) {
6037       IRConst* cdst = next->Iex.Const.con;
6038       vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
6039       if (jk == Ijk_Boring || jk == Ijk_Call) {
6040          /* Boring transfer to known address */
6041          PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6042          if (env->chainingAllowed) {
6043             /* .. almost always true .. */
6044             /* Skip the event check at the dst if this is a forwards
6045                edge. */
6046             Bool toFastEP
6047                = env->mode64
6048                ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
6049                : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
6050             if (0) vex_printf("%s", toFastEP ? "X" : ".");
6051             addInstr(env, PPCInstr_XDirect(
6052                              env->mode64 ? (Addr64)cdst->Ico.U64
6053                                          : (Addr64)cdst->Ico.U32,
6054                              amCIA, always, toFastEP));
6055          } else {
6056             /* .. very occasionally .. */
6057             /* We can't use chaining, so ask for an assisted transfer,
6058                as that's the only alternative that is allowable. */
6059             HReg r = iselWordExpr_R(env, next, IEndianess);
6060             addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6061                                              Ijk_Boring));
6062          }
6063          return;
6064       }
6065    }
6066 
6067    /* Case: call/return (==boring) transfer to any address */
6068    switch (jk) {
6069       case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
6070          HReg       r     = iselWordExpr_R(env, next, IEndianess);
6071          PPCAMode*  amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6072          if (env->chainingAllowed) {
6073             addInstr(env, PPCInstr_XIndir(r, amCIA, always));
6074          } else {
6075             addInstr(env, PPCInstr_XAssisted(r, amCIA, always,
6076                                              Ijk_Boring));
6077          }
6078          return;
6079       }
6080       default:
6081          break;
6082    }
6083 
6084    /* Case: assisted transfer to arbitrary address */
6085    switch (jk) {
6086       /* Keep this list in sync with that for Ist_Exit above */
6087       case Ijk_ClientReq:
6088       case Ijk_EmFail:
6089       case Ijk_EmWarn:
6090       case Ijk_NoDecode:
6091       case Ijk_NoRedir:
6092       case Ijk_SigBUS:
6093       case Ijk_SigTRAP:
6094       case Ijk_Sys_syscall:
6095       case Ijk_InvalICache:
6096       {
6097          HReg      r     = iselWordExpr_R(env, next, IEndianess);
6098          PPCAMode* amCIA = PPCAMode_IR(offsIP, hregPPC_GPR31(env->mode64));
6099          addInstr(env, PPCInstr_XAssisted(r, amCIA, always, jk));
6100          return;
6101       }
6102       default:
6103          break;
6104    }
6105 
6106    vex_printf( "\n-- PUT(%d) = ", offsIP);
6107    ppIRExpr( next );
6108    vex_printf( "; exit-");
6109    ppIRJumpKind(jk);
6110    vex_printf( "\n");
6111    vassert(0); // are we expecting any other kind?
6112 }
6113 
6114 
6115 /*---------------------------------------------------------*/
6116 /*--- Insn selector top-level                           ---*/
6117 /*---------------------------------------------------------*/
6118 
6119 /* 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)6120 HInstrArray* iselSB_PPC ( const IRSB* bb,
6121                           VexArch      arch_host,
6122                           const VexArchInfo* archinfo_host,
6123                           const VexAbiInfo*  vbi,
6124                           Int offs_Host_EvC_Counter,
6125                           Int offs_Host_EvC_FailAddr,
6126                           Bool chainingAllowed,
6127                           Bool addProfInc,
6128                           Addr max_ga)
6129 
6130 {
6131    Int       i, j;
6132    HReg      hregLo, hregMedLo, hregMedHi, hregHi;
6133    ISelEnv*  env;
6134    UInt      hwcaps_host = archinfo_host->hwcaps;
6135    Bool      mode64 = False;
6136    UInt      mask32, mask64;
6137    PPCAMode *amCounter, *amFailAddr;
6138    IREndness IEndianess;
6139 
6140    vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
6141    mode64 = arch_host == VexArchPPC64;
6142 
6143    /* do some sanity checks */
6144    mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
6145             | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX
6146             | VEX_HWCAPS_PPC32_DFP | VEX_HWCAPS_PPC32_ISA2_07;
6147 
6148 
6149    mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
6150             | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX | VEX_HWCAPS_PPC64_DFP
6151             | VEX_HWCAPS_PPC64_ISA2_07;
6152 
6153    if (mode64) {
6154       vassert((hwcaps_host & mask32) == 0);
6155    } else {
6156       vassert((hwcaps_host & mask64) == 0);
6157    }
6158 
6159    /* Check that the host's endianness is as expected. */
6160    vassert((archinfo_host->endness == VexEndnessBE) ||
6161 	   (archinfo_host->endness == VexEndnessLE));
6162 
6163    if (archinfo_host->endness == VexEndnessBE)
6164      IEndianess = Iend_BE;
6165    else
6166      IEndianess = Iend_LE;
6167 
6168    /* Make up an initial environment to use. */
6169    env = LibVEX_Alloc_inline(sizeof(ISelEnv));
6170    env->vreg_ctr = 0;
6171 
6172    /* Are we being ppc32 or ppc64? */
6173    env->mode64 = mode64;
6174 
6175    /* Set up output code array. */
6176    env->code = newHInstrArray();
6177 
6178    /* Copy BB's type env. */
6179    env->type_env = bb->tyenv;
6180 
6181    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
6182     * change as we go along.
6183     *
6184     * vregmap2 and vregmap3 are only used in 32 bit mode
6185     * for supporting I128 in 32-bit mode
6186     */
6187    env->n_vregmap = bb->tyenv->types_used;
6188    env->vregmapLo    = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6189    env->vregmapMedLo = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6190    if (mode64) {
6191       env->vregmapMedHi = NULL;
6192       env->vregmapHi    = NULL;
6193    } else {
6194       env->vregmapMedHi = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6195       env->vregmapHi    = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
6196    }
6197 
6198    /* and finally ... */
6199    env->chainingAllowed = chainingAllowed;
6200    env->max_ga          = max_ga;
6201    env->hwcaps          = hwcaps_host;
6202    env->previous_rm     = NULL;
6203    env->vbi             = vbi;
6204 
6205    /* For each IR temporary, allocate a suitably-kinded virtual
6206       register. */
6207    j = 0;
6208    for (i = 0; i < env->n_vregmap; i++) {
6209       hregLo = hregMedLo = hregMedHi = hregHi = INVALID_HREG;
6210       switch (bb->tyenv->types[i]) {
6211       case Ity_I1:
6212       case Ity_I8:
6213       case Ity_I16:
6214       case Ity_I32:
6215          if (mode64) {
6216             hregLo = mkHReg(True, HRcInt64, 0, j++);
6217          } else {
6218             hregLo = mkHReg(True, HRcInt32, 0, j++);
6219          }
6220          break;
6221       case Ity_I64:
6222          if (mode64) {
6223             hregLo    = mkHReg(True, HRcInt64, 0, j++);
6224          } else {
6225             hregLo    = mkHReg(True, HRcInt32, 0, j++);
6226             hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6227          }
6228          break;
6229       case Ity_I128:
6230          if (mode64) {
6231             hregLo    = mkHReg(True, HRcInt64, 0, j++);
6232             hregMedLo = mkHReg(True, HRcInt64, 0, j++);
6233          } else {
6234             hregLo    = mkHReg(True, HRcInt32, 0, j++);
6235             hregMedLo = mkHReg(True, HRcInt32, 0, j++);
6236             hregMedHi = mkHReg(True, HRcInt32, 0, j++);
6237             hregHi    = mkHReg(True, HRcInt32, 0, j++);
6238          }
6239          break;
6240       case Ity_F32:
6241       case Ity_F64:
6242          hregLo = mkHReg(True, HRcFlt64, 0, j++);
6243          break;
6244       case Ity_V128:
6245          hregLo = mkHReg(True, HRcVec128, 0, j++);
6246          break;
6247       case Ity_D32:
6248       case Ity_D64:
6249          hregLo = mkHReg(True, HRcFlt64, 0, j++);
6250          break;
6251       case Ity_D128:
6252          hregLo    = mkHReg(True, HRcFlt64, 0, j++);
6253          hregMedLo = mkHReg(True, HRcFlt64, 0, j++);
6254          break;
6255       default:
6256          ppIRType(bb->tyenv->types[i]);
6257          vpanic("iselBB(ppc): IRTemp type");
6258       }
6259       env->vregmapLo[i]    = hregLo;
6260       env->vregmapMedLo[i] = hregMedLo;
6261       if (!mode64) {
6262          env->vregmapMedHi[i] = hregMedHi;
6263          env->vregmapHi[i]    = hregHi;
6264       }
6265    }
6266    env->vreg_ctr = j;
6267 
6268    /* The very first instruction must be an event check. */
6269    amCounter  = PPCAMode_IR(offs_Host_EvC_Counter, hregPPC_GPR31(mode64));
6270    amFailAddr = PPCAMode_IR(offs_Host_EvC_FailAddr, hregPPC_GPR31(mode64));
6271    addInstr(env, PPCInstr_EvCheck(amCounter, amFailAddr));
6272 
6273    /* Possibly a block counter increment (for profiling).  At this
6274       point we don't know the address of the counter, so just pretend
6275       it is zero.  It will have to be patched later, but before this
6276       translation is used, by a call to LibVEX_patchProfCtr. */
6277    if (addProfInc) {
6278       addInstr(env, PPCInstr_ProfInc());
6279    }
6280 
6281    /* Ok, finally we can iterate over the statements. */
6282    for (i = 0; i < bb->stmts_used; i++)
6283       iselStmt(env, bb->stmts[i], IEndianess);
6284 
6285    iselNext(env, bb->next, bb->jumpkind, bb->offsIP, IEndianess);
6286 
6287    /* record the number of vregs we used. */
6288    env->code->n_vregs = env->vreg_ctr;
6289    return env->code;
6290 }
6291 
6292 
6293 /*---------------------------------------------------------------*/
6294 /*--- end                                     host_ppc_isel.c ---*/
6295 /*---------------------------------------------------------------*/
6296