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