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-2011 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_ppc_defs.h"
45
46/* GPR register class for ppc32/64 */
47#define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32)
48
49
50/*---------------------------------------------------------*/
51/*--- Register Usage Conventions                        ---*/
52/*---------------------------------------------------------*/
53/*
54  Integer Regs
55  ------------
56  GPR0       Reserved
57  GPR1       Stack Pointer
58  GPR2       not used - TOC pointer
59  GPR3:10    Allocateable
60  GPR11      if mode64: not used - calls by ptr / env ptr for some langs
61  GPR12      if mode64: not used - exceptions / global linkage code
62  GPR13      not used - Thread-specific pointer
63  GPR14:28   Allocateable
64  GPR29      Unused by us (reserved for the dispatcher)
65  GPR30      AltiVec temp spill register
66  GPR31      GuestStatePointer
67
68  Of Allocateable regs:
69  if (mode64)
70    GPR3:10  Caller-saved regs
71  else
72    GPR3:12  Caller-saved regs
73  GPR14:29   Callee-saved regs
74
75  GPR3       [Return | Parameter] - carrying reg
76  GPR4:10    Parameter-carrying regs
77
78
79  Floating Point Regs
80  -------------------
81  FPR0:31    Allocateable
82
83  FPR0       Caller-saved - scratch reg
84  if (mode64)
85    FPR1:13  Caller-saved - param & return regs
86  else
87    FPR1:8   Caller-saved - param & return regs
88    FPR9:13  Caller-saved regs
89  FPR14:31   Callee-saved regs
90
91
92  Vector Regs (on processors with the VMX feature)
93  -----------
94  VR0-VR1    Volatile scratch registers
95  VR2-VR13   Volatile vector parameters registers
96  VR14-VR19  Volatile scratch registers
97  VR20-VR31  Non-volatile registers
98  VRSAVE     Non-volatile 32-bit register
99*/
100
101
102/*---------------------------------------------------------*/
103/*--- PPC FP Status & Control Register Conventions      ---*/
104/*---------------------------------------------------------*/
105/*
106  Vex-generated code expects to run with the FPU set as follows: all
107  exceptions masked.  The rounding mode is set appropriately before
108  each floating point insn emitted (or left unchanged if known to be
109  correct already).  There are a few fp insns (fmr,fneg,fabs,fnabs),
110  which are unaffected by the rm and so the rounding mode is not set
111  prior to them.
112
113  At least on MPC7447A (Mac Mini), frsqrte is also not affected by
114  rounding mode.  At some point the ppc docs get sufficiently vague
115  that the only way to find out is to write test programs.
116*/
117/* Notes on the FP instruction set, 6 Feb 06.
118
119What                 exns -> CR1 ?   Sets FPRF ?   Observes RM ?
120-------------------------------------------------------------
121
122fmr[.]                   if .             n             n
123fneg[.]                  if .             n             n
124fabs[.]                  if .             n             n
125fnabs[.]                 if .             n             n
126
127fadd[.]                  if .             y             y
128fadds[.]                 if .             y             y
129fcfid[.] (Si64->dbl)     if .             y             y
130fcfidU[.] (Ui64->dbl)    if .             y             y
131fcfids[.] (Si64->sngl)   if .             Y             Y
132fcfidus[.] (Ui64->sngl)  if .             Y             Y
133fcmpo (cmp, result       n                n             n
134fcmpu  to crfD)          n                n             n
135fctid[.]  (dbl->i64)     if .       ->undef             y
136fctidz[.] (dbl->i64)     if .       ->undef    rounds-to-zero
137fctiw[.]  (dbl->i32)     if .       ->undef             y
138fctiwz[.] (dbl->i32)     if .       ->undef    rounds-to-zero
139fdiv[.]                  if .             y             y
140fdivs[.]                 if .             y             y
141fmadd[.]                 if .             y             y
142fmadds[.]                if .             y             y
143fmsub[.]                 if .             y             y
144fmsubs[.]                if .             y             y
145fmul[.]                  if .             y             y
146fmuls[.]                 if .             y             y
147
148(note: for fnm*, rounding happens before final negation)
149fnmadd[.]                if .             y             y
150fnmadds[.]               if .             y             y
151fnmsub[.]                if .             y             y
152fnmsubs[.]               if .             y             y
153
154fre[.]                   if .             y             y
155fres[.]                  if .             y             y
156
157frsqrte[.]               if .             y       apparently not
158
159fsqrt[.]                 if .             y             y
160fsqrts[.]                if .             y             y
161fsub[.]                  if .             y             y
162fsubs[.]                 if .             y             y
163
164
165fpscr: bits 30-31 (ibm) is RM
166            24-29 (ibm) are exnmasks/non-IEEE bit, all zero
167	    15-19 (ibm) is FPRF: class, <, =, >, UNord
168
169ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF
170in future)
171
172mcrfs     - move fpscr field to CR field
173mtfsfi[.] - 4 bit imm moved to fpscr field
174mtfsf[.]  - move frS[low 1/2] to fpscr but using 8-bit field mask
175mtfsb1[.] - set given fpscr bit
176mtfsb0[.] - clear given fpscr bit
177mffs[.]   - move all fpscr to frD[low 1/2]
178
179For [.] presumably cr1 is set with exn summary bits, as per
180main FP insns
181
182A single precision store truncates/denormalises the in-register value,
183but does not round it.  This is so that flds followed by fsts is
184always the identity.
185*/
186
187
188/*---------------------------------------------------------*/
189/*--- misc helpers                                      ---*/
190/*---------------------------------------------------------*/
191
192/* These are duplicated in guest-ppc/toIR.c */
193static IRExpr* unop ( IROp op, IRExpr* a )
194{
195   return IRExpr_Unop(op, a);
196}
197
198static IRExpr* mkU32 ( UInt i )
199{
200   return IRExpr_Const(IRConst_U32(i));
201}
202
203static IRExpr* bind ( Int binder )
204{
205   return IRExpr_Binder(binder);
206}
207
208
209/*---------------------------------------------------------*/
210/*--- ISelEnv                                           ---*/
211/*---------------------------------------------------------*/
212
213/* This carries around:
214
215   - A mapping from IRTemp to IRType, giving the type of any IRTemp we
216     might encounter.  This is computed before insn selection starts,
217     and does not change.
218
219   - A mapping from IRTemp to HReg.  This tells the insn selector
220     which virtual register(s) are associated with each IRTemp
221      temporary.  This is computed before insn selection starts, and
222      does not change.  We expect this mapping to map precisely the
223      same set of IRTemps as the type mapping does.
224
225         - vregmap   holds the primary register for the IRTemp.
226         - vregmapHI holds the secondary register for the IRTemp,
227              if any is needed.  That's only for Ity_I64 temps
228              in 32 bit mode or Ity_I128 temps in 64-bit mode.
229
230    - The name of the vreg in which we stash a copy of the link reg,
231      so helper functions don't kill it.
232
233    - The code array, that is, the insns selected so far.
234
235    - A counter, for generating new virtual registers.
236
237    - The host subarchitecture we are selecting insns for.
238      This is set at the start and does not change.
239
240    - A Bool to tell us if the host is 32 or 64bit.
241      This is set at the start and does not change.
242
243    - An IRExpr*, which may be NULL, holding the IR expression (an
244      IRRoundingMode-encoded value) to which the FPU's rounding mode
245      was most recently set.  Setting to NULL is always safe.  Used to
246      avoid redundant settings of the FPU's rounding mode, as
247      described in set_FPU_rounding_mode below.
248
249    - A VexMiscInfo*, needed for knowing how to generate
250      function calls for this target
251*/
252
253typedef
254   struct {
255      IRTypeEnv*   type_env;
256
257      HReg*        vregmap;
258      HReg*        vregmapHI;
259      Int          n_vregmap;
260
261      HReg         savedLR;
262
263      HInstrArray* code;
264
265      Int          vreg_ctr;
266
267      /* 27 Jan 06: Not currently used, but should be */
268      UInt         hwcaps;
269
270      Bool         mode64;
271
272      IRExpr*      previous_rm;
273
274      VexAbiInfo*  vbi;
275   }
276   ISelEnv;
277
278
279static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
280{
281   vassert(tmp >= 0);
282   vassert(tmp < env->n_vregmap);
283   return env->vregmap[tmp];
284}
285
286static void lookupIRTempPair ( HReg* vrHI, HReg* vrLO,
287                               ISelEnv* env, IRTemp tmp )
288{
289   vassert(!env->mode64);
290   vassert(tmp >= 0);
291   vassert(tmp < env->n_vregmap);
292   vassert(env->vregmapHI[tmp] != INVALID_HREG);
293   *vrLO = env->vregmap[tmp];
294   *vrHI = env->vregmapHI[tmp];
295}
296
297static void addInstr ( ISelEnv* env, PPCInstr* instr )
298{
299   addHInstr(env->code, instr);
300   if (vex_traceflags & VEX_TRACE_VCODE) {
301      ppPPCInstr(instr, env->mode64);
302      vex_printf("\n");
303   }
304}
305
306static HReg newVRegI ( ISelEnv* env )
307{
308   HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64),
309                     True/*virtual reg*/);
310   env->vreg_ctr++;
311   return reg;
312}
313
314static HReg newVRegF ( ISelEnv* env )
315{
316   HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/);
317   env->vreg_ctr++;
318   return reg;
319}
320
321static HReg newVRegV ( ISelEnv* env )
322{
323   HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/);
324   env->vreg_ctr++;
325   return reg;
326}
327
328
329/*---------------------------------------------------------*/
330/*--- ISEL: Forward declarations                        ---*/
331/*---------------------------------------------------------*/
332
333/* These are organised as iselXXX and iselXXX_wrk pairs.  The
334   iselXXX_wrk do the real work, but are not to be called directly.
335   For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
336   checks that all returned registers are virtual.  You should not
337   call the _wrk version directly.
338
339   'Word' refers to the size of the native machine word, that is,
340   32-bit int in 32-bit mode and 64-bit int in 64-bit mode.  '2Word'
341   therefore refers to a double-width (64/128-bit) quantity in two
342   integer registers.
343*/
344/* 32-bit mode: compute an I8/I16/I32 into a GPR.
345   64-bit mode: compute an I8/I16/I32/I64 into a GPR. */
346static HReg          iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e );
347static HReg          iselWordExpr_R     ( ISelEnv* env, IRExpr* e );
348
349/* 32-bit mode: Compute an I8/I16/I32 into a RH
350                (reg-or-halfword-immediate).
351   64-bit mode: Compute an I8/I16/I32/I64 into a RH
352                (reg-or-halfword-immediate).
353   It's important to specify whether the immediate is to be regarded
354   as signed or not.  If yes, this will never return -32768 as an
355   immediate; this guaranteed that all signed immediates that are
356   return can have their sign inverted if need be.
357*/
358static PPCRH*        iselWordExpr_RH_wrk ( ISelEnv* env,
359                                           Bool syned, IRExpr* e );
360static PPCRH*        iselWordExpr_RH     ( ISelEnv* env,
361                                           Bool syned, IRExpr* e );
362
363/* 32-bit mode: compute an I32 into a RI (reg or 32-bit immediate).
364   64-bit mode: compute an I64 into a RI (reg or 64-bit immediate). */
365static PPCRI*        iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
366static PPCRI*        iselWordExpr_RI     ( ISelEnv* env, IRExpr* e );
367
368/* In 32 bit mode ONLY, compute an I8 into a
369   reg-or-5-bit-unsigned-immediate, the latter being an immediate in
370   the range 1 .. 31 inclusive.  Used for doing shift amounts. */
371static PPCRH*        iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e );
372static PPCRH*        iselWordExpr_RH5u     ( ISelEnv* env, IRExpr* e );
373
374/* In 64-bit mode ONLY, compute an I8 into a
375   reg-or-6-bit-unsigned-immediate, the latter being an immediate in
376   the range 1 .. 63 inclusive.  Used for doing shift amounts. */
377static PPCRH*        iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e );
378static PPCRH*        iselWordExpr_RH6u     ( ISelEnv* env, IRExpr* e );
379
380/* 32-bit mode: compute an I32 into an AMode.
381   64-bit mode: compute an I64 into an AMode.
382
383   Requires to know (xferTy) the type of data to be loaded/stored
384   using this amode.  That is so that, for 64-bit code generation, any
385   PPCAMode_IR returned will have an index (immediate offset) field
386   that is guaranteed to be 4-aligned, if there is any chance that the
387   amode is to be used in ld/ldu/lda/std/stdu.
388
389   Since there are no such restrictions on 32-bit insns, xferTy is
390   ignored for 32-bit code generation. */
391static PPCAMode*     iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy );
392static PPCAMode*     iselWordExpr_AMode     ( ISelEnv* env, IRExpr* e, IRType xferTy );
393
394/* 32-bit mode ONLY: compute an I64 into a GPR pair. */
395static void          iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
396                                         ISelEnv* env, IRExpr* e );
397static void          iselInt64Expr     ( HReg* rHi, HReg* rLo,
398                                         ISelEnv* env, IRExpr* e );
399
400/* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
401static void          iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
402                                          ISelEnv* env, IRExpr* e );
403static void          iselInt128Expr     ( HReg* rHi, HReg* rLo,
404                                          ISelEnv* env, IRExpr* e );
405
406static PPCCondCode   iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
407static PPCCondCode   iselCondCode     ( ISelEnv* env, IRExpr* e );
408
409static HReg          iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );
410static HReg          iselDblExpr     ( ISelEnv* env, IRExpr* e );
411
412static HReg          iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );
413static HReg          iselFltExpr     ( ISelEnv* env, IRExpr* e );
414
415static HReg          iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );
416static HReg          iselVecExpr     ( ISelEnv* env, IRExpr* e );
417
418
419/*---------------------------------------------------------*/
420/*--- ISEL: Misc helpers                                ---*/
421/*---------------------------------------------------------*/
422
423/* Make an int reg-reg move. */
424
425static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src )
426{
427   vassert(hregClass(r_dst) == hregClass(r_src));
428   vassert(hregClass(r_src) ==  HRcInt32 ||
429           hregClass(r_src) ==  HRcInt64);
430   return PPCInstr_Alu(Palu_OR, r_dst, r_src, PPCRH_Reg(r_src));
431}
432
433/* Advance/retreat %r1 by n. */
434
435static void add_to_sp ( ISelEnv* env, UInt n )
436{
437   HReg sp = StackFramePtr(env->mode64);
438   vassert(n < 256 && (n%16) == 0);
439   addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp,
440                               PPCRH_Imm(True,toUShort(n)) ));
441}
442
443static void sub_from_sp ( ISelEnv* env, UInt n )
444{
445   HReg sp = StackFramePtr(env->mode64);
446   vassert(n < 256 && (n%16) == 0);
447   addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp,
448                               PPCRH_Imm(True,toUShort(n)) ));
449}
450
451/*
452  returns a quadword aligned address on the stack
453   - copies SP, adds 16bytes, aligns to quadword.
454  use sub_from_sp(32) before calling this,
455  as expects to have 32 bytes to play with.
456*/
457static HReg get_sp_aligned16 ( ISelEnv* env )
458{
459   HReg       r = newVRegI(env);
460   HReg align16 = newVRegI(env);
461   addInstr(env, mk_iMOVds_RR(r, StackFramePtr(env->mode64)));
462   // add 16
463   addInstr(env, PPCInstr_Alu( Palu_ADD, r, r,
464                               PPCRH_Imm(True,toUShort(16)) ));
465   // mask to quadword
466   addInstr(env,
467            PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64));
468   addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16)));
469   return r;
470}
471
472
473
474/* Load 2*I32 regs to fp reg */
475static HReg mk_LoadRR32toFPR ( ISelEnv* env,
476                               HReg r_srcHi, HReg r_srcLo )
477{
478   HReg fr_dst = newVRegF(env);
479   PPCAMode *am_addr0, *am_addr1;
480
481   vassert(!env->mode64);
482   vassert(hregClass(r_srcHi) == HRcInt32);
483   vassert(hregClass(r_srcLo) == HRcInt32);
484
485   sub_from_sp( env, 16 );        // Move SP down 16 bytes
486   am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
487   am_addr1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) );
488
489   // store hi,lo as Ity_I32's
490   addInstr(env, PPCInstr_Store( 4, am_addr0, r_srcHi, env->mode64 ));
491   addInstr(env, PPCInstr_Store( 4, am_addr1, r_srcLo, env->mode64 ));
492
493   // load as float
494   addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
495
496   add_to_sp( env, 16 );          // Reset SP
497   return fr_dst;
498}
499
500/* Load I64 reg to fp reg */
501static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src )
502{
503   HReg fr_dst = newVRegF(env);
504   PPCAMode *am_addr0;
505
506   vassert(env->mode64);
507   vassert(hregClass(r_src) == HRcInt64);
508
509   sub_from_sp( env, 16 );        // Move SP down 16 bytes
510   am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
511
512   // store as Ity_I64
513   addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 ));
514
515   // load as float
516   addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0));
517
518   add_to_sp( env, 16 );          // Reset SP
519   return fr_dst;
520}
521
522
523/* Given an amode, return one which references 4 bytes further
524   along. */
525
526static PPCAMode* advance4 ( ISelEnv* env, PPCAMode* am )
527{
528   PPCAMode* am4 = dopyPPCAMode( am );
529   if (am4->tag == Pam_IR
530       && am4->Pam.IR.index + 4 <= 32767) {
531      am4->Pam.IR.index += 4;
532   } else {
533      vpanic("advance4(ppc,host)");
534   }
535   return am4;
536}
537
538
539/* Given a guest-state array descriptor, an index expression and a
540   bias, generate a PPCAMode pointing at the relevant piece of
541   guest state.  */
542static
543PPCAMode* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
544                                IRExpr* off, Int bias )
545{
546   HReg rtmp, roff;
547   Int  elemSz = sizeofIRType(descr->elemTy);
548   Int  nElems = descr->nElems;
549   Int  shift  = 0;
550
551   /* Throw out any cases we don't need.  In theory there might be a
552      day where we need to handle others, but not today. */
553
554   if (nElems != 16 && nElems != 32)
555      vpanic("genGuestArrayOffset(ppc host)(1)");
556
557   switch (elemSz) {
558      case 4:  shift = 2; break;
559      case 8:  shift = 3; break;
560      default: vpanic("genGuestArrayOffset(ppc host)(2)");
561   }
562
563   if (bias < -100 || bias > 100) /* somewhat arbitrarily */
564      vpanic("genGuestArrayOffset(ppc host)(3)");
565   if (descr->base < 0 || descr->base > 5000) /* somewhat arbitrarily */
566      vpanic("genGuestArrayOffset(ppc host)(4)");
567
568   /* Compute off into a reg, %off.  Then return:
569
570         addi %tmp, %off, bias (if bias != 0)
571         andi %tmp, nElems-1
572         sldi %tmp, shift
573         addi %tmp, %tmp, base
574         ... Baseblockptr + %tmp ...
575   */
576   roff = iselWordExpr_R(env, off);
577   rtmp = newVRegI(env);
578   addInstr(env, PPCInstr_Alu(
579                    Palu_ADD,
580                    rtmp, roff,
581                    PPCRH_Imm(True/*signed*/, toUShort(bias))));
582   addInstr(env, PPCInstr_Alu(
583                    Palu_AND,
584                    rtmp, rtmp,
585                    PPCRH_Imm(False/*unsigned*/, toUShort(nElems-1))));
586   addInstr(env, PPCInstr_Shft(
587                    Pshft_SHL,
588                    env->mode64 ? False : True/*F:64-bit, T:32-bit shift*/,
589                    rtmp, rtmp,
590                    PPCRH_Imm(False/*unsigned*/, toUShort(shift))));
591   addInstr(env, PPCInstr_Alu(
592                    Palu_ADD,
593                    rtmp, rtmp,
594                    PPCRH_Imm(True/*signed*/, toUShort(descr->base))));
595   return
596      PPCAMode_RR( GuestStatePtr(env->mode64), rtmp );
597}
598
599
600/*---------------------------------------------------------*/
601/*--- ISEL: Function call helpers                       ---*/
602/*---------------------------------------------------------*/
603
604/* Used only in doHelperCall.  See big comment in doHelperCall re
605   handling of register-parameter args.  This function figures out
606   whether evaluation of an expression might require use of a fixed
607   register.  If in doubt return True (safe but suboptimal).
608*/
609static
610Bool mightRequireFixedRegs ( IRExpr* e )
611{
612   switch (e->tag) {
613   case Iex_RdTmp: case Iex_Const: case Iex_Get:
614      return False;
615   default:
616      return True;
617   }
618}
619
620
621/* Do a complete function call.  guard is a Ity_Bit expression
622   indicating whether or not the call happens.  If guard==NULL, the
623   call is unconditional. */
624
625static
626void doHelperCall ( ISelEnv* env,
627                    Bool passBBP,
628                    IRExpr* guard, IRCallee* cee, IRExpr** args )
629{
630   PPCCondCode cc;
631   HReg        argregs[PPC_N_REGPARMS];
632   HReg        tmpregs[PPC_N_REGPARMS];
633   Bool        go_fast;
634   Int         n_args, i, argreg;
635   UInt        argiregs;
636   ULong       target;
637   Bool        mode64 = env->mode64;
638
639   /* Do we need to force use of an odd-even reg pair for 64-bit
640      args? */
641   Bool regalign_int64s
642      = (!mode64) && env->vbi->host_ppc32_regalign_int64_args;
643
644   /* Marshal args for a call and do the call.
645
646      If passBBP is True, %rbp (the baseblock pointer) is to be passed
647      as the first arg.
648
649      This function only deals with a tiny set of possibilities, which
650      cover all helpers in practice.  The restrictions are that only
651      arguments in registers are supported, hence only PPC_N_REGPARMS x
652      (mode32:32 | mode64:64) integer bits in total can be passed.
653      In fact the only supported arg type is (mode32:I32 | mode64:I64).
654
655      Generating code which is both efficient and correct when
656      parameters are to be passed in registers is difficult, for the
657      reasons elaborated in detail in comments attached to
658      doHelperCall() in priv/host-x86/isel.c.  Here, we use a variant
659      of the method described in those comments.
660
661      The problem is split into two cases: the fast scheme and the
662      slow scheme.  In the fast scheme, arguments are computed
663      directly into the target (real) registers.  This is only safe
664      when we can be sure that computation of each argument will not
665      trash any real registers set by computation of any other
666      argument.
667
668      In the slow scheme, all args are first computed into vregs, and
669      once they are all done, they are moved to the relevant real
670      regs.  This always gives correct code, but it also gives a bunch
671      of vreg-to-rreg moves which are usually redundant but are hard
672      for the register allocator to get rid of.
673
674      To decide which scheme to use, all argument expressions are
675      first examined.  If they are all so simple that it is clear they
676      will be evaluated without use of any fixed registers, use the
677      fast scheme, else use the slow scheme.  Note also that only
678      unconditional calls may use the fast scheme, since having to
679      compute a condition expression could itself trash real
680      registers.
681
682      Note this requires being able to examine an expression and
683      determine whether or not evaluation of it might use a fixed
684      register.  That requires knowledge of how the rest of this insn
685      selector works.  Currently just the following 3 are regarded as
686      safe -- hopefully they cover the majority of arguments in
687      practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
688   */
689
690   /* Note that the cee->regparms field is meaningless on PPC32/64 host
691      (since there is only one calling convention) and so we always
692      ignore it. */
693
694   n_args = 0;
695   for (i = 0; args[i]; i++)
696      n_args++;
697
698   if (PPC_N_REGPARMS < n_args + (passBBP ? 1 : 0)) {
699      vpanic("doHelperCall(PPC): cannot currently handle > 8 args");
700      // PPC_N_REGPARMS
701   }
702
703   argregs[0] = hregPPC_GPR3(mode64);
704   argregs[1] = hregPPC_GPR4(mode64);
705   argregs[2] = hregPPC_GPR5(mode64);
706   argregs[3] = hregPPC_GPR6(mode64);
707   argregs[4] = hregPPC_GPR7(mode64);
708   argregs[5] = hregPPC_GPR8(mode64);
709   argregs[6] = hregPPC_GPR9(mode64);
710   argregs[7] = hregPPC_GPR10(mode64);
711   argiregs = 0;
712
713   tmpregs[0] = tmpregs[1] = tmpregs[2] =
714   tmpregs[3] = tmpregs[4] = tmpregs[5] =
715   tmpregs[6] = tmpregs[7] = INVALID_HREG;
716
717   /* First decide which scheme (slow or fast) is to be used.  First
718      assume the fast scheme, and select slow if any contraindications
719      (wow) appear. */
720
721   go_fast = True;
722
723   if (guard) {
724      if (guard->tag == Iex_Const
725          && guard->Iex.Const.con->tag == Ico_U1
726          && guard->Iex.Const.con->Ico.U1 == True) {
727         /* unconditional */
728      } else {
729         /* Not manifestly unconditional -- be conservative. */
730         go_fast = False;
731      }
732   }
733
734   if (go_fast) {
735      for (i = 0; i < n_args; i++) {
736         if (mightRequireFixedRegs(args[i])) {
737            go_fast = False;
738            break;
739         }
740      }
741   }
742
743   /* At this point the scheme to use has been established.  Generate
744      code to get the arg values into the argument rregs. */
745
746   if (go_fast) {
747
748      /* FAST SCHEME */
749      argreg = 0;
750      if (passBBP) {
751         argiregs |= (1 << (argreg+3));
752         addInstr(env, mk_iMOVds_RR( argregs[argreg],
753                                     GuestStatePtr(mode64) ));
754         argreg++;
755      }
756
757      for (i = 0; i < n_args; i++) {
758         vassert(argreg < PPC_N_REGPARMS);
759         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
760                 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
761         if (!mode64) {
762            if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
763               argiregs |= (1 << (argreg+3));
764               addInstr(env,
765                        mk_iMOVds_RR( argregs[argreg],
766                                      iselWordExpr_R(env, args[i]) ));
767            } else { // Ity_I64
768               HReg rHi, rLo;
769               if (regalign_int64s && (argreg%2) == 1)
770                              // ppc32 ELF abi spec for passing LONG_LONG
771                  argreg++;   // XXX: odd argreg => even rN
772               vassert(argreg < PPC_N_REGPARMS-1);
773               iselInt64Expr(&rHi,&rLo, env, args[i]);
774               argiregs |= (1 << (argreg+3));
775               addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
776               argiregs |= (1 << (argreg+3));
777               addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
778            }
779         } else { // mode64
780            argiregs |= (1 << (argreg+3));
781            addInstr(env, mk_iMOVds_RR( argregs[argreg],
782                                        iselWordExpr_R(env, args[i]) ));
783         }
784         argreg++;
785      }
786
787      /* Fast scheme only applies for unconditional calls.  Hence: */
788      cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
789
790   } else {
791
792      /* SLOW SCHEME; move via temporaries */
793      argreg = 0;
794
795      if (passBBP) {
796         /* This is pretty stupid; better to move directly to r3
797            after the rest of the args are done. */
798         tmpregs[argreg] = newVRegI(env);
799         addInstr(env, mk_iMOVds_RR( tmpregs[argreg],
800                                     GuestStatePtr(mode64) ));
801         argreg++;
802      }
803
804      for (i = 0; i < n_args; i++) {
805         vassert(argreg < PPC_N_REGPARMS);
806         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 ||
807                 typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
808         if (!mode64) {
809            if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
810               tmpregs[argreg] = iselWordExpr_R(env, args[i]);
811            } else { // Ity_I64
812               HReg rHi, rLo;
813               if (regalign_int64s && (argreg%2) == 1)
814                             // ppc32 ELF abi spec for passing LONG_LONG
815                  argreg++;  // XXX: odd argreg => even rN
816               vassert(argreg < PPC_N_REGPARMS-1);
817               iselInt64Expr(&rHi,&rLo, env, args[i]);
818               tmpregs[argreg++] = rHi;
819               tmpregs[argreg]   = rLo;
820            }
821         } else { // mode64
822            tmpregs[argreg] = iselWordExpr_R(env, args[i]);
823         }
824         argreg++;
825      }
826
827      /* Now we can compute the condition.  We can't do it earlier
828         because the argument computations could trash the condition
829         codes.  Be a bit clever to handle the common case where the
830         guard is 1:Bit. */
831      cc = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
832      if (guard) {
833         if (guard->tag == Iex_Const
834             && guard->Iex.Const.con->tag == Ico_U1
835             && guard->Iex.Const.con->Ico.U1 == True) {
836            /* unconditional -- do nothing */
837         } else {
838            cc = iselCondCode( env, guard );
839         }
840      }
841
842      /* Move the args to their final destinations. */
843      for (i = 0; i < argreg; i++) {
844         if (tmpregs[i] == INVALID_HREG)  // Skip invalid regs
845            continue;
846         /* None of these insns, including any spill code that might
847            be generated, may alter the condition codes. */
848         argiregs |= (1 << (i+3));
849         addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
850      }
851
852   }
853
854   target = mode64 ? Ptr_to_ULong(cee->addr) :
855                     toUInt(Ptr_to_ULong(cee->addr));
856
857   /* Finally, the call itself. */
858   addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs ));
859}
860
861
862/*---------------------------------------------------------*/
863/*--- ISEL: FP rounding mode helpers                    ---*/
864/*---------------------------------------------------------*/
865
866///* Set FPU's rounding mode to the default */
867//static
868//void set_FPU_rounding_default ( ISelEnv* env )
869//{
870//   HReg fr_src = newVRegF(env);
871//   HReg r_src  = newVRegI(env);
872//
873//   /* Default rounding mode = 0x0
874//      Only supporting the rounding-mode bits - the rest of FPSCR is 0x0
875//       - so we can set the whole register at once (faster)
876//      note: upper 32 bits ignored by FpLdFPSCR
877//   */
878//   addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64));
879//   if (env->mode64) {
880//      fr_src = mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
881//   } else {
882//      fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
883//   }
884//   addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
885//}
886
887/* Convert IR rounding mode to PPC encoding */
888static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR )
889{
890   /*
891   rounding mode | PPC | IR
892   ------------------------
893   to nearest    | 00  | 00
894   to zero       | 01  | 11
895   to +infinity  | 10  | 10
896   to -infinity  | 11  | 01
897   */
898   HReg r_rmPPC = newVRegI(env);
899   HReg r_tmp1  = newVRegI(env);
900
901   vassert(hregClass(r_rmIR) == HRcGPR(env->mode64));
902
903   // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3
904   //
905   // slwi  tmp1,    r_rmIR, 1
906   // xor   tmp1,    r_rmIR, tmp1
907   // andi  r_rmPPC, tmp1, 3
908
909   addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
910                               r_tmp1, r_rmIR, PPCRH_Imm(False,1)));
911
912   addInstr(env, PPCInstr_Alu( Palu_XOR, r_tmp1, r_rmIR,
913                               PPCRH_Reg(r_tmp1) ));
914
915   addInstr(env, PPCInstr_Alu( Palu_AND, r_rmPPC, r_tmp1,
916                               PPCRH_Imm(False,3) ));
917
918   return r_rmPPC;
919}
920
921
922/* Set the FPU's rounding mode: 'mode' is an I32-typed expression
923   denoting a value in the range 0 .. 3, indicating a round mode
924   encoded as per type IRRoundingMode.  Set the PPC FPSCR to have the
925   same rounding.
926
927   For speed & simplicity, we're setting the *entire* FPSCR here.
928
929   Setting the rounding mode is expensive.  So this function tries to
930   avoid repeatedly setting the rounding mode to the same thing by
931   first comparing 'mode' to the 'mode' tree supplied in the previous
932   call to this function, if any.  (The previous value is stored in
933   env->previous_rm.)  If 'mode' is a single IR temporary 't' and
934   env->previous_rm is also just 't', then the setting is skipped.
935
936   This is safe because of the SSA property of IR: an IR temporary can
937   only be defined once and so will have the same value regardless of
938   where it appears in the block.  Cool stuff, SSA.
939
940   A safety condition: all attempts to set the RM must be aware of
941   this mechanism - by being routed through the functions here.
942
943   Of course this only helps if blocks where the RM is set more than
944   once and it is set to the same value each time, *and* that value is
945   held in the same IR temporary each time.  In order to assure the
946   latter as much as possible, the IR optimiser takes care to do CSE
947   on any block with any sign of floating point activity.
948*/
949static
950void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
951{
952   HReg fr_src = newVRegF(env);
953   HReg r_src;
954
955   vassert(typeOfIRExpr(env->type_env,mode) == Ity_I32);
956
957   /* Do we need to do anything? */
958   if (env->previous_rm
959       && env->previous_rm->tag == Iex_RdTmp
960       && mode->tag == Iex_RdTmp
961       && env->previous_rm->Iex.RdTmp.tmp == mode->Iex.RdTmp.tmp) {
962      /* no - setting it to what it was before.  */
963      vassert(typeOfIRExpr(env->type_env, env->previous_rm) == Ity_I32);
964      return;
965   }
966
967   /* No luck - we better set it, and remember what we set it to. */
968   env->previous_rm = mode;
969
970   /* Only supporting the rounding-mode bits - the rest of FPSCR is
971      0x0 - so we can set the whole register at once (faster). */
972
973   // Resolve rounding mode and convert to PPC representation
974   r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode) );
975   // gpr -> fpr
976   if (env->mode64) {
977      fr_src = mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
978   } else {
979      fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64
980   }
981
982   // Move to FPSCR
983   addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));
984}
985
986
987/*---------------------------------------------------------*/
988/*--- ISEL: vector helpers                              ---*/
989/*---------------------------------------------------------*/
990
991/* Generate all-zeroes into a new vector register.
992*/
993static HReg generate_zeroes_V128 ( ISelEnv* env )
994{
995   HReg dst = newVRegV(env);
996   addInstr(env, PPCInstr_AvBinary(Pav_XOR, dst, dst, dst));
997   return dst;
998}
999
1000/* Generate all-ones into a new vector register.
1001*/
1002static HReg generate_ones_V128 ( ISelEnv* env )
1003{
1004   HReg dst = newVRegV(env);
1005   PPCVI5s * src = PPCVI5s_Imm(-1);
1006   addInstr(env, PPCInstr_AvSplat(8, dst, src));
1007   return dst;
1008}
1009
1010
1011/*
1012  Generates code for AvSplat
1013  - takes in IRExpr* of type 8|16|32
1014    returns vector reg of duplicated lanes of input
1015  - uses AvSplat(imm) for imms up to simm6.
1016    otherwise must use store reg & load vector
1017*/
1018static HReg mk_AvDuplicateRI( ISelEnv* env, IRExpr* e )
1019{
1020   HReg   r_src;
1021   HReg   dst = newVRegV(env);
1022   PPCRI* ri  = iselWordExpr_RI(env, e);
1023   IRType ty  = typeOfIRExpr(env->type_env,e);
1024   UInt   sz  = (ty == Ity_I8) ? 8 : (ty == Ity_I16) ? 16 : 32;
1025   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
1026
1027   /* special case: immediate */
1028   if (ri->tag == Pri_Imm) {
1029      Int simm32 = (Int)ri->Pri.Imm;
1030
1031      /* figure out if it's do-able with imm splats. */
1032      if (simm32 >= -32 && simm32 <= 31) {
1033         Char simm6 = (Char)simm32;
1034         if (simm6 > 15) {           /* 16:31 inclusive */
1035            HReg v1 = newVRegV(env);
1036            HReg v2 = newVRegV(env);
1037            addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1038            addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6-16)));
1039            addInstr(env,
1040               (sz== 8) ? PPCInstr_AvBin8x16(Pav_SUBU, dst, v2, v1) :
1041               (sz==16) ? PPCInstr_AvBin16x8(Pav_SUBU, dst, v2, v1)
1042                        : PPCInstr_AvBin32x4(Pav_SUBU, dst, v2, v1) );
1043            return dst;
1044         }
1045         if (simm6 < -16) {          /* -32:-17 inclusive */
1046            HReg v1 = newVRegV(env);
1047            HReg v2 = newVRegV(env);
1048            addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16)));
1049            addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6+16)));
1050            addInstr(env,
1051               (sz== 8) ? PPCInstr_AvBin8x16(Pav_ADDU, dst, v2, v1) :
1052               (sz==16) ? PPCInstr_AvBin16x8(Pav_ADDU, dst, v2, v1)
1053                        : PPCInstr_AvBin32x4(Pav_ADDU, dst, v2, v1) );
1054            return dst;
1055         }
1056         /* simplest form:              -16:15 inclusive */
1057         addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6)));
1058         return dst;
1059      }
1060
1061      /* no luck; use the Slow way. */
1062      r_src = newVRegI(env);
1063      addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64));
1064   }
1065   else {
1066      r_src = ri->Pri.Reg;
1067   }
1068
1069   /* default case: store r_src in lowest lane of 16-aligned mem,
1070      load vector, splat lowest lane to dst */
1071   {
1072      /* CAB: Maybe faster to store r_src multiple times (sz dependent),
1073              and simply load the vector? */
1074      HReg r_aligned16;
1075      HReg v_src = newVRegV(env);
1076      PPCAMode *am_off12;
1077
1078      sub_from_sp( env, 32 );     // Move SP down
1079      /* Get a 16-aligned address within our stack space */
1080      r_aligned16 = get_sp_aligned16( env );
1081      am_off12 = PPCAMode_IR( 12, r_aligned16 );
1082
1083      /* Store r_src in low word of 16-aligned mem */
1084      addInstr(env, PPCInstr_Store( 4, am_off12, r_src, env->mode64 ));
1085
1086      /* Load src to vector[low lane] */
1087      addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, v_src, am_off12 ) );
1088      add_to_sp( env, 32 );       // Reset SP
1089
1090      /* Finally, splat v_src[low_lane] to dst */
1091      addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Reg(v_src)));
1092      return dst;
1093   }
1094}
1095
1096
1097/* for each lane of vSrc: lane == nan ? laneX = all 1's : all 0's */
1098static HReg isNan ( ISelEnv* env, HReg vSrc )
1099{
1100   HReg zeros, msk_exp, msk_mnt, expt, mnts, vIsNan;
1101
1102   vassert(hregClass(vSrc) == HRcVec128);
1103
1104   zeros   = mk_AvDuplicateRI(env, mkU32(0));
1105   msk_exp = mk_AvDuplicateRI(env, mkU32(0x7F800000));
1106   msk_mnt = mk_AvDuplicateRI(env, mkU32(0x7FFFFF));
1107   expt    = newVRegV(env);
1108   mnts    = newVRegV(env);
1109   vIsNan  = newVRegV(env);
1110
1111   /* 32bit float => sign(1) | exponent(8) | mantissa(23)
1112      nan => exponent all ones, mantissa > 0 */
1113
1114   addInstr(env, PPCInstr_AvBinary(Pav_AND, expt, vSrc, msk_exp));
1115   addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, expt, expt, msk_exp));
1116   addInstr(env, PPCInstr_AvBinary(Pav_AND, mnts, vSrc, msk_mnt));
1117   addInstr(env, PPCInstr_AvBin32x4(Pav_CMPGTU, mnts, mnts, zeros));
1118   addInstr(env, PPCInstr_AvBinary(Pav_AND, vIsNan, expt, mnts));
1119   return vIsNan;
1120}
1121
1122
1123/*---------------------------------------------------------*/
1124/*--- ISEL: Integer expressions (64/32/16/8 bit)        ---*/
1125/*---------------------------------------------------------*/
1126
1127/* Select insns for an integer-typed expression, and add them to the
1128   code list.  Return a reg holding the result.  This reg will be a
1129   virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
1130   want to modify it, ask for a new vreg, copy it in there, and modify
1131   the copy.  The register allocator will do its best to map both
1132   vregs to the same real register, so the copies will often disappear
1133   later in the game.
1134
1135   This should handle expressions of 64, 32, 16 and 8-bit type.
1136   All results are returned in a (mode64 ? 64bit : 32bit) register.
1137   For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
1138   are arbitrary, so you should mask or sign extend partial values
1139   if necessary.
1140*/
1141
1142static HReg iselWordExpr_R ( ISelEnv* env, IRExpr* e )
1143{
1144   HReg r = iselWordExpr_R_wrk(env, e);
1145   /* sanity checks ... */
1146#  if 0
1147   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1148#  endif
1149
1150   vassert(hregClass(r) == HRcGPR(env->mode64));
1151   vassert(hregIsVirtual(r));
1152   return r;
1153}
1154
1155/* DO NOT CALL THIS DIRECTLY ! */
1156static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
1157{
1158   Bool mode64 = env->mode64;
1159   MatchInfo mi;
1160   DECLARE_PATTERN(p_32to1_then_1Uto8);
1161
1162   IRType ty = typeOfIRExpr(env->type_env,e);
1163   vassert(ty == Ity_I8 || ty == Ity_I16 ||
1164           ty == Ity_I32 || ((ty == Ity_I64) && mode64));
1165
1166   switch (e->tag) {
1167
1168   /* --------- TEMP --------- */
1169   case Iex_RdTmp:
1170      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1171
1172   /* --------- LOAD --------- */
1173   case Iex_Load: {
1174      HReg      r_dst;
1175      PPCAMode* am_addr;
1176      if (e->Iex.Load.end != Iend_BE)
1177         goto irreducible;
1178      r_dst   = newVRegI(env);
1179      am_addr = iselWordExpr_AMode( env, e->Iex.Load.addr, ty/*of xfer*/ );
1180      addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1181                                   r_dst, am_addr, mode64 ));
1182      return r_dst;
1183      /*NOTREACHED*/
1184   }
1185
1186   /* --------- BINARY OP --------- */
1187   case Iex_Binop: {
1188      PPCAluOp  aluOp;
1189      PPCShftOp shftOp;
1190
1191      /* Is it an addition or logical style op? */
1192      switch (e->Iex.Binop.op) {
1193      case Iop_Add8: case Iop_Add16: case Iop_Add32: case Iop_Add64:
1194         aluOp = Palu_ADD; break;
1195      case Iop_Sub8: case Iop_Sub16: case Iop_Sub32: case Iop_Sub64:
1196         aluOp = Palu_SUB; break;
1197      case Iop_And8: case Iop_And16: case Iop_And32: case Iop_And64:
1198         aluOp = Palu_AND; break;
1199      case Iop_Or8:  case Iop_Or16:  case Iop_Or32:  case Iop_Or64:
1200         aluOp = Palu_OR; break;
1201      case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: case Iop_Xor64:
1202         aluOp = Palu_XOR; break;
1203      default:
1204         aluOp = Palu_INVALID; break;
1205      }
1206      /* For commutative ops we assume any literal
1207         values are on the second operand. */
1208      if (aluOp != Palu_INVALID) {
1209         HReg   r_dst   = newVRegI(env);
1210         HReg   r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1211         PPCRH* ri_srcR = NULL;
1212         /* get right arg into an RH, in the appropriate way */
1213         switch (aluOp) {
1214         case Palu_ADD: case Palu_SUB:
1215            ri_srcR = iselWordExpr_RH(env, True/*signed*/,
1216                                      e->Iex.Binop.arg2);
1217            break;
1218         case Palu_AND: case Palu_OR: case Palu_XOR:
1219            ri_srcR = iselWordExpr_RH(env, False/*signed*/,
1220                                      e->Iex.Binop.arg2);
1221            break;
1222         default:
1223            vpanic("iselWordExpr_R_wrk-aluOp-arg2");
1224         }
1225         addInstr(env, PPCInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
1226         return r_dst;
1227      }
1228
1229      /* a shift? */
1230      switch (e->Iex.Binop.op) {
1231      case Iop_Shl8: case Iop_Shl16: case Iop_Shl32: case Iop_Shl64:
1232         shftOp = Pshft_SHL; break;
1233      case Iop_Shr8: case Iop_Shr16: case Iop_Shr32: case Iop_Shr64:
1234         shftOp = Pshft_SHR; break;
1235      case Iop_Sar8: case Iop_Sar16: case Iop_Sar32: case Iop_Sar64:
1236         shftOp = Pshft_SAR; break;
1237      default:
1238         shftOp = Pshft_INVALID; break;
1239      }
1240      /* we assume any literal values are on the second operand. */
1241      if (shftOp != Pshft_INVALID) {
1242         HReg   r_dst   = newVRegI(env);
1243         HReg   r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1244         PPCRH* ri_srcR = NULL;
1245         /* get right arg into an RH, in the appropriate way */
1246         switch (shftOp) {
1247         case Pshft_SHL: case Pshft_SHR: case Pshft_SAR:
1248            if (!mode64)
1249               ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2);
1250            else
1251               ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
1252            break;
1253         default:
1254            vpanic("iselIntExpr_R_wrk-shftOp-arg2");
1255         }
1256         /* widen the left arg if needed */
1257         if (shftOp == Pshft_SHR || shftOp == Pshft_SAR) {
1258            if (ty == Ity_I8 || ty == Ity_I16) {
1259               PPCRH* amt = PPCRH_Imm(False,
1260                                      toUShort(ty == Ity_I8 ? 24 : 16));
1261               HReg   tmp = newVRegI(env);
1262               addInstr(env, PPCInstr_Shft(Pshft_SHL,
1263                                           True/*32bit shift*/,
1264                                           tmp, r_srcL, amt));
1265               addInstr(env, PPCInstr_Shft(shftOp,
1266                                           True/*32bit shift*/,
1267                                           tmp, tmp,    amt));
1268               r_srcL = tmp;
1269               vassert(0); /* AWAITING TEST CASE */
1270            }
1271         }
1272         /* Only 64 expressions need 64bit shifts,
1273            32bit shifts are fine for all others */
1274         if (ty == Ity_I64) {
1275            vassert(mode64);
1276            addInstr(env, PPCInstr_Shft(shftOp, False/*64bit shift*/,
1277                                        r_dst, r_srcL, ri_srcR));
1278         } else {
1279            addInstr(env, PPCInstr_Shft(shftOp, True/*32bit shift*/,
1280                                        r_dst, r_srcL, ri_srcR));
1281         }
1282         return r_dst;
1283      }
1284
1285      /* How about a div? */
1286      if (e->Iex.Binop.op == Iop_DivS32 ||
1287          e->Iex.Binop.op == Iop_DivU32 ||
1288          e->Iex.Binop.op == Iop_DivS32E ||
1289          e->Iex.Binop.op == Iop_DivU32E) {
1290         Bool syned  = toBool((e->Iex.Binop.op == Iop_DivS32) || (e->Iex.Binop.op == Iop_DivS32E));
1291         HReg r_dst  = newVRegI(env);
1292         HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1293         HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1294         addInstr( env,
1295                      PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivU32E )
1296                                             || ( e->Iex.Binop.op == Iop_DivS32E ) ) ? True
1297                                                                                     : False,
1298                                    syned,
1299                                    True/*32bit div*/,
1300                                    r_dst,
1301                                    r_srcL,
1302                                    r_srcR ) );
1303         return r_dst;
1304      }
1305      if (e->Iex.Binop.op == Iop_DivS64 ||
1306          e->Iex.Binop.op == Iop_DivU64 || e->Iex.Binop.op == Iop_DivS64E
1307          || e->Iex.Binop.op == Iop_DivU64E ) {
1308         Bool syned  = toBool((e->Iex.Binop.op == Iop_DivS64) ||(e->Iex.Binop.op == Iop_DivS64E));
1309         HReg r_dst  = newVRegI(env);
1310         HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1311         HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1312         vassert(mode64);
1313         addInstr( env,
1314                      PPCInstr_Div( ( ( e->Iex.Binop.op == Iop_DivS64E )
1315                                             || ( e->Iex.Binop.op
1316                                                      == Iop_DivU64E ) ) ? True
1317                                                                         : False,
1318                                    syned,
1319                                    False/*64bit div*/,
1320                                    r_dst,
1321                                    r_srcL,
1322                                    r_srcR ) );
1323         return r_dst;
1324      }
1325
1326      /* No? Anyone for a mul? */
1327      if (e->Iex.Binop.op == Iop_Mul32
1328          || e->Iex.Binop.op == Iop_Mul64) {
1329         Bool syned       = False;
1330         Bool sz32        = (e->Iex.Binop.op != Iop_Mul64);
1331         HReg r_dst       = newVRegI(env);
1332         HReg r_srcL      = iselWordExpr_R(env, e->Iex.Binop.arg1);
1333         HReg r_srcR      = iselWordExpr_R(env, e->Iex.Binop.arg2);
1334         addInstr(env, PPCInstr_MulL(syned, False/*lo32*/, sz32,
1335                                     r_dst, r_srcL, r_srcR));
1336         return r_dst;
1337      }
1338
1339      /* 32 x 32 -> 64 multiply */
1340      if (mode64
1341          && (e->Iex.Binop.op == Iop_MullU32
1342              || e->Iex.Binop.op == Iop_MullS32)) {
1343         HReg tLo    = newVRegI(env);
1344         HReg tHi    = newVRegI(env);
1345         HReg r_dst  = newVRegI(env);
1346         Bool syned  = toBool(e->Iex.Binop.op == Iop_MullS32);
1347         HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1348         HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1349         addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
1350                                     False/*lo32*/, True/*32bit mul*/,
1351                                     tLo, r_srcL, r_srcR));
1352         addInstr(env, PPCInstr_MulL(syned,
1353                                     True/*hi32*/, True/*32bit mul*/,
1354                                     tHi, r_srcL, r_srcR));
1355         addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1356                                     r_dst, tHi, PPCRH_Imm(False,32)));
1357         addInstr(env, PPCInstr_Alu(Palu_OR,
1358                                    r_dst, r_dst, PPCRH_Reg(tLo)));
1359         return r_dst;
1360      }
1361
1362      /* El-mutanto 3-way compare? */
1363      if (e->Iex.Binop.op == Iop_CmpORD32S
1364          || e->Iex.Binop.op == Iop_CmpORD32U) {
1365         Bool   syned = toBool(e->Iex.Binop.op == Iop_CmpORD32S);
1366         HReg   dst   = newVRegI(env);
1367         HReg   srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1368         PPCRH* srcR  = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
1369         addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
1370                                    7/*cr*/, srcL, srcR));
1371         addInstr(env, PPCInstr_MfCR(dst));
1372         addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1373                                    PPCRH_Imm(False,7<<1)));
1374         return dst;
1375      }
1376
1377      if (e->Iex.Binop.op == Iop_CmpORD64S
1378          || e->Iex.Binop.op == Iop_CmpORD64U) {
1379         Bool   syned = toBool(e->Iex.Binop.op == Iop_CmpORD64S);
1380         HReg   dst   = newVRegI(env);
1381         HReg   srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1382         PPCRH* srcR  = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
1383         vassert(mode64);
1384         addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
1385                                    7/*cr*/, srcL, srcR));
1386         addInstr(env, PPCInstr_MfCR(dst));
1387         addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1388                                    PPCRH_Imm(False,7<<1)));
1389         return dst;
1390      }
1391
1392      if (e->Iex.Binop.op == Iop_Max32U) {
1393         HReg        r1   = iselWordExpr_R(env, e->Iex.Binop.arg1);
1394         HReg        r2   = iselWordExpr_R(env, e->Iex.Binop.arg2);
1395         HReg        rdst = newVRegI(env);
1396         PPCCondCode cc   = mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
1397         addInstr(env, mk_iMOVds_RR(rdst, r1));
1398         addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1399                                    7/*cr*/, rdst, PPCRH_Reg(r2)));
1400         addInstr(env, PPCInstr_CMov(cc, rdst, PPCRI_Reg(r2)));
1401         return rdst;
1402      }
1403
1404      if (e->Iex.Binop.op == Iop_32HLto64) {
1405         HReg   r_Hi  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1406         HReg   r_Lo  = iselWordExpr_R(env, e->Iex.Binop.arg2);
1407         HReg   r_dst = newVRegI(env);
1408         HReg   msk   = newVRegI(env);
1409         vassert(mode64);
1410         /* r_dst = OR( r_Hi<<32, r_Lo ) */
1411         addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1412                                     r_dst, r_Hi, PPCRH_Imm(False,32)));
1413         addInstr(env, PPCInstr_LI(msk, 0xFFFFFFFF, mode64));
1414         addInstr(env, PPCInstr_Alu( Palu_AND, r_Lo, r_Lo,
1415                                     PPCRH_Reg(msk) ));
1416         addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst,
1417                                     PPCRH_Reg(r_Lo) ));
1418         return r_dst;
1419      }
1420
1421      if (e->Iex.Binop.op == Iop_CmpF64) {
1422         HReg fr_srcL    = iselDblExpr(env, e->Iex.Binop.arg1);
1423         HReg fr_srcR    = iselDblExpr(env, e->Iex.Binop.arg2);
1424
1425         HReg r_ccPPC   = newVRegI(env);
1426         HReg r_ccIR    = newVRegI(env);
1427         HReg r_ccIR_b0 = newVRegI(env);
1428         HReg r_ccIR_b2 = newVRegI(env);
1429         HReg r_ccIR_b6 = newVRegI(env);
1430
1431         addInstr(env, PPCInstr_FpCmp(r_ccPPC, fr_srcL, fr_srcR));
1432
1433         /* Map compare result from PPC to IR,
1434            conforming to CmpF64 definition. */
1435         /*
1436           FP cmp result | PPC | IR
1437           --------------------------
1438           UN            | 0x1 | 0x45
1439           EQ            | 0x2 | 0x40
1440           GT            | 0x4 | 0x00
1441           LT            | 0x8 | 0x01
1442         */
1443
1444         // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1445         addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1446                                     r_ccIR_b0, r_ccPPC,
1447                                     PPCRH_Imm(False,0x3)));
1448         addInstr(env, PPCInstr_Alu(Palu_OR,  r_ccIR_b0,
1449                                    r_ccPPC,   PPCRH_Reg(r_ccIR_b0)));
1450         addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b0,
1451                                    r_ccIR_b0, PPCRH_Imm(False,0x1)));
1452
1453         // r_ccIR_b2 = r_ccPPC[0]
1454         addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1455                                     r_ccIR_b2, r_ccPPC,
1456                                     PPCRH_Imm(False,0x2)));
1457         addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b2,
1458                                    r_ccIR_b2, PPCRH_Imm(False,0x4)));
1459
1460         // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
1461         addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1462                                     r_ccIR_b6, r_ccPPC,
1463                                     PPCRH_Imm(False,0x1)));
1464         addInstr(env, PPCInstr_Alu(Palu_OR,  r_ccIR_b6,
1465                                    r_ccPPC, PPCRH_Reg(r_ccIR_b6)));
1466         addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1467                                     r_ccIR_b6, r_ccIR_b6,
1468                                     PPCRH_Imm(False,0x6)));
1469         addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b6,
1470                                    r_ccIR_b6, PPCRH_Imm(False,0x40)));
1471
1472         // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
1473         addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1474                                    r_ccIR_b0, PPCRH_Reg(r_ccIR_b2)));
1475         addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1476                                    r_ccIR,    PPCRH_Reg(r_ccIR_b6)));
1477         return r_ccIR;
1478      }
1479
1480      if ( e->Iex.Binop.op == Iop_F64toI32S ||
1481               e->Iex.Binop.op == Iop_F64toI32U ) {
1482         /* This works in both mode64 and mode32. */
1483         HReg      r1      = StackFramePtr(env->mode64);
1484         PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1485         HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2);
1486         HReg      ftmp    = newVRegF(env);
1487         HReg      idst    = newVRegI(env);
1488
1489         /* Set host rounding mode */
1490         set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
1491
1492         sub_from_sp( env, 16 );
1493         addInstr(env, PPCInstr_FpCftI(False/*F->I*/, True/*int32*/,
1494                                       e->Iex.Binop.op == Iop_F64toI32S ? True/*syned*/
1495                                                                     : False,
1496                                       True/*flt64*/,
1497                                       ftmp, fsrc));
1498         addInstr(env, PPCInstr_FpSTFIW(r1, ftmp));
1499         addInstr(env, PPCInstr_Load(4, idst, zero_r1, mode64));
1500
1501         /* in 64-bit mode we need to sign-widen idst. */
1502         if (mode64)
1503            addInstr(env, PPCInstr_Unary(Pun_EXTSW, idst, idst));
1504
1505         add_to_sp( env, 16 );
1506
1507         ///* Restore default FPU rounding. */
1508         //set_FPU_rounding_default( env );
1509         return idst;
1510      }
1511
1512      if (e->Iex.Binop.op == Iop_F64toI64S || e->Iex.Binop.op == Iop_F64toI64U ) {
1513         if (mode64) {
1514            HReg      r1      = StackFramePtr(env->mode64);
1515            PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1516            HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2);
1517            HReg      idst    = newVRegI(env);
1518            HReg      ftmp    = newVRegF(env);
1519
1520            /* Set host rounding mode */
1521            set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
1522
1523            sub_from_sp( env, 16 );
1524            addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
1525                                          ( e->Iex.Binop.op == Iop_F64toI64S ) ? True
1526                                                                            : False,
1527                                          True, ftmp, fsrc));
1528            addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1529            addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1530            add_to_sp( env, 16 );
1531
1532            ///* Restore default FPU rounding. */
1533            //set_FPU_rounding_default( env );
1534            return idst;
1535         }
1536      }
1537
1538      break;
1539   }
1540
1541   /* --------- UNARY OP --------- */
1542   case Iex_Unop: {
1543      IROp op_unop = e->Iex.Unop.op;
1544
1545      /* 1Uto8(32to1(expr32)) */
1546      DEFINE_PATTERN(p_32to1_then_1Uto8,
1547                     unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1548      if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1549         IRExpr* expr32 = mi.bindee[0];
1550         HReg r_dst = newVRegI(env);
1551         HReg r_src = iselWordExpr_R(env, expr32);
1552         addInstr(env, PPCInstr_Alu(Palu_AND, r_dst,
1553                                    r_src, PPCRH_Imm(False,1)));
1554         return r_dst;
1555      }
1556
1557      /* 16Uto32(LDbe:I16(expr32)) */
1558      {
1559         DECLARE_PATTERN(p_LDbe16_then_16Uto32);
1560         DEFINE_PATTERN(p_LDbe16_then_16Uto32,
1561                        unop(Iop_16Uto32,
1562                             IRExpr_Load(Iend_BE,Ity_I16,bind(0))) );
1563         if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
1564            HReg r_dst = newVRegI(env);
1565            PPCAMode* amode
1566               = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/ );
1567            addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
1568            return r_dst;
1569         }
1570      }
1571
1572      switch (op_unop) {
1573      case Iop_8Uto16:
1574      case Iop_8Uto32:
1575      case Iop_8Uto64:
1576      case Iop_16Uto32:
1577      case Iop_16Uto64: {
1578         HReg   r_dst = newVRegI(env);
1579         HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1580         UShort mask  = toUShort(op_unop==Iop_16Uto64 ? 0xFFFF :
1581                                 op_unop==Iop_16Uto32 ? 0xFFFF : 0xFF);
1582         addInstr(env, PPCInstr_Alu(Palu_AND,r_dst,r_src,
1583                                    PPCRH_Imm(False,mask)));
1584         return r_dst;
1585      }
1586      case Iop_32Uto64: {
1587         HReg r_dst = newVRegI(env);
1588         HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1589         vassert(mode64);
1590         addInstr(env,
1591                  PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1592                                r_dst, r_src, PPCRH_Imm(False,32)));
1593         addInstr(env,
1594                  PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1595                                r_dst, r_dst, PPCRH_Imm(False,32)));
1596         return r_dst;
1597      }
1598      case Iop_8Sto16:
1599      case Iop_8Sto32:
1600      case Iop_16Sto32: {
1601         HReg   r_dst = newVRegI(env);
1602         HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1603         UShort amt   = toUShort(op_unop==Iop_16Sto32 ? 16 : 24);
1604         addInstr(env,
1605                  PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1606                                r_dst, r_src, PPCRH_Imm(False,amt)));
1607         addInstr(env,
1608                  PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1609                                r_dst, r_dst, PPCRH_Imm(False,amt)));
1610         return r_dst;
1611      }
1612      case Iop_8Sto64:
1613      case Iop_16Sto64: {
1614         HReg   r_dst = newVRegI(env);
1615         HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1616         UShort amt   = toUShort(op_unop==Iop_8Sto64  ? 56 : 48);
1617         vassert(mode64);
1618         addInstr(env,
1619                  PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1620                                r_dst, r_src, PPCRH_Imm(False,amt)));
1621         addInstr(env,
1622                  PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1623                                r_dst, r_dst, PPCRH_Imm(False,amt)));
1624         return r_dst;
1625      }
1626      case Iop_32Sto64: {
1627         HReg   r_dst = newVRegI(env);
1628         HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1629	 vassert(mode64);
1630         /* According to the IBM docs, in 64 bit mode, srawi r,r,0
1631            sign extends the lower 32 bits into the upper 32 bits. */
1632         addInstr(env,
1633                  PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1634                                r_dst, r_src, PPCRH_Imm(False,0)));
1635         return r_dst;
1636      }
1637      case Iop_Not8:
1638      case Iop_Not16:
1639      case Iop_Not32:
1640      case Iop_Not64: {
1641         if (op_unop == Iop_Not64) vassert(mode64);
1642         HReg r_dst = newVRegI(env);
1643         HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1644         addInstr(env, PPCInstr_Unary(Pun_NOT,r_dst,r_src));
1645         return r_dst;
1646      }
1647      case Iop_64HIto32: {
1648         if (!mode64) {
1649            HReg rHi, rLo;
1650            iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1651            return rHi; /* and abandon rLo .. poor wee thing :-) */
1652         } else {
1653            HReg   r_dst = newVRegI(env);
1654            HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1655            addInstr(env,
1656                     PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1657                                   r_dst, r_src, PPCRH_Imm(False,32)));
1658            return r_dst;
1659         }
1660      }
1661      case Iop_64to32: {
1662         if (!mode64) {
1663            HReg rHi, rLo;
1664            iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1665            return rLo; /* similar stupid comment to the above ... */
1666         } else {
1667            /* This is a no-op. */
1668            return iselWordExpr_R(env, e->Iex.Unop.arg);
1669         }
1670      }
1671      case Iop_64to16: {
1672         if (mode64) { /* This is a no-op. */
1673            return iselWordExpr_R(env, e->Iex.Unop.arg);
1674         }
1675         break; /* evidently not used in 32-bit mode */
1676      }
1677      case Iop_16HIto8:
1678      case Iop_32HIto16: {
1679         HReg   r_dst = newVRegI(env);
1680         HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1681         UShort shift = toUShort(op_unop == Iop_16HIto8 ? 8 : 16);
1682         addInstr(env,
1683                  PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1684                                r_dst, r_src, PPCRH_Imm(False,shift)));
1685         return r_dst;
1686      }
1687      case Iop_128HIto64:
1688         if (mode64) {
1689            HReg rHi, rLo;
1690            iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1691            return rHi; /* and abandon rLo .. poor wee thing :-) */
1692         }
1693         break;
1694      case Iop_128to64:
1695         if (mode64) {
1696            HReg rHi, rLo;
1697            iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1698            return rLo; /* similar stupid comment to the above ... */
1699         }
1700         break;
1701      case Iop_1Uto32:
1702      case Iop_1Uto8: {
1703         HReg        r_dst = newVRegI(env);
1704         PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg);
1705         addInstr(env, PPCInstr_Set(cond,r_dst));
1706         return r_dst;
1707      }
1708      case Iop_1Sto8:
1709      case Iop_1Sto16:
1710      case Iop_1Sto32: {
1711         /* could do better than this, but for now ... */
1712         HReg        r_dst = newVRegI(env);
1713         PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg);
1714         addInstr(env, PPCInstr_Set(cond,r_dst));
1715         addInstr(env,
1716                  PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1717                                r_dst, r_dst, PPCRH_Imm(False,31)));
1718         addInstr(env,
1719                  PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1720                                r_dst, r_dst, PPCRH_Imm(False,31)));
1721         return r_dst;
1722      }
1723      case Iop_1Sto64:
1724         if (mode64) {
1725            /* could do better than this, but for now ... */
1726            HReg        r_dst = newVRegI(env);
1727            PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg);
1728            addInstr(env, PPCInstr_Set(cond,r_dst));
1729            addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1730                                        r_dst, r_dst, PPCRH_Imm(False,63)));
1731            addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1732                                        r_dst, r_dst, PPCRH_Imm(False,63)));
1733            return r_dst;
1734         }
1735         break;
1736      case Iop_Clz32:
1737      case Iop_Clz64: {
1738         HReg r_src, r_dst;
1739         PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 :
1740                                                      Pun_CLZ64;
1741         if (op_unop == Iop_Clz64 && !mode64)
1742            goto irreducible;
1743         /* Count leading zeroes. */
1744         r_dst = newVRegI(env);
1745         r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1746         addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
1747         return r_dst;
1748      }
1749
1750      case Iop_Left8:
1751      case Iop_Left32:
1752      case Iop_Left64: {
1753         HReg r_src, r_dst;
1754         if (op_unop == Iop_Left64 && !mode64)
1755            goto irreducible;
1756         r_dst = newVRegI(env);
1757         r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1758         addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1759         addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1760         return r_dst;
1761      }
1762
1763      case Iop_CmpwNEZ32: {
1764         HReg r_dst = newVRegI(env);
1765         HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1766         addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1767         addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1768         addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1769                                     r_dst, r_dst, PPCRH_Imm(False, 31)));
1770         return r_dst;
1771      }
1772
1773      case Iop_CmpwNEZ64: {
1774         HReg r_dst = newVRegI(env);
1775         HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1776         if (!mode64) goto irreducible;
1777         addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1778         addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1779         addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1780                                     r_dst, r_dst, PPCRH_Imm(False, 63)));
1781         return r_dst;
1782      }
1783
1784      case Iop_V128to32: {
1785         HReg        r_aligned16;
1786         HReg        dst  = newVRegI(env);
1787         HReg        vec  = iselVecExpr(env, e->Iex.Unop.arg);
1788         PPCAMode *am_off0, *am_off12;
1789         sub_from_sp( env, 32 );     // Move SP down 32 bytes
1790
1791         // get a quadword aligned address within our stack space
1792         r_aligned16 = get_sp_aligned16( env );
1793         am_off0  = PPCAMode_IR( 0, r_aligned16 );
1794         am_off12 = PPCAMode_IR( 12,r_aligned16 );
1795
1796         // store vec, load low word to dst
1797         addInstr(env,
1798                  PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
1799         addInstr(env,
1800                  PPCInstr_Load( 4, dst, am_off12, mode64 ));
1801
1802         add_to_sp( env, 32 );       // Reset SP
1803         return dst;
1804      }
1805
1806      case Iop_V128to64:
1807      case Iop_V128HIto64:
1808         if (mode64) {
1809            HReg     r_aligned16;
1810            HReg     dst = newVRegI(env);
1811            HReg     vec = iselVecExpr(env, e->Iex.Unop.arg);
1812            PPCAMode *am_off0, *am_off8;
1813            sub_from_sp( env, 32 );     // Move SP down 32 bytes
1814
1815            // get a quadword aligned address within our stack space
1816            r_aligned16 = get_sp_aligned16( env );
1817            am_off0 = PPCAMode_IR( 0, r_aligned16 );
1818            am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
1819
1820            // store vec, load low word (+8) or high (+0) to dst
1821            addInstr(env,
1822                     PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
1823            addInstr(env,
1824                     PPCInstr_Load(
1825                        8, dst,
1826                        op_unop == Iop_V128HIto64 ? am_off0 : am_off8,
1827                        mode64 ));
1828
1829            add_to_sp( env, 32 );       // Reset SP
1830            return dst;
1831         }
1832         break;
1833      case Iop_16to8:
1834      case Iop_32to8:
1835      case Iop_32to16:
1836      case Iop_64to8:
1837         /* These are no-ops. */
1838         return iselWordExpr_R(env, e->Iex.Unop.arg);
1839
1840      /* ReinterpF64asI64(e) */
1841      /* Given an IEEE754 double, produce an I64 with the same bit
1842         pattern. */
1843      case Iop_ReinterpF64asI64:
1844         if (mode64) {
1845            PPCAMode *am_addr;
1846            HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
1847            HReg r_dst  = newVRegI(env);
1848
1849            sub_from_sp( env, 16 );     // Move SP down 16 bytes
1850            am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
1851
1852            // store as F64
1853            addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
1854                                           fr_src, am_addr ));
1855            // load as Ity_I64
1856            addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
1857
1858            add_to_sp( env, 16 );       // Reset SP
1859            return r_dst;
1860         }
1861         break;
1862
1863      /* ReinterpF32asI32(e) */
1864      /* Given an IEEE754 float, produce an I32 with the same bit
1865         pattern. */
1866      case Iop_ReinterpF32asI32: {
1867         /* I believe this generates correct code for both 32- and
1868            64-bit hosts. */
1869         PPCAMode *am_addr;
1870         HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1871         HReg r_dst  = newVRegI(env);
1872
1873         sub_from_sp( env, 16 );     // Move SP down 16 bytes
1874         am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
1875
1876         // store as F32
1877         addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
1878                                        fr_src, am_addr ));
1879         // load as Ity_I32
1880         addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
1881
1882         add_to_sp( env, 16 );       // Reset SP
1883         return r_dst;
1884      }
1885
1886      default:
1887         break;
1888      }
1889      break;
1890   }
1891
1892   /* --------- GET --------- */
1893   case Iex_Get: {
1894      if (ty == Ity_I8  || ty == Ity_I16 ||
1895          ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
1896         HReg r_dst = newVRegI(env);
1897         PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
1898                                          GuestStatePtr(mode64) );
1899         addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)),
1900                                      r_dst, am_addr, mode64 ));
1901         return r_dst;
1902      }
1903      break;
1904   }
1905
1906   case Iex_GetI: {
1907      PPCAMode* src_am
1908         = genGuestArrayOffset( env, e->Iex.GetI.descr,
1909                                     e->Iex.GetI.ix, e->Iex.GetI.bias );
1910      HReg r_dst = newVRegI(env);
1911      if (mode64 && ty == Ity_I64) {
1912         addInstr(env, PPCInstr_Load( toUChar(8),
1913                                      r_dst, src_am, mode64 ));
1914         return r_dst;
1915      }
1916      if ((!mode64) && ty == Ity_I32) {
1917         addInstr(env, PPCInstr_Load( toUChar(4),
1918                                      r_dst, src_am, mode64 ));
1919         return r_dst;
1920      }
1921      break;
1922   }
1923
1924   /* --------- CCALL --------- */
1925   case Iex_CCall: {
1926      HReg    r_dst = newVRegI(env);
1927      vassert(ty == Ity_I32);
1928
1929      /* be very restrictive for now.  Only 32/64-bit ints allowed
1930         for args, and 32 bits for return type. */
1931      if (e->Iex.CCall.retty != Ity_I32)
1932         goto irreducible;
1933
1934      /* Marshal args, do the call, clear stack. */
1935      doHelperCall( env, False, NULL,
1936                    e->Iex.CCall.cee, e->Iex.CCall.args );
1937
1938      /* GPR3 now holds the destination address from Pin_Goto */
1939      addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
1940      return r_dst;
1941   }
1942
1943   /* --------- LITERAL --------- */
1944   /* 32/16/8-bit literals */
1945   case Iex_Const: {
1946      Long l;
1947      HReg r_dst = newVRegI(env);
1948      IRConst* con = e->Iex.Const.con;
1949      switch (con->tag) {
1950         case Ico_U64: if (!mode64) goto irreducible;
1951                       l = (Long)            con->Ico.U64; break;
1952         case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
1953         case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
1954         case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
1955         default:      vpanic("iselIntExpr_R.const(ppc)");
1956      }
1957      addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64));
1958      return r_dst;
1959   }
1960
1961   /* --------- MULTIPLEX --------- */
1962   case Iex_Mux0X: {
1963      if ((ty == Ity_I8  || ty == Ity_I16 ||
1964           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) &&
1965          typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1966         PPCCondCode  cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
1967         HReg   r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
1968         HReg   rX     = iselWordExpr_R(env, e->Iex.Mux0X.exprX);
1969         PPCRI* r0     = iselWordExpr_RI(env, e->Iex.Mux0X.expr0);
1970         HReg   r_dst  = newVRegI(env);
1971         HReg   r_tmp  = newVRegI(env);
1972         addInstr(env, mk_iMOVds_RR(r_dst,rX));
1973         addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp,
1974                                    r_cond, PPCRH_Imm(False,0xFF)));
1975         addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1976                                    7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
1977         addInstr(env, PPCInstr_CMov(cc,r_dst,r0));
1978         return r_dst;
1979      }
1980      break;
1981   }
1982
1983   default:
1984      break;
1985   } /* switch (e->tag) */
1986
1987
1988   /* We get here if no pattern matched. */
1989 irreducible:
1990   ppIRExpr(e);
1991   vpanic("iselIntExpr_R(ppc): cannot reduce tree");
1992}
1993
1994
1995/*---------------------------------------------------------*/
1996/*--- ISEL: Integer expression auxiliaries              ---*/
1997/*---------------------------------------------------------*/
1998
1999/* --------------------- AMODEs --------------------- */
2000
2001/* Return an AMode which computes the value of the specified
2002   expression, possibly also adding insns to the code list as a
2003   result.  The expression may only be a word-size one.
2004*/
2005
2006static Bool uInt_fits_in_16_bits ( UInt u )
2007{
2008   /* Is u the same as the sign-extend of its lower 16 bits? */
2009   Int i = u & 0xFFFF;
2010   i <<= 16;
2011   i >>= 16;
2012   return toBool(u == (UInt)i);
2013}
2014
2015static Bool uLong_fits_in_16_bits ( ULong u )
2016{
2017   /* Is u the same as the sign-extend of its lower 16 bits? */
2018   Long i = u & 0xFFFFULL;
2019   i <<= 48;
2020   i >>= 48;
2021   return toBool(u == (ULong)i);
2022}
2023
2024static Bool uLong_is_4_aligned ( ULong u )
2025{
2026   return toBool((u & 3ULL) == 0);
2027}
2028
2029static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2030{
2031   Bool mode64 = env->mode64;
2032   switch (am->tag) {
2033   case Pam_IR:
2034      /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2035         somehow, but I think it's OK. */
2036      return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) &&
2037                     hregIsVirtual(am->Pam.IR.base) &&
2038                     uInt_fits_in_16_bits(am->Pam.IR.index) );
2039   case Pam_RR:
2040      return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) &&
2041                     hregIsVirtual(am->Pam.RR.base) &&
2042                     hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2043                     hregIsVirtual(am->Pam.IR.index) );
2044   default:
2045      vpanic("sane_AMode: unknown ppc amode tag");
2046   }
2047}
2048
2049static
2050PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy )
2051{
2052   PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy);
2053   vassert(sane_AMode(env, am));
2054   return am;
2055}
2056
2057/* DO NOT CALL THIS DIRECTLY ! */
2058static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy )
2059{
2060   IRType ty = typeOfIRExpr(env->type_env,e);
2061
2062   if (env->mode64) {
2063
2064      /* If the data load/store type is I32 or I64, this amode might
2065         be destined for use in ld/ldu/lwa/st/stu.  In which case
2066         insist that if it comes out as an _IR, the immediate must
2067         have its bottom two bits be zero.  This does assume that for
2068         any other type (I8/I16/I128/F32/F64/V128) the amode will not
2069         be parked in any such instruction.  But that seems a
2070         reasonable assumption.  */
2071      Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2072
2073      vassert(ty == Ity_I64);
2074
2075      /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2076      if (e->tag == Iex_Binop
2077          && e->Iex.Binop.op == Iop_Add64
2078          && e->Iex.Binop.arg2->tag == Iex_Const
2079          && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2080          && (aligned4imm  ? uLong_is_4_aligned(e->Iex.Binop.arg2
2081                                                 ->Iex.Const.con->Ico.U64)
2082                           : True)
2083          && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2084                                    ->Iex.Const.con->Ico.U64)) {
2085         return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2086                             iselWordExpr_R(env, e->Iex.Binop.arg1) );
2087      }
2088
2089      /* Add64(expr,expr) */
2090      if (e->tag == Iex_Binop
2091          && e->Iex.Binop.op == Iop_Add64) {
2092         HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
2093         HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2094         return PPCAMode_RR( r_idx, r_base );
2095      }
2096
2097   } else {
2098
2099      vassert(ty == Ity_I32);
2100
2101      /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2102      if (e->tag == Iex_Binop
2103          && e->Iex.Binop.op == Iop_Add32
2104          && e->Iex.Binop.arg2->tag == Iex_Const
2105          && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2106          && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2107                                   ->Iex.Const.con->Ico.U32)) {
2108         return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2109                             iselWordExpr_R(env, e->Iex.Binop.arg1) );
2110      }
2111
2112      /* Add32(expr,expr) */
2113      if (e->tag == Iex_Binop
2114          && e->Iex.Binop.op == Iop_Add32) {
2115         HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
2116         HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2117         return PPCAMode_RR( r_idx, r_base );
2118      }
2119
2120   }
2121
2122   /* Doesn't match anything in particular.  Generate it into
2123      a register and use that. */
2124   return PPCAMode_IR( 0, iselWordExpr_R(env,e) );
2125}
2126
2127
2128/* --------------------- RH --------------------- */
2129
2130/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2131   (reg-or-halfword-immediate).  It's important to specify whether the
2132   immediate is to be regarded as signed or not.  If yes, this will
2133   never return -32768 as an immediate; this guaranteed that all
2134   signed immediates that are return can have their sign inverted if
2135   need be. */
2136
2137static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e )
2138{
2139   PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e);
2140   /* sanity checks ... */
2141   switch (ri->tag) {
2142   case Prh_Imm:
2143      vassert(ri->Prh.Imm.syned == syned);
2144      if (syned)
2145         vassert(ri->Prh.Imm.imm16 != 0x8000);
2146      return ri;
2147   case Prh_Reg:
2148      vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2149      vassert(hregIsVirtual(ri->Prh.Reg.reg));
2150      return ri;
2151   default:
2152      vpanic("iselIntExpr_RH: unknown ppc RH tag");
2153   }
2154}
2155
2156/* DO NOT CALL THIS DIRECTLY ! */
2157static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e )
2158{
2159   ULong u;
2160   Long  l;
2161   IRType ty = typeOfIRExpr(env->type_env,e);
2162   vassert(ty == Ity_I8  || ty == Ity_I16 ||
2163           ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2164
2165   /* special case: immediate */
2166   if (e->tag == Iex_Const) {
2167      IRConst* con = e->Iex.Const.con;
2168      /* What value are we aiming to generate? */
2169      switch (con->tag) {
2170      /* Note: Not sign-extending - we carry 'syned' around */
2171      case Ico_U64: vassert(env->mode64);
2172                    u =              con->Ico.U64; break;
2173      case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2174      case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2175      case Ico_U8:  u = 0x000000FF & con->Ico.U8; break;
2176      default:      vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2177      }
2178      l = (Long)u;
2179      /* Now figure out if it's representable. */
2180      if (!syned && u <= 65535) {
2181         return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2182      }
2183      if (syned && l >= -32767 && l <= 32767) {
2184         return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2185      }
2186      /* no luck; use the Slow Way. */
2187   }
2188
2189   /* default case: calculate into a register and return that */
2190   return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2191}
2192
2193
2194/* --------------------- RIs --------------------- */
2195
2196/* Calculate an expression into an PPCRI operand.  As with
2197   iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2198   in 64-bit mode, 64 bits. */
2199
2200static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e )
2201{
2202   PPCRI* ri = iselWordExpr_RI_wrk(env, e);
2203   /* sanity checks ... */
2204   switch (ri->tag) {
2205   case Pri_Imm:
2206      return ri;
2207   case Pri_Reg:
2208      vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2209      vassert(hregIsVirtual(ri->Pri.Reg));
2210      return ri;
2211   default:
2212      vpanic("iselIntExpr_RI: unknown ppc RI tag");
2213   }
2214}
2215
2216/* DO NOT CALL THIS DIRECTLY ! */
2217static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
2218{
2219   Long  l;
2220   IRType ty = typeOfIRExpr(env->type_env,e);
2221   vassert(ty == Ity_I8  || ty == Ity_I16 ||
2222           ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2223
2224   /* special case: immediate */
2225   if (e->tag == Iex_Const) {
2226      IRConst* con = e->Iex.Const.con;
2227      switch (con->tag) {
2228      case Ico_U64: vassert(env->mode64);
2229                    l = (Long)            con->Ico.U64; break;
2230      case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
2231      case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2232      case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
2233      default:      vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2234      }
2235      return PPCRI_Imm((ULong)l);
2236   }
2237
2238   /* default case: calculate into a register and return that */
2239   return PPCRI_Reg( iselWordExpr_R ( env, e ) );
2240}
2241
2242
2243/* --------------------- RH5u --------------------- */
2244
2245/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2246   being an immediate in the range 1 .. 31 inclusive.  Used for doing
2247   shift amounts.  Only used in 32-bit mode. */
2248
2249static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e )
2250{
2251   PPCRH* ri;
2252   vassert(!env->mode64);
2253   ri = iselWordExpr_RH5u_wrk(env, e);
2254   /* sanity checks ... */
2255   switch (ri->tag) {
2256   case Prh_Imm:
2257      vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2258      vassert(!ri->Prh.Imm.syned);
2259      return ri;
2260   case Prh_Reg:
2261      vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2262      vassert(hregIsVirtual(ri->Prh.Reg.reg));
2263      return ri;
2264   default:
2265      vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2266   }
2267}
2268
2269/* DO NOT CALL THIS DIRECTLY ! */
2270static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e )
2271{
2272   IRType ty = typeOfIRExpr(env->type_env,e);
2273   vassert(ty == Ity_I8);
2274
2275   /* special case: immediate */
2276   if (e->tag == Iex_Const
2277       && e->Iex.Const.con->tag == Ico_U8
2278       && e->Iex.Const.con->Ico.U8 >= 1
2279       && e->Iex.Const.con->Ico.U8 <= 31) {
2280      return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2281   }
2282
2283   /* default case: calculate into a register and return that */
2284   return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2285}
2286
2287
2288/* --------------------- RH6u --------------------- */
2289
2290/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2291   being an immediate in the range 1 .. 63 inclusive.  Used for doing
2292   shift amounts.  Only used in 64-bit mode. */
2293
2294static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e )
2295{
2296   PPCRH* ri;
2297   vassert(env->mode64);
2298   ri = iselWordExpr_RH6u_wrk(env, e);
2299   /* sanity checks ... */
2300   switch (ri->tag) {
2301   case Prh_Imm:
2302      vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2303      vassert(!ri->Prh.Imm.syned);
2304      return ri;
2305   case Prh_Reg:
2306      vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2307      vassert(hregIsVirtual(ri->Prh.Reg.reg));
2308      return ri;
2309   default:
2310      vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2311   }
2312}
2313
2314/* DO NOT CALL THIS DIRECTLY ! */
2315static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e )
2316{
2317   IRType ty = typeOfIRExpr(env->type_env,e);
2318   vassert(ty == Ity_I8);
2319
2320   /* special case: immediate */
2321   if (e->tag == Iex_Const
2322       && e->Iex.Const.con->tag == Ico_U8
2323       && e->Iex.Const.con->Ico.U8 >= 1
2324       && e->Iex.Const.con->Ico.U8 <= 63) {
2325      return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2326   }
2327
2328   /* default case: calculate into a register and return that */
2329   return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2330}
2331
2332
2333/* --------------------- CONDCODE --------------------- */
2334
2335/* Generate code to evaluated a bit-typed expression, returning the
2336   condition code which would correspond when the expression would
2337   notionally have returned 1. */
2338
2339static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
2340{
2341   /* Uh, there's nothing we can sanity check here, unfortunately. */
2342   return iselCondCode_wrk(env,e);
2343}
2344
2345/* DO NOT CALL THIS DIRECTLY ! */
2346static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
2347{
2348   vassert(e);
2349   vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2350
2351   /* Constant 1:Bit */
2352   if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2353      // Make a compare that will always be true:
2354      HReg r_zero = newVRegI(env);
2355      addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2356      addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2357                                 7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2358      return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2359   }
2360
2361   /* Not1(...) */
2362   if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2363      /* Generate code for the arg, and negate the test condition */
2364      PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2365      cond.test = invertCondTest(cond.test);
2366      return cond;
2367   }
2368
2369   /* --- patterns rooted at: 32to1 or 64to1 --- */
2370
2371   /* 32to1, 64to1 */
2372   if (e->tag == Iex_Unop &&
2373       (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2374      HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2375      HReg tmp = newVRegI(env);
2376      /* could do better, probably -- andi. */
2377      addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2378                                 src, PPCRH_Imm(False,1)));
2379      addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2380                                 7/*cr*/, tmp, PPCRH_Imm(False,1)));
2381      return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2382   }
2383
2384   /* --- patterns rooted at: CmpNEZ8 --- */
2385
2386   /* CmpNEZ8(x) */
2387   /* could do better -- andi. */
2388   if (e->tag == Iex_Unop
2389       && e->Iex.Unop.op == Iop_CmpNEZ8) {
2390      HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg);
2391      HReg tmp = newVRegI(env);
2392      addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2393                                 PPCRH_Imm(False,0xFF)));
2394      addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2395                                 7/*cr*/, tmp, PPCRH_Imm(False,0)));
2396      return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2397   }
2398
2399   /* --- patterns rooted at: CmpNEZ32 --- */
2400
2401   /* CmpNEZ32(x) */
2402   if (e->tag == Iex_Unop
2403       && e->Iex.Unop.op == Iop_CmpNEZ32) {
2404      HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg);
2405      addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2406                                 7/*cr*/, r1, PPCRH_Imm(False,0)));
2407      return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2408   }
2409
2410   /* --- patterns rooted at: Cmp*32* --- */
2411
2412   /* Cmp*32*(x,y) */
2413   if (e->tag == Iex_Binop
2414       && (e->Iex.Binop.op == Iop_CmpEQ32
2415           || e->Iex.Binop.op == Iop_CmpNE32
2416           || e->Iex.Binop.op == Iop_CmpLT32S
2417           || e->Iex.Binop.op == Iop_CmpLT32U
2418           || e->Iex.Binop.op == Iop_CmpLE32S
2419           || e->Iex.Binop.op == Iop_CmpLE32U)) {
2420      Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2421                    e->Iex.Binop.op == Iop_CmpLE32S);
2422      HReg   r1  = iselWordExpr_R(env, e->Iex.Binop.arg1);
2423      PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
2424      addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2425                                 7/*cr*/, r1, ri2));
2426
2427      switch (e->Iex.Binop.op) {
2428      case Iop_CmpEQ32:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2429      case Iop_CmpNE32:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2430      case Iop_CmpLT32U: case Iop_CmpLT32S:
2431         return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2432      case Iop_CmpLE32U: case Iop_CmpLE32S:
2433         return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2434      default: vpanic("iselCondCode(ppc): CmpXX32");
2435      }
2436   }
2437
2438   /* --- patterns rooted at: CmpNEZ64 --- */
2439
2440   /* CmpNEZ64 */
2441   if (e->tag == Iex_Unop
2442       && e->Iex.Unop.op == Iop_CmpNEZ64) {
2443      if (!env->mode64) {
2444         HReg hi, lo;
2445         HReg tmp = newVRegI(env);
2446         iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg );
2447         addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2448         addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2449                                    7/*cr*/, tmp,PPCRH_Imm(False,0)));
2450         return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2451      } else {  // mode64
2452         HReg r_src = iselWordExpr_R(env, e->Iex.Binop.arg1);
2453         addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2454                                    7/*cr*/, r_src,PPCRH_Imm(False,0)));
2455         return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2456      }
2457   }
2458
2459   /* --- patterns rooted at: Cmp*64* --- */
2460
2461   /* Cmp*64*(x,y) */
2462   if (e->tag == Iex_Binop
2463       && (e->Iex.Binop.op == Iop_CmpEQ64
2464           || e->Iex.Binop.op == Iop_CmpNE64
2465           || e->Iex.Binop.op == Iop_CmpLT64S
2466           || e->Iex.Binop.op == Iop_CmpLT64U
2467           || e->Iex.Binop.op == Iop_CmpLE64S
2468           || e->Iex.Binop.op == Iop_CmpLE64U)) {
2469      Bool   syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2470                      e->Iex.Binop.op == Iop_CmpLE64S);
2471      HReg    r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2472      PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
2473      vassert(env->mode64);
2474      addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2475                                 7/*cr*/, r1, ri2));
2476
2477      switch (e->Iex.Binop.op) {
2478      case Iop_CmpEQ64:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2479      case Iop_CmpNE64:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2480      case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2481      case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2482      default: vpanic("iselCondCode(ppc): CmpXX64");
2483      }
2484   }
2485
2486   /* var */
2487   if (e->tag == Iex_RdTmp) {
2488      HReg r_src      = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2489      HReg src_masked = newVRegI(env);
2490      addInstr(env,
2491               PPCInstr_Alu(Palu_AND, src_masked,
2492                            r_src, PPCRH_Imm(False,1)));
2493      addInstr(env,
2494               PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2495                            7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2496      return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2497   }
2498
2499   vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
2500   ppIRExpr(e);
2501   vpanic("iselCondCode(ppc)");
2502}
2503
2504
2505/*---------------------------------------------------------*/
2506/*--- ISEL: Integer expressions (128 bit)               ---*/
2507/*---------------------------------------------------------*/
2508
2509/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
2510   which is returned as the first two parameters.  As with
2511   iselWordExpr_R, these may be either real or virtual regs; in any
2512   case they must not be changed by subsequent code emitted by the
2513   caller.  */
2514
2515static void iselInt128Expr ( HReg* rHi, HReg* rLo,
2516                             ISelEnv* env, IRExpr* e )
2517{
2518   vassert(env->mode64);
2519   iselInt128Expr_wrk(rHi, rLo, env, e);
2520#  if 0
2521   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2522#  endif
2523   vassert(hregClass(*rHi) == HRcGPR(env->mode64));
2524   vassert(hregIsVirtual(*rHi));
2525   vassert(hregClass(*rLo) == HRcGPR(env->mode64));
2526   vassert(hregIsVirtual(*rLo));
2527}
2528
2529/* DO NOT CALL THIS DIRECTLY ! */
2530static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
2531                                 ISelEnv* env, IRExpr* e )
2532{
2533   vassert(e);
2534   vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
2535
2536   /* read 128-bit IRTemp */
2537   if (e->tag == Iex_RdTmp) {
2538      lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
2539      return;
2540   }
2541
2542   /* --------- BINARY ops --------- */
2543   if (e->tag == Iex_Binop) {
2544      switch (e->Iex.Binop.op) {
2545      /* 64 x 64 -> 128 multiply */
2546      case Iop_MullU64:
2547      case Iop_MullS64: {
2548         HReg     tLo     = newVRegI(env);
2549         HReg     tHi     = newVRegI(env);
2550         Bool     syned   = toBool(e->Iex.Binop.op == Iop_MullS64);
2551         HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
2552         HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2553         addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
2554                                     False/*lo64*/, False/*64bit mul*/,
2555                                     tLo, r_srcL, r_srcR));
2556         addInstr(env, PPCInstr_MulL(syned,
2557                                     True/*hi64*/, False/*64bit mul*/,
2558                                     tHi, r_srcL, r_srcR));
2559         *rHi = tHi;
2560         *rLo = tLo;
2561         return;
2562      }
2563
2564      /* 64HLto128(e1,e2) */
2565      case Iop_64HLto128:
2566         *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2567         *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2568         return;
2569
2570      default:
2571         break;
2572      }
2573   } /* if (e->tag == Iex_Binop) */
2574
2575
2576   /* --------- UNARY ops --------- */
2577   if (e->tag == Iex_Unop) {
2578      switch (e->Iex.Unop.op) {
2579      default:
2580         break;
2581      }
2582   } /* if (e->tag == Iex_Unop) */
2583
2584   vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
2585   ppIRExpr(e);
2586   vpanic("iselInt128Expr(ppc64)");
2587}
2588
2589
2590/*---------------------------------------------------------*/
2591/*--- ISEL: Integer expressions (64 bit)                ---*/
2592/*---------------------------------------------------------*/
2593
2594/* 32-bit mode ONLY: compute a 64-bit value into a register pair,
2595   which is returned as the first two parameters.  As with
2596   iselIntExpr_R, these may be either real or virtual regs; in any
2597   case they must not be changed by subsequent code emitted by the
2598   caller.  */
2599
2600static void iselInt64Expr ( HReg* rHi, HReg* rLo,
2601                            ISelEnv* env, IRExpr* e )
2602{
2603   vassert(!env->mode64);
2604   iselInt64Expr_wrk(rHi, rLo, env, e);
2605#  if 0
2606   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2607#  endif
2608   vassert(hregClass(*rHi) == HRcInt32);
2609   vassert(hregIsVirtual(*rHi));
2610   vassert(hregClass(*rLo) == HRcInt32);
2611   vassert(hregIsVirtual(*rLo));
2612}
2613
2614/* DO NOT CALL THIS DIRECTLY ! */
2615static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
2616                                ISelEnv* env, IRExpr* e )
2617{
2618   vassert(e);
2619   vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
2620
2621   /* 64-bit load */
2622   if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
2623      HReg tLo    = newVRegI(env);
2624      HReg tHi    = newVRegI(env);
2625      HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
2626      vassert(!env->mode64);
2627      addInstr(env, PPCInstr_Load( 4/*byte-load*/,
2628                                   tHi, PPCAMode_IR( 0, r_addr ),
2629                                   False/*32-bit insn please*/) );
2630      addInstr(env, PPCInstr_Load( 4/*byte-load*/,
2631                                   tLo, PPCAMode_IR( 4, r_addr ),
2632                                   False/*32-bit insn please*/) );
2633      *rHi = tHi;
2634      *rLo = tLo;
2635      return;
2636   }
2637
2638   /* 64-bit literal */
2639   if (e->tag == Iex_Const) {
2640      ULong w64 = e->Iex.Const.con->Ico.U64;
2641      UInt  wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
2642      UInt  wLo = ((UInt)w64) & 0xFFFFFFFF;
2643      HReg  tLo = newVRegI(env);
2644      HReg  tHi = newVRegI(env);
2645      vassert(e->Iex.Const.con->tag == Ico_U64);
2646      addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
2647      addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
2648      *rHi = tHi;
2649      *rLo = tLo;
2650      return;
2651   }
2652
2653   /* read 64-bit IRTemp */
2654   if (e->tag == Iex_RdTmp) {
2655      lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
2656      return;
2657   }
2658
2659   /* 64-bit GET */
2660   if (e->tag == Iex_Get) {
2661      PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2662                                       GuestStatePtr(False/*mode32*/) );
2663      PPCAMode* am_addr4 = advance4(env, am_addr);
2664      HReg tLo = newVRegI(env);
2665      HReg tHi = newVRegI(env);
2666      addInstr(env, PPCInstr_Load( 4, tHi, am_addr,  False/*mode32*/ ));
2667      addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
2668      *rHi = tHi;
2669      *rLo = tLo;
2670      return;
2671   }
2672
2673   /* 64-bit Mux0X */
2674   if (e->tag == Iex_Mux0X) {
2675      HReg e0Lo, e0Hi, eXLo, eXHi;
2676      HReg tLo = newVRegI(env);
2677      HReg tHi = newVRegI(env);
2678
2679      PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2680      HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
2681      HReg r_tmp  = newVRegI(env);
2682
2683      iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
2684      iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX);
2685      addInstr(env, mk_iMOVds_RR(tHi,eXHi));
2686      addInstr(env, mk_iMOVds_RR(tLo,eXLo));
2687
2688      addInstr(env, PPCInstr_Alu(Palu_AND,
2689                                 r_tmp, r_cond, PPCRH_Imm(False,0xFF)));
2690      addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2691                                 7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
2692
2693      addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(e0Hi)));
2694      addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(e0Lo)));
2695      *rHi = tHi;
2696      *rLo = tLo;
2697      return;
2698   }
2699
2700   /* --------- BINARY ops --------- */
2701   if (e->tag == Iex_Binop) {
2702      IROp op_binop = e->Iex.Binop.op;
2703      switch (op_binop) {
2704         /* 32 x 32 -> 64 multiply */
2705         case Iop_MullU32:
2706         case Iop_MullS32: {
2707            HReg     tLo     = newVRegI(env);
2708            HReg     tHi     = newVRegI(env);
2709            Bool     syned   = toBool(op_binop == Iop_MullS32);
2710            HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
2711            HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2712            addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/,
2713                                        False/*lo32*/, True/*32bit mul*/,
2714                                        tLo, r_srcL, r_srcR));
2715            addInstr(env, PPCInstr_MulL(syned,
2716                                        True/*hi32*/, True/*32bit mul*/,
2717                                        tHi, r_srcL, r_srcR));
2718            *rHi = tHi;
2719            *rLo = tLo;
2720            return;
2721         }
2722
2723         /* Or64/And64/Xor64 */
2724         case Iop_Or64:
2725         case Iop_And64:
2726         case Iop_Xor64: {
2727            HReg xLo, xHi, yLo, yHi;
2728            HReg tLo = newVRegI(env);
2729            HReg tHi = newVRegI(env);
2730            PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
2731                          (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
2732            iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2733            iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2734            addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
2735            addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
2736            *rHi = tHi;
2737            *rLo = tLo;
2738            return;
2739         }
2740
2741         /* Add64 */
2742         case Iop_Add64: {
2743            HReg xLo, xHi, yLo, yHi;
2744            HReg tLo = newVRegI(env);
2745            HReg tHi = newVRegI(env);
2746            iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2747            iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2748            addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
2749                                            tLo, xLo, yLo));
2750            addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
2751                                            tHi, xHi, yHi));
2752            *rHi = tHi;
2753            *rLo = tLo;
2754            return;
2755         }
2756
2757         /* 32HLto64(e1,e2) */
2758         case Iop_32HLto64:
2759            *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2760            *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2761            return;
2762
2763         /* F64toI64[S|U] */
2764         case Iop_F64toI64S: case Iop_F64toI64U: {
2765            HReg      tLo     = newVRegI(env);
2766            HReg      tHi     = newVRegI(env);
2767            HReg      r1      = StackFramePtr(env->mode64);
2768            PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
2769            PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
2770            HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2);
2771            HReg      ftmp    = newVRegF(env);
2772
2773            vassert(!env->mode64);
2774            /* Set host rounding mode */
2775            set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2776
2777            sub_from_sp( env, 16 );
2778            addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/,
2779                                          (op_binop == Iop_F64toI64S) ? True : False,
2780                                          True, ftmp, fsrc));
2781            addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
2782            addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
2783            addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
2784            add_to_sp( env, 16 );
2785
2786            ///* Restore default FPU rounding. */
2787            //set_FPU_rounding_default( env );
2788            *rHi = tHi;
2789            *rLo = tLo;
2790            return;
2791         }
2792
2793         default:
2794            break;
2795      }
2796   } /* if (e->tag == Iex_Binop) */
2797
2798
2799   /* --------- UNARY ops --------- */
2800   if (e->tag == Iex_Unop) {
2801      switch (e->Iex.Unop.op) {
2802
2803      /* CmpwNEZ64(e) */
2804      case Iop_CmpwNEZ64: {
2805         HReg argHi, argLo;
2806         HReg tmp1  = newVRegI(env);
2807         HReg tmp2  = newVRegI(env);
2808         iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
2809         /* tmp1 = argHi | argLo */
2810         addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
2811         /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2812         addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
2813         addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
2814         addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2815                                     tmp2, tmp2, PPCRH_Imm(False, 31)));
2816         *rHi = tmp2;
2817         *rLo = tmp2; /* yes, really tmp2 */
2818         return;
2819      }
2820
2821      /* Left64 */
2822      case Iop_Left64: {
2823         HReg argHi, argLo;
2824         HReg zero32 = newVRegI(env);
2825         HReg resHi  = newVRegI(env);
2826         HReg resLo  = newVRegI(env);
2827         iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
2828         vassert(env->mode64 == False);
2829         addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
2830         /* resHi:resLo = - argHi:argLo */
2831         addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
2832                                         resLo, zero32, argLo ));
2833         addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
2834                                         resHi, zero32, argHi ));
2835         /* resHi:resLo |= srcHi:srcLo */
2836         addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
2837         addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
2838         *rHi = resHi;
2839         *rLo = resLo;
2840         return;
2841      }
2842
2843      /* 32Sto64(e) */
2844      case Iop_32Sto64: {
2845         HReg tHi = newVRegI(env);
2846         HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2847         addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2848                                     tHi, src, PPCRH_Imm(False,31)));
2849         *rHi = tHi;
2850         *rLo = src;
2851         return;
2852      }
2853
2854      /* 32Uto64(e) */
2855      case Iop_32Uto64: {
2856         HReg tHi = newVRegI(env);
2857         HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg);
2858         addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
2859         *rHi = tHi;
2860         *rLo = tLo;
2861         return;
2862      }
2863
2864      /* V128{HI}to64 */
2865      case Iop_V128HIto64:
2866      case Iop_V128to64: {
2867         HReg r_aligned16;
2868         Int  off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
2869         HReg tLo = newVRegI(env);
2870         HReg tHi = newVRegI(env);
2871         HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
2872         PPCAMode *am_off0, *am_offLO, *am_offHI;
2873         sub_from_sp( env, 32 );     // Move SP down 32 bytes
2874
2875         // get a quadword aligned address within our stack space
2876         r_aligned16 = get_sp_aligned16( env );
2877         am_off0  = PPCAMode_IR( 0,     r_aligned16 );
2878         am_offHI = PPCAMode_IR( off,   r_aligned16 );
2879         am_offLO = PPCAMode_IR( off+4, r_aligned16 );
2880
2881         // store as Vec128
2882         addInstr(env,
2883                  PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2884
2885         // load hi,lo words (of hi/lo half of vec) as Ity_I32's
2886         addInstr(env,
2887                  PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
2888         addInstr(env,
2889                  PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
2890
2891         add_to_sp( env, 32 );       // Reset SP
2892         *rHi = tHi;
2893         *rLo = tLo;
2894         return;
2895      }
2896
2897      /* could do better than this, but for now ... */
2898      case Iop_1Sto64: {
2899         HReg tLo = newVRegI(env);
2900         HReg tHi = newVRegI(env);
2901         PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2902         addInstr(env, PPCInstr_Set(cond,tLo));
2903         addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
2904                                     tLo, tLo, PPCRH_Imm(False,31)));
2905         addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2906                                     tLo, tLo, PPCRH_Imm(False,31)));
2907         addInstr(env, mk_iMOVds_RR(tHi, tLo));
2908         *rHi = tHi;
2909         *rLo = tLo;
2910         return;
2911      }
2912
2913      case Iop_Not64: {
2914         HReg xLo, xHi;
2915         HReg tmpLo = newVRegI(env);
2916         HReg tmpHi = newVRegI(env);
2917         iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg);
2918         addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
2919         addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
2920         *rHi = tmpHi;
2921         *rLo = tmpLo;
2922         return;
2923      }
2924
2925      /* ReinterpF64asI64(e) */
2926      /* Given an IEEE754 double, produce an I64 with the same bit
2927         pattern. */
2928      case Iop_ReinterpF64asI64: {
2929         PPCAMode *am_addr0, *am_addr1;
2930         HReg fr_src  = iselDblExpr(env, e->Iex.Unop.arg);
2931         HReg r_dstLo = newVRegI(env);
2932         HReg r_dstHi = newVRegI(env);
2933
2934         sub_from_sp( env, 16 );     // Move SP down 16 bytes
2935         am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
2936         am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
2937
2938         // store as F64
2939         addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2940                                        fr_src, am_addr0 ));
2941
2942         // load hi,lo as Ity_I32's
2943         addInstr(env, PPCInstr_Load( 4, r_dstHi,
2944                                      am_addr0, False/*mode32*/ ));
2945         addInstr(env, PPCInstr_Load( 4, r_dstLo,
2946                                      am_addr1, False/*mode32*/ ));
2947         *rHi = r_dstHi;
2948         *rLo = r_dstLo;
2949
2950         add_to_sp( env, 16 );       // Reset SP
2951         return;
2952      }
2953
2954      default:
2955         break;
2956      }
2957   } /* if (e->tag == Iex_Unop) */
2958
2959   vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
2960   ppIRExpr(e);
2961   vpanic("iselInt64Expr(ppc)");
2962}
2963
2964
2965/*---------------------------------------------------------*/
2966/*--- ISEL: Floating point expressions (32 bit)         ---*/
2967/*---------------------------------------------------------*/
2968
2969/* Nothing interesting here; really just wrappers for
2970   64-bit stuff. */
2971
2972static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
2973{
2974   HReg r = iselFltExpr_wrk( env, e );
2975#  if 0
2976   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2977#  endif
2978   vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
2979   vassert(hregIsVirtual(r));
2980   return r;
2981}
2982
2983/* DO NOT CALL THIS DIRECTLY */
2984static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
2985{
2986   Bool        mode64 = env->mode64;
2987
2988   IRType ty = typeOfIRExpr(env->type_env,e);
2989   vassert(ty == Ity_F32);
2990
2991   if (e->tag == Iex_RdTmp) {
2992      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2993   }
2994
2995   if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
2996      PPCAMode* am_addr;
2997      HReg r_dst = newVRegF(env);
2998      vassert(e->Iex.Load.ty == Ity_F32);
2999      am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/);
3000      addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
3001      return r_dst;
3002   }
3003
3004   if (e->tag == Iex_Get) {
3005      HReg r_dst = newVRegF(env);
3006      PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3007                                       GuestStatePtr(env->mode64) );
3008      addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
3009      return r_dst;
3010   }
3011
3012   if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3013      /* This is quite subtle.  The only way to do the relevant
3014         truncation is to do a single-precision store and then a
3015         double precision load to get it back into a register.  The
3016         problem is, if the data is then written to memory a second
3017         time, as in
3018
3019            STbe(...) = TruncF64asF32(...)
3020
3021         then will the second truncation further alter the value?  The
3022         answer is no: flds (as generated here) followed by fsts
3023         (generated for the STbe) is the identity function on 32-bit
3024         floats, so we are safe.
3025
3026         Another upshot of this is that if iselStmt can see the
3027         entirety of
3028
3029            STbe(...) = TruncF64asF32(arg)
3030
3031         then it can short circuit having to deal with TruncF64asF32
3032         individually; instead just compute arg into a 64-bit FP
3033         register and do 'fsts' (since that itself does the
3034         truncation).
3035
3036         We generate pretty poor code here (should be ok both for
3037         32-bit and 64-bit mode); but it is expected that for the most
3038         part the latter optimisation will apply and hence this code
3039         will not often be used.
3040      */
3041      HReg      fsrc    = iselDblExpr(env, e->Iex.Unop.arg);
3042      HReg      fdst    = newVRegF(env);
3043      PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3044
3045      sub_from_sp( env, 16 );
3046      // store as F32, hence truncating
3047      addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3048                                     fsrc, zero_r1 ));
3049      // and reload.  Good huh?! (sigh)
3050      addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3051                                     fdst, zero_r1 ));
3052      add_to_sp( env, 16 );
3053      return fdst;
3054   }
3055
3056   if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3057      if (mode64) {
3058         HReg fdst = newVRegF(env);
3059         HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
3060         HReg r1   = StackFramePtr(env->mode64);
3061         PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3062
3063         /* Set host rounding mode */
3064         set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3065
3066         sub_from_sp( env, 16 );
3067
3068         addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3069         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3070         addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3071                                       False, False,
3072                                       fdst, fdst));
3073
3074         add_to_sp( env, 16 );
3075
3076         ///* Restore default FPU rounding. */
3077         //set_FPU_rounding_default( env );
3078         return fdst;
3079      } else {
3080         /* 32-bit mode */
3081         HReg fdst = newVRegF(env);
3082         HReg isrcHi, isrcLo;
3083         HReg r1   = StackFramePtr(env->mode64);
3084         PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3085         PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3086
3087         iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2);
3088
3089         /* Set host rounding mode */
3090         set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3091
3092         sub_from_sp( env, 16 );
3093
3094         addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3095         addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3096         addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3097         addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3098                                       False, False,
3099                                       fdst, fdst));
3100
3101         add_to_sp( env, 16 );
3102
3103         ///* Restore default FPU rounding. */
3104         //set_FPU_rounding_default( env );
3105         return fdst;
3106      }
3107
3108   }
3109
3110   vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3111   ppIRExpr(e);
3112   vpanic("iselFltExpr_wrk(ppc)");
3113}
3114
3115
3116/*---------------------------------------------------------*/
3117/*--- ISEL: Floating point expressions (64 bit)         ---*/
3118/*---------------------------------------------------------*/
3119
3120/* Compute a 64-bit floating point value into a register, the identity
3121   of which is returned.  As with iselIntExpr_R, the reg may be either
3122   real or virtual; in any case it must not be changed by subsequent
3123   code emitted by the caller.  */
3124
3125/* IEEE 754 formats.  From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3126
3127    Type                  S (1 bit)   E (11 bits)   F (52 bits)
3128    ----                  ---------   -----------   -----------
3129    signalling NaN        u           2047 (max)    .0uuuuu---u
3130                                                    (with at least
3131                                                     one 1 bit)
3132    quiet NaN             u           2047 (max)    .1uuuuu---u
3133
3134    negative infinity     1           2047 (max)    .000000---0
3135
3136    positive infinity     0           2047 (max)    .000000---0
3137
3138    negative zero         1           0             .000000---0
3139
3140    positive zero         0           0             .000000---0
3141*/
3142
3143static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
3144{
3145   HReg r = iselDblExpr_wrk( env, e );
3146#  if 0
3147   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3148#  endif
3149   vassert(hregClass(r) == HRcFlt64);
3150   vassert(hregIsVirtual(r));
3151   return r;
3152}
3153
3154/* DO NOT CALL THIS DIRECTLY */
3155static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
3156{
3157   Bool mode64 = env->mode64;
3158   IRType ty = typeOfIRExpr(env->type_env,e);
3159   vassert(e);
3160   vassert(ty == Ity_F64);
3161
3162   if (e->tag == Iex_RdTmp) {
3163      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3164   }
3165
3166   /* --------- LITERAL --------- */
3167   if (e->tag == Iex_Const) {
3168      union { UInt u32x2[2]; ULong u64; Double f64; } u;
3169      vassert(sizeof(u) == 8);
3170      vassert(sizeof(u.u64) == 8);
3171      vassert(sizeof(u.f64) == 8);
3172      vassert(sizeof(u.u32x2) == 8);
3173
3174      if (e->Iex.Const.con->tag == Ico_F64) {
3175         u.f64 = e->Iex.Const.con->Ico.F64;
3176      }
3177      else if (e->Iex.Const.con->tag == Ico_F64i) {
3178         u.u64 = e->Iex.Const.con->Ico.F64i;
3179      }
3180      else
3181         vpanic("iselDblExpr(ppc): const");
3182
3183      if (!mode64) {
3184         HReg r_srcHi = newVRegI(env);
3185         HReg r_srcLo = newVRegI(env);
3186         addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3187         addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3188         return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3189      } else { // mode64
3190         HReg r_src = newVRegI(env);
3191         addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3192         return mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
3193      }
3194   }
3195
3196   /* --------- LOAD --------- */
3197   if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
3198      HReg r_dst = newVRegF(env);
3199      PPCAMode* am_addr;
3200      vassert(e->Iex.Load.ty == Ity_F64);
3201      am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/);
3202      addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3203      return r_dst;
3204   }
3205
3206   /* --------- GET --------- */
3207   if (e->tag == Iex_Get) {
3208      HReg r_dst = newVRegF(env);
3209      PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3210                                       GuestStatePtr(mode64) );
3211      addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
3212      return r_dst;
3213   }
3214
3215   /* --------- OPS --------- */
3216   if (e->tag == Iex_Qop) {
3217      PPCFpOp fpop = Pfp_INVALID;
3218      switch (e->Iex.Qop.op) {
3219         case Iop_MAddF64:    fpop = Pfp_MADDD; break;
3220         case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
3221         case Iop_MSubF64:    fpop = Pfp_MSUBD; break;
3222         case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
3223         default: break;
3224      }
3225      if (fpop != Pfp_INVALID) {
3226         HReg r_dst  = newVRegF(env);
3227         HReg r_srcML  = iselDblExpr(env, e->Iex.Qop.arg2);
3228         HReg r_srcMR  = iselDblExpr(env, e->Iex.Qop.arg3);
3229         HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.arg4);
3230         set_FPU_rounding_mode( env, e->Iex.Qop.arg1 );
3231         addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst,
3232                                               r_srcML, r_srcMR, r_srcAcc));
3233         return r_dst;
3234      }
3235   }
3236
3237   if (e->tag == Iex_Triop) {
3238      PPCFpOp fpop = Pfp_INVALID;
3239      switch (e->Iex.Triop.op) {
3240         case Iop_AddF64:    fpop = Pfp_ADDD; break;
3241         case Iop_SubF64:    fpop = Pfp_SUBD; break;
3242         case Iop_MulF64:    fpop = Pfp_MULD; break;
3243         case Iop_DivF64:    fpop = Pfp_DIVD; break;
3244         case Iop_AddF64r32: fpop = Pfp_ADDS; break;
3245         case Iop_SubF64r32: fpop = Pfp_SUBS; break;
3246         case Iop_MulF64r32: fpop = Pfp_MULS; break;
3247         case Iop_DivF64r32: fpop = Pfp_DIVS; break;
3248         default: break;
3249      }
3250      if (fpop != Pfp_INVALID) {
3251         HReg r_dst  = newVRegF(env);
3252         HReg r_srcL = iselDblExpr(env, e->Iex.Triop.arg2);
3253         HReg r_srcR = iselDblExpr(env, e->Iex.Triop.arg3);
3254         set_FPU_rounding_mode( env, e->Iex.Triop.arg1 );
3255         addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
3256         return r_dst;
3257      }
3258   }
3259
3260   if (e->tag == Iex_Binop) {
3261      PPCFpOp fpop = Pfp_INVALID;
3262      switch (e->Iex.Binop.op) {
3263         case Iop_SqrtF64: fpop = Pfp_SQRT; break;
3264         default: break;
3265      }
3266      if (fpop != Pfp_INVALID) {
3267         HReg fr_dst = newVRegF(env);
3268         HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2);
3269         set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3270         addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
3271         return fr_dst;
3272      }
3273   }
3274
3275   if (e->tag == Iex_Binop) {
3276
3277      if (e->Iex.Binop.op == Iop_RoundF64toF32) {
3278         HReg r_dst = newVRegF(env);
3279         HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2);
3280         set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3281         addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
3282         //set_FPU_rounding_default( env );
3283         return r_dst;
3284      }
3285
3286      if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
3287         if (mode64) {
3288            HReg fdst = newVRegF(env);
3289            HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
3290            HReg r1   = StackFramePtr(env->mode64);
3291            PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3292
3293            /* Set host rounding mode */
3294            set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3295
3296            sub_from_sp( env, 16 );
3297
3298            addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3299            addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3300            addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3301                                          e->Iex.Binop.op == Iop_I64StoF64,
3302                                          True/*fdst is 64 bit*/,
3303                                          fdst, fdst));
3304
3305            add_to_sp( env, 16 );
3306
3307            ///* Restore default FPU rounding. */
3308            //set_FPU_rounding_default( env );
3309            return fdst;
3310         } else {
3311            /* 32-bit mode */
3312            HReg fdst = newVRegF(env);
3313            HReg isrcHi, isrcLo;
3314            HReg r1   = StackFramePtr(env->mode64);
3315            PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3316            PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3317
3318            iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2);
3319
3320            /* Set host rounding mode */
3321            set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3322
3323            sub_from_sp( env, 16 );
3324
3325            addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3326            addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3327            addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3328            addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/,
3329                                          e->Iex.Binop.op == Iop_I64StoF64,
3330                                          True/*fdst is 64 bit*/,
3331                                          fdst, fdst));
3332
3333            add_to_sp( env, 16 );
3334
3335            ///* Restore default FPU rounding. */
3336            //set_FPU_rounding_default( env );
3337            return fdst;
3338         }
3339      }
3340
3341   }
3342
3343   if (e->tag == Iex_Unop) {
3344      PPCFpOp fpop = Pfp_INVALID;
3345      switch (e->Iex.Unop.op) {
3346         case Iop_NegF64:     fpop = Pfp_NEG; break;
3347         case Iop_AbsF64:     fpop = Pfp_ABS; break;
3348         case Iop_Est5FRSqrt: fpop = Pfp_RSQRTE; break;
3349         case Iop_RoundF64toF64_NegINF:  fpop = Pfp_FRIM; break;
3350         case Iop_RoundF64toF64_PosINF:  fpop = Pfp_FRIP; break;
3351         case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
3352         case Iop_RoundF64toF64_ZERO:    fpop = Pfp_FRIZ; break;
3353         default: break;
3354      }
3355      if (fpop != Pfp_INVALID) {
3356         HReg fr_dst = newVRegF(env);
3357         HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
3358         addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
3359         return fr_dst;
3360      }
3361   }
3362
3363   if (e->tag == Iex_Unop) {
3364      switch (e->Iex.Unop.op) {
3365         case Iop_ReinterpI64asF64: {
3366            /* Given an I64, produce an IEEE754 double with the same
3367               bit pattern. */
3368            if (!mode64) {
3369               HReg r_srcHi, r_srcLo;
3370               iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg);
3371               return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3372            } else {
3373               HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3374               return mk_LoadR64toFPR( env, r_src );
3375            }
3376         }
3377
3378         case Iop_F32toF64: {
3379            if (e->Iex.Unop.arg->tag == Iex_Unop &&
3380                     e->Iex.Unop.arg->Iex.Unop.op == Iop_ReinterpI32asF32 ) {
3381               e = e->Iex.Unop.arg;
3382
3383               HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
3384               HReg fr_dst = newVRegF(env);
3385               PPCAMode *am_addr;
3386
3387               sub_from_sp( env, 16 );        // Move SP down 16 bytes
3388               am_addr = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3389
3390               // store src as Ity_I32's
3391               addInstr(env, PPCInstr_Store( 4, am_addr, src, env->mode64 ));
3392
3393               // load single precision float, but the end results loads into a
3394               // 64-bit FP register -- i.e., F64.
3395               addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, fr_dst, am_addr));
3396
3397               add_to_sp( env, 16 );          // Reset SP
3398               return fr_dst;
3399            }
3400
3401
3402            /* this is a no-op */
3403            HReg res = iselFltExpr(env, e->Iex.Unop.arg);
3404            return res;
3405         }
3406         default:
3407            break;
3408      }
3409   }
3410
3411   /* --------- MULTIPLEX --------- */
3412   if (e->tag == Iex_Mux0X) {
3413      if (ty == Ity_F64
3414          && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
3415         PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3416         HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
3417         HReg frX    = iselDblExpr(env, e->Iex.Mux0X.exprX);
3418         HReg fr0    = iselDblExpr(env, e->Iex.Mux0X.expr0);
3419         HReg fr_dst = newVRegF(env);
3420         HReg r_tmp  = newVRegI(env);
3421         addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp,
3422                                    r_cond, PPCRH_Imm(False,0xFF)));
3423         addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, frX ));
3424         addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3425                                    7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
3426         addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr0 ));
3427         return fr_dst;
3428      }
3429   }
3430
3431   vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
3432   ppIRExpr(e);
3433   vpanic("iselDblExpr_wrk(ppc)");
3434}
3435
3436
3437/*---------------------------------------------------------*/
3438/*--- ISEL: SIMD (Vector) expressions, 128 bit.         ---*/
3439/*---------------------------------------------------------*/
3440
3441static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
3442{
3443   HReg r = iselVecExpr_wrk( env, e );
3444#  if 0
3445   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3446#  endif
3447   vassert(hregClass(r) == HRcVec128);
3448   vassert(hregIsVirtual(r));
3449   return r;
3450}
3451
3452/* DO NOT CALL THIS DIRECTLY */
3453static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
3454{
3455   Bool mode64 = env->mode64;
3456   PPCAvOp op = Pav_INVALID;
3457   PPCAvFpOp fpop = Pavfp_INVALID;
3458   IRType  ty = typeOfIRExpr(env->type_env,e);
3459   vassert(e);
3460   vassert(ty == Ity_V128);
3461
3462   if (e->tag == Iex_RdTmp) {
3463      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3464   }
3465
3466   if (e->tag == Iex_Get) {
3467      /* Guest state vectors are 16byte aligned,
3468         so don't need to worry here */
3469      HReg dst = newVRegV(env);
3470      addInstr(env,
3471               PPCInstr_AvLdSt( True/*load*/, 16, dst,
3472                                PPCAMode_IR( e->Iex.Get.offset,
3473                                             GuestStatePtr(mode64) )));
3474      return dst;
3475   }
3476
3477   if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
3478      PPCAMode* am_addr;
3479      HReg v_dst = newVRegV(env);
3480      vassert(e->Iex.Load.ty == Ity_V128);
3481      am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_V128/*xfer*/);
3482      addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, v_dst, am_addr));
3483      return v_dst;
3484   }
3485
3486   if (e->tag == Iex_Unop) {
3487      switch (e->Iex.Unop.op) {
3488
3489      case Iop_NotV128: {
3490         HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3491         HReg dst = newVRegV(env);
3492         addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
3493         return dst;
3494      }
3495
3496      case Iop_CmpNEZ8x16: {
3497         HReg arg  = iselVecExpr(env, e->Iex.Unop.arg);
3498         HReg zero = newVRegV(env);
3499         HReg dst  = newVRegV(env);
3500         addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3501         addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
3502         addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3503         return dst;
3504      }
3505
3506      case Iop_CmpNEZ16x8: {
3507         HReg arg  = iselVecExpr(env, e->Iex.Unop.arg);
3508         HReg zero = newVRegV(env);
3509         HReg dst  = newVRegV(env);
3510         addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3511         addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
3512         addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3513         return dst;
3514      }
3515
3516      case Iop_CmpNEZ32x4: {
3517         HReg arg  = iselVecExpr(env, e->Iex.Unop.arg);
3518         HReg zero = newVRegV(env);
3519         HReg dst  = newVRegV(env);
3520         addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3521         addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
3522         addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3523         return dst;
3524      }
3525
3526      case Iop_Recip32Fx4:    fpop = Pavfp_RCPF;    goto do_32Fx4_unary;
3527      case Iop_RSqrt32Fx4:    fpop = Pavfp_RSQRTF;  goto do_32Fx4_unary;
3528      case Iop_I32UtoFx4:     fpop = Pavfp_CVTU2F;  goto do_32Fx4_unary;
3529      case Iop_I32StoFx4:     fpop = Pavfp_CVTS2F;  goto do_32Fx4_unary;
3530      case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
3531      case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
3532      case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM;  goto do_32Fx4_unary;
3533      case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP;  goto do_32Fx4_unary;
3534      case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN;  goto do_32Fx4_unary;
3535      case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ;  goto do_32Fx4_unary;
3536      do_32Fx4_unary:
3537      {
3538         HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3539         HReg dst = newVRegV(env);
3540         addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
3541         return dst;
3542      }
3543
3544      case Iop_32UtoV128: {
3545         HReg r_aligned16, r_zeros;
3546         HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3547         HReg   dst = newVRegV(env);
3548         PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
3549         sub_from_sp( env, 32 );     // Move SP down
3550
3551         /* Get a quadword aligned address within our stack space */
3552         r_aligned16 = get_sp_aligned16( env );
3553         am_off0  = PPCAMode_IR( 0,  r_aligned16 );
3554         am_off4  = PPCAMode_IR( 4,  r_aligned16 );
3555         am_off8  = PPCAMode_IR( 8,  r_aligned16 );
3556         am_off12 = PPCAMode_IR( 12, r_aligned16 );
3557
3558         /* Store zeros */
3559         r_zeros = newVRegI(env);
3560         addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
3561         addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
3562         addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
3563         addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
3564
3565         /* Store r_src in low word of quadword-aligned mem */
3566         addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
3567
3568         /* Load word into low word of quadword vector reg */
3569         addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
3570
3571         add_to_sp( env, 32 );       // Reset SP
3572         return dst;
3573      }
3574
3575      case Iop_Dup8x16:
3576      case Iop_Dup16x8:
3577      case Iop_Dup32x4:
3578         return mk_AvDuplicateRI(env, e->Iex.Binop.arg1);
3579
3580      default:
3581         break;
3582      } /* switch (e->Iex.Unop.op) */
3583   } /* if (e->tag == Iex_Unop) */
3584
3585   if (e->tag == Iex_Binop) {
3586      switch (e->Iex.Binop.op) {
3587
3588      case Iop_64HLtoV128: {
3589         if (!mode64) {
3590            HReg     r3, r2, r1, r0, r_aligned16;
3591            PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
3592            HReg     dst = newVRegV(env);
3593            /* do this via the stack (easy, convenient, etc) */
3594            sub_from_sp( env, 32 );        // Move SP down
3595
3596            // get a quadword aligned address within our stack space
3597            r_aligned16 = get_sp_aligned16( env );
3598            am_off0  = PPCAMode_IR( 0,  r_aligned16 );
3599            am_off4  = PPCAMode_IR( 4,  r_aligned16 );
3600            am_off8  = PPCAMode_IR( 8,  r_aligned16 );
3601            am_off12 = PPCAMode_IR( 12, r_aligned16 );
3602
3603            /* Do the less significant 64 bits */
3604            iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2);
3605            addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
3606            addInstr(env, PPCInstr_Store( 4, am_off8,  r1, mode64 ));
3607            /* Do the more significant 64 bits */
3608            iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1);
3609            addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
3610            addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
3611
3612            /* Fetch result back from stack. */
3613            addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
3614
3615            add_to_sp( env, 32 );          // Reset SP
3616            return dst;
3617         } else {
3618            HReg     rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
3619            HReg     rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
3620            HReg     dst = newVRegV(env);
3621            HReg     r_aligned16;
3622            PPCAMode *am_off0, *am_off8;
3623            /* do this via the stack (easy, convenient, etc) */
3624            sub_from_sp( env, 32 );        // Move SP down
3625
3626            // get a quadword aligned address within our stack space
3627            r_aligned16 = get_sp_aligned16( env );
3628            am_off0  = PPCAMode_IR( 0,  r_aligned16 );
3629            am_off8  = PPCAMode_IR( 8,  r_aligned16 );
3630
3631            /* Store 2*I64 to stack */
3632            addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
3633            addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
3634
3635            /* Fetch result back from stack. */
3636            addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
3637
3638            add_to_sp( env, 32 );          // Reset SP
3639            return dst;
3640         }
3641      }
3642
3643      case Iop_Add32Fx4:   fpop = Pavfp_ADDF;   goto do_32Fx4;
3644      case Iop_Sub32Fx4:   fpop = Pavfp_SUBF;   goto do_32Fx4;
3645      case Iop_Max32Fx4:   fpop = Pavfp_MAXF;   goto do_32Fx4;
3646      case Iop_Min32Fx4:   fpop = Pavfp_MINF;   goto do_32Fx4;
3647      case Iop_Mul32Fx4:   fpop = Pavfp_MULF;   goto do_32Fx4;
3648      case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
3649      case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
3650      case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
3651      do_32Fx4:
3652      {
3653         HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3654         HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3655         HReg dst = newVRegV(env);
3656         addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
3657         return dst;
3658      }
3659
3660      case Iop_CmpLE32Fx4: {
3661         HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3662         HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3663         HReg dst = newVRegV(env);
3664
3665         /* stay consistent with native ppc compares:
3666            if a left/right lane holds a nan, return zeros for that lane
3667            so: le == NOT(gt OR isNan)
3668          */
3669         HReg isNanLR = newVRegV(env);
3670         HReg isNanL = isNan(env, argL);
3671         HReg isNanR = isNan(env, argR);
3672         addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
3673                                         isNanL, isNanR));
3674
3675         addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
3676                                           argL, argR));
3677         addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
3678         addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3679         return dst;
3680      }
3681
3682      case Iop_AndV128:    op = Pav_AND;      goto do_AvBin;
3683      case Iop_OrV128:     op = Pav_OR;       goto do_AvBin;
3684      case Iop_XorV128:    op = Pav_XOR;      goto do_AvBin;
3685      do_AvBin: {
3686         HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3687         HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3688         HReg dst  = newVRegV(env);
3689         addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
3690         return dst;
3691      }
3692
3693      case Iop_Shl8x16:    op = Pav_SHL;    goto do_AvBin8x16;
3694      case Iop_Shr8x16:    op = Pav_SHR;    goto do_AvBin8x16;
3695      case Iop_Sar8x16:    op = Pav_SAR;    goto do_AvBin8x16;
3696      case Iop_Rol8x16:    op = Pav_ROTL;   goto do_AvBin8x16;
3697      case Iop_InterleaveHI8x16: op = Pav_MRGHI;  goto do_AvBin8x16;
3698      case Iop_InterleaveLO8x16: op = Pav_MRGLO;  goto do_AvBin8x16;
3699      case Iop_Add8x16:    op = Pav_ADDU;   goto do_AvBin8x16;
3700      case Iop_QAdd8Ux16:  op = Pav_QADDU;  goto do_AvBin8x16;
3701      case Iop_QAdd8Sx16:  op = Pav_QADDS;  goto do_AvBin8x16;
3702      case Iop_Sub8x16:    op = Pav_SUBU;   goto do_AvBin8x16;
3703      case Iop_QSub8Ux16:  op = Pav_QSUBU;  goto do_AvBin8x16;
3704      case Iop_QSub8Sx16:  op = Pav_QSUBS;  goto do_AvBin8x16;
3705      case Iop_Avg8Ux16:   op = Pav_AVGU;   goto do_AvBin8x16;
3706      case Iop_Avg8Sx16:   op = Pav_AVGS;   goto do_AvBin8x16;
3707      case Iop_Max8Ux16:   op = Pav_MAXU;   goto do_AvBin8x16;
3708      case Iop_Max8Sx16:   op = Pav_MAXS;   goto do_AvBin8x16;
3709      case Iop_Min8Ux16:   op = Pav_MINU;   goto do_AvBin8x16;
3710      case Iop_Min8Sx16:   op = Pav_MINS;   goto do_AvBin8x16;
3711      case Iop_MullEven8Ux16: op = Pav_OMULU;  goto do_AvBin8x16;
3712      case Iop_MullEven8Sx16: op = Pav_OMULS;  goto do_AvBin8x16;
3713      case Iop_CmpEQ8x16:  op = Pav_CMPEQU; goto do_AvBin8x16;
3714      case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
3715      case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
3716      do_AvBin8x16: {
3717         HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3718         HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3719         HReg dst  = newVRegV(env);
3720         addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
3721         return dst;
3722      }
3723
3724      case Iop_Shl16x8:    op = Pav_SHL;    goto do_AvBin16x8;
3725      case Iop_Shr16x8:    op = Pav_SHR;    goto do_AvBin16x8;
3726      case Iop_Sar16x8:    op = Pav_SAR;    goto do_AvBin16x8;
3727      case Iop_Rol16x8:    op = Pav_ROTL;   goto do_AvBin16x8;
3728      case Iop_NarrowBin16to8x16:    op = Pav_PACKUU;  goto do_AvBin16x8;
3729      case Iop_QNarrowBin16Uto8Ux16: op = Pav_QPACKUU; goto do_AvBin16x8;
3730      case Iop_QNarrowBin16Sto8Sx16: op = Pav_QPACKSS; goto do_AvBin16x8;
3731      case Iop_InterleaveHI16x8:  op = Pav_MRGHI;  goto do_AvBin16x8;
3732      case Iop_InterleaveLO16x8:  op = Pav_MRGLO;  goto do_AvBin16x8;
3733      case Iop_Add16x8:    op = Pav_ADDU;   goto do_AvBin16x8;
3734      case Iop_QAdd16Ux8:  op = Pav_QADDU;  goto do_AvBin16x8;
3735      case Iop_QAdd16Sx8:  op = Pav_QADDS;  goto do_AvBin16x8;
3736      case Iop_Sub16x8:    op = Pav_SUBU;   goto do_AvBin16x8;
3737      case Iop_QSub16Ux8:  op = Pav_QSUBU;  goto do_AvBin16x8;
3738      case Iop_QSub16Sx8:  op = Pav_QSUBS;  goto do_AvBin16x8;
3739      case Iop_Avg16Ux8:   op = Pav_AVGU;   goto do_AvBin16x8;
3740      case Iop_Avg16Sx8:   op = Pav_AVGS;   goto do_AvBin16x8;
3741      case Iop_Max16Ux8:   op = Pav_MAXU;   goto do_AvBin16x8;
3742      case Iop_Max16Sx8:   op = Pav_MAXS;   goto do_AvBin16x8;
3743      case Iop_Min16Ux8:   op = Pav_MINU;   goto do_AvBin16x8;
3744      case Iop_Min16Sx8:   op = Pav_MINS;   goto do_AvBin16x8;
3745      case Iop_MullEven16Ux8: op = Pav_OMULU;  goto do_AvBin16x8;
3746      case Iop_MullEven16Sx8: op = Pav_OMULS;  goto do_AvBin16x8;
3747      case Iop_CmpEQ16x8:  op = Pav_CMPEQU; goto do_AvBin16x8;
3748      case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
3749      case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
3750      do_AvBin16x8: {
3751         HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3752         HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3753         HReg dst  = newVRegV(env);
3754         addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
3755         return dst;
3756      }
3757
3758      case Iop_Shl32x4:    op = Pav_SHL;    goto do_AvBin32x4;
3759      case Iop_Shr32x4:    op = Pav_SHR;    goto do_AvBin32x4;
3760      case Iop_Sar32x4:    op = Pav_SAR;    goto do_AvBin32x4;
3761      case Iop_Rol32x4:    op = Pav_ROTL;   goto do_AvBin32x4;
3762      case Iop_NarrowBin32to16x8:    op = Pav_PACKUU;  goto do_AvBin32x4;
3763      case Iop_QNarrowBin32Uto16Ux8: op = Pav_QPACKUU; goto do_AvBin32x4;
3764      case Iop_QNarrowBin32Sto16Sx8: op = Pav_QPACKSS; goto do_AvBin32x4;
3765      case Iop_InterleaveHI32x4:  op = Pav_MRGHI;  goto do_AvBin32x4;
3766      case Iop_InterleaveLO32x4:  op = Pav_MRGLO;  goto do_AvBin32x4;
3767      case Iop_Add32x4:    op = Pav_ADDU;   goto do_AvBin32x4;
3768      case Iop_QAdd32Ux4:  op = Pav_QADDU;  goto do_AvBin32x4;
3769      case Iop_QAdd32Sx4:  op = Pav_QADDS;  goto do_AvBin32x4;
3770      case Iop_Sub32x4:    op = Pav_SUBU;   goto do_AvBin32x4;
3771      case Iop_QSub32Ux4:  op = Pav_QSUBU;  goto do_AvBin32x4;
3772      case Iop_QSub32Sx4:  op = Pav_QSUBS;  goto do_AvBin32x4;
3773      case Iop_Avg32Ux4:   op = Pav_AVGU;   goto do_AvBin32x4;
3774      case Iop_Avg32Sx4:   op = Pav_AVGS;   goto do_AvBin32x4;
3775      case Iop_Max32Ux4:   op = Pav_MAXU;   goto do_AvBin32x4;
3776      case Iop_Max32Sx4:   op = Pav_MAXS;   goto do_AvBin32x4;
3777      case Iop_Min32Ux4:   op = Pav_MINU;   goto do_AvBin32x4;
3778      case Iop_Min32Sx4:   op = Pav_MINS;   goto do_AvBin32x4;
3779      case Iop_CmpEQ32x4:  op = Pav_CMPEQU; goto do_AvBin32x4;
3780      case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
3781      case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
3782      do_AvBin32x4: {
3783         HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3784         HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3785         HReg dst  = newVRegV(env);
3786         addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
3787         return dst;
3788      }
3789
3790      case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
3791      case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
3792      do_AvShift8x16: {
3793         HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3794         HReg dst    = newVRegV(env);
3795         HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3796         addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
3797         return dst;
3798      }
3799
3800      case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
3801      case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
3802      case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
3803      do_AvShift16x8: {
3804         HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3805         HReg dst    = newVRegV(env);
3806         HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3807         addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
3808         return dst;
3809      }
3810
3811      case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
3812      case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
3813      case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
3814      do_AvShift32x4: {
3815         HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3816         HReg dst    = newVRegV(env);
3817         HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3818         addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
3819         return dst;
3820      }
3821
3822      case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
3823      case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
3824      do_AvShiftV128: {
3825         HReg dst    = newVRegV(env);
3826         HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3827         HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3828         /* Note: shift value gets masked by 127 */
3829         addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
3830         return dst;
3831      }
3832
3833      case Iop_Perm8x16: {
3834         HReg dst   = newVRegV(env);
3835         HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1);
3836         HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2);
3837         addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
3838         return dst;
3839      }
3840
3841      default:
3842         break;
3843      } /* switch (e->Iex.Binop.op) */
3844   } /* if (e->tag == Iex_Binop) */
3845
3846   if (e->tag == Iex_Const ) {
3847      vassert(e->Iex.Const.con->tag == Ico_V128);
3848      if (e->Iex.Const.con->Ico.V128 == 0x0000) {
3849         return generate_zeroes_V128(env);
3850      }
3851      else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
3852         return generate_ones_V128(env);
3853      }
3854   }
3855
3856   vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
3857              LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
3858                                 env->hwcaps));
3859   ppIRExpr(e);
3860   vpanic("iselVecExpr_wrk(ppc)");
3861}
3862
3863
3864/*---------------------------------------------------------*/
3865/*--- ISEL: Statements                                  ---*/
3866/*---------------------------------------------------------*/
3867
3868static void iselStmt ( ISelEnv* env, IRStmt* stmt )
3869{
3870   Bool mode64 = env->mode64;
3871   if (vex_traceflags & VEX_TRACE_VCODE) {
3872      vex_printf("\n -- ");
3873      ppIRStmt(stmt);
3874      vex_printf("\n");
3875   }
3876
3877   switch (stmt->tag) {
3878
3879   /* --------- STORE --------- */
3880   case Ist_Store: {
3881      IRType    tya   = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
3882      IRType    tyd   = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3883      IREndness end   = stmt->Ist.Store.end;
3884
3885      if (end != Iend_BE)
3886         goto stmt_fail;
3887      if (!mode64 && (tya != Ity_I32))
3888         goto stmt_fail;
3889      if (mode64 && (tya != Ity_I64))
3890         goto stmt_fail;
3891
3892      if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
3893          (mode64 && (tyd == Ity_I64))) {
3894         PPCAMode* am_addr
3895            = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3896         HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
3897         addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)),
3898                                       am_addr, r_src, mode64 ));
3899         return;
3900      }
3901      if (tyd == Ity_F64) {
3902         PPCAMode* am_addr
3903            = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3904         HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
3905         addInstr(env,
3906                  PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
3907         return;
3908      }
3909      if (tyd == Ity_F32) {
3910         PPCAMode* am_addr
3911            = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3912         HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3913         addInstr(env,
3914                  PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
3915         return;
3916      }
3917      if (tyd == Ity_V128) {
3918         PPCAMode* am_addr
3919            = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3920         HReg v_src = iselVecExpr(env, stmt->Ist.Store.data);
3921         addInstr(env,
3922                  PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
3923         return;
3924      }
3925      if (tyd == Ity_I64 && !mode64) {
3926         /* Just calculate the address in the register.  Life is too
3927            short to arse around trying and possibly failing to adjust
3928            the offset in a 'reg+offset' style amode. */
3929         HReg rHi32, rLo32;
3930         HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
3931         iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data );
3932         addInstr(env, PPCInstr_Store( 4/*byte-store*/,
3933                                       PPCAMode_IR( 0, r_addr ),
3934                                       rHi32,
3935                                       False/*32-bit insn please*/) );
3936         addInstr(env, PPCInstr_Store( 4/*byte-store*/,
3937                                       PPCAMode_IR( 4, r_addr ),
3938                                       rLo32,
3939                                       False/*32-bit insn please*/) );
3940         return;
3941      }
3942      break;
3943   }
3944
3945   /* --------- PUT --------- */
3946   case Ist_Put: {
3947      IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3948      if (ty == Ity_I8  || ty == Ity_I16 ||
3949          ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
3950         HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
3951         PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3952                                          GuestStatePtr(mode64) );
3953         addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)),
3954                                       am_addr, r_src, mode64 ));
3955         return;
3956      }
3957      if (!mode64 && ty == Ity_I64) {
3958         HReg rHi, rLo;
3959         PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
3960                                           GuestStatePtr(mode64) );
3961         PPCAMode* am_addr4 = advance4(env, am_addr);
3962         iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data);
3963         addInstr(env, PPCInstr_Store( 4, am_addr,  rHi, mode64 ));
3964         addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
3965         return;
3966     }
3967     if (ty == Ity_V128) {
3968         /* Guest state vectors are 16byte aligned,
3969            so don't need to worry here */
3970         HReg v_src = iselVecExpr(env, stmt->Ist.Put.data);
3971         PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
3972                                           GuestStatePtr(mode64) );
3973         addInstr(env,
3974                  PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
3975         return;
3976      }
3977      if (ty == Ity_F64) {
3978         HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data);
3979         PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3980                                          GuestStatePtr(mode64) );
3981         addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3982                                        fr_src, am_addr ));
3983         return;
3984      }
3985      break;
3986   }
3987
3988   /* --------- Indexed PUT --------- */
3989   case Ist_PutI: {
3990      PPCAMode* dst_am
3991         = genGuestArrayOffset(
3992              env, stmt->Ist.PutI.descr,
3993                   stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
3994      IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
3995      if (mode64 && ty == Ity_I64) {
3996         HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data);
3997         addInstr(env, PPCInstr_Store( toUChar(8),
3998                                       dst_am, r_src, mode64 ));
3999         return;
4000      }
4001      if ((!mode64) && ty == Ity_I32) {
4002         HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data);
4003         addInstr(env, PPCInstr_Store( toUChar(4),
4004                                       dst_am, r_src, mode64 ));
4005         return;
4006      }
4007      break;
4008   }
4009
4010   /* --------- TMP --------- */
4011   case Ist_WrTmp: {
4012      IRTemp tmp = stmt->Ist.WrTmp.tmp;
4013      IRType ty = typeOfIRTemp(env->type_env, tmp);
4014      if (ty == Ity_I8  || ty == Ity_I16 ||
4015          ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
4016         HReg r_dst = lookupIRTemp(env, tmp);
4017         HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
4018         addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
4019         return;
4020      }
4021      if (!mode64 && ty == Ity_I64) {
4022         HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
4023         iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
4024         lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
4025         addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
4026         addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
4027         return;
4028      }
4029      if (mode64 && ty == Ity_I128) {
4030         HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
4031         iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
4032         lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
4033         addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
4034         addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
4035         return;
4036      }
4037      if (ty == Ity_I1) {
4038         PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
4039         HReg r_dst = lookupIRTemp(env, tmp);
4040         addInstr(env, PPCInstr_Set(cond, r_dst));
4041         return;
4042      }
4043      if (ty == Ity_F64) {
4044         HReg fr_dst = lookupIRTemp(env, tmp);
4045         HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data);
4046         addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
4047         return;
4048      }
4049      if (ty == Ity_F32) {
4050         HReg fr_dst = lookupIRTemp(env, tmp);
4051         HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
4052         addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
4053         return;
4054      }
4055      if (ty == Ity_V128) {
4056         HReg v_dst = lookupIRTemp(env, tmp);
4057         HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data);
4058         addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
4059         return;
4060      }
4061      break;
4062   }
4063
4064   /* --------- Load Linked or Store Conditional --------- */
4065   case Ist_LLSC: {
4066      IRTemp res    = stmt->Ist.LLSC.result;
4067      IRType tyRes  = typeOfIRTemp(env->type_env, res);
4068      IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
4069
4070      if (stmt->Ist.LLSC.end != Iend_BE)
4071         goto stmt_fail;
4072      if (!mode64 && (tyAddr != Ity_I32))
4073         goto stmt_fail;
4074      if (mode64 && (tyAddr != Ity_I64))
4075         goto stmt_fail;
4076
4077      if (stmt->Ist.LLSC.storedata == NULL) {
4078         /* LL */
4079         HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr );
4080         HReg r_dst  = lookupIRTemp(env, res);
4081         if (tyRes == Ity_I32) {
4082            addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
4083            return;
4084         }
4085         if (tyRes == Ity_I64 && mode64) {
4086            addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
4087            return;
4088         }
4089         /* fallthru */;
4090      } else {
4091         /* SC */
4092         HReg   r_res  = lookupIRTemp(env, res); /* :: Ity_I1 */
4093         HReg   r_a    = iselWordExpr_R(env, stmt->Ist.LLSC.addr);
4094         HReg   r_src  = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
4095         HReg   r_tmp  = newVRegI(env);
4096         IRType tyData = typeOfIRExpr(env->type_env,
4097                                      stmt->Ist.LLSC.storedata);
4098         vassert(tyRes == Ity_I1);
4099         if (tyData == Ity_I32 || (tyData == Ity_I64 && mode64)) {
4100            addInstr(env, PPCInstr_StoreC( tyData==Ity_I32 ? 4 : 8,
4101                                           r_a, r_src, mode64 ));
4102            addInstr(env, PPCInstr_MfCR( r_tmp ));
4103            addInstr(env, PPCInstr_Shft(
4104                             Pshft_SHR,
4105                             env->mode64 ? False : True
4106                                /*F:64-bit, T:32-bit shift*/,
4107                             r_tmp, r_tmp,
4108                             PPCRH_Imm(False/*unsigned*/, 29)));
4109            /* Probably unnecessary, since the IR dest type is Ity_I1,
4110               and so we are entitled to leave whatever junk we like
4111               drifting round in the upper 31 or 63 bits of r_res.
4112               However, for the sake of conservativeness .. */
4113            addInstr(env, PPCInstr_Alu(
4114                             Palu_AND,
4115                             r_res, r_tmp,
4116                             PPCRH_Imm(False/*signed*/, 1)));
4117            return;
4118         }
4119         /* fallthru */
4120      }
4121      goto stmt_fail;
4122      /*NOTREACHED*/
4123   }
4124
4125   /* --------- Call to DIRTY helper --------- */
4126   case Ist_Dirty: {
4127      IRType   retty;
4128      IRDirty* d = stmt->Ist.Dirty.details;
4129      Bool     passBBP = False;
4130
4131      if (d->nFxState == 0)
4132         vassert(!d->needsBBP);
4133      passBBP = toBool(d->nFxState > 0 && d->needsBBP);
4134
4135      /* Marshal args, do the call, clear stack. */
4136      doHelperCall( env, passBBP, d->guard, d->cee, d->args );
4137
4138      /* Now figure out what to do with the returned value, if any. */
4139      if (d->tmp == IRTemp_INVALID)
4140         /* No return value.  Nothing to do. */
4141         return;
4142
4143      retty = typeOfIRTemp(env->type_env, d->tmp);
4144      if (!mode64 && retty == Ity_I64) {
4145         HReg r_dstHi, r_dstLo;
4146         /* The returned value is in %r3:%r4.  Park it in the
4147            register-pair associated with tmp. */
4148         lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
4149         addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
4150         addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
4151         return;
4152      }
4153      if (retty == Ity_I8  || retty == Ity_I16 ||
4154          retty == Ity_I32 || ((retty == Ity_I64) && mode64)) {
4155         /* The returned value is in %r3.  Park it in the register
4156            associated with tmp. */
4157         HReg r_dst = lookupIRTemp(env, d->tmp);
4158         addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
4159         return;
4160      }
4161      break;
4162   }
4163
4164   /* --------- MEM FENCE --------- */
4165   case Ist_MBE:
4166      switch (stmt->Ist.MBE.event) {
4167         case Imbe_Fence:
4168            addInstr(env, PPCInstr_MFence());
4169            return;
4170         default:
4171            break;
4172      }
4173      break;
4174
4175   /* --------- INSTR MARK --------- */
4176   /* Doesn't generate any executable code ... */
4177   case Ist_IMark:
4178       return;
4179
4180   /* --------- ABI HINT --------- */
4181   /* These have no meaning (denotation in the IR) and so we ignore
4182      them ... if any actually made it this far. */
4183   case Ist_AbiHint:
4184       return;
4185
4186   /* --------- NO-OP --------- */
4187   /* Fairly self-explanatory, wouldn't you say? */
4188   case Ist_NoOp:
4189       return;
4190
4191   /* --------- EXIT --------- */
4192   case Ist_Exit: {
4193      PPCRI*      ri_dst;
4194      PPCCondCode cc;
4195      IRConstTag tag = stmt->Ist.Exit.dst->tag;
4196      if (!mode64 && (tag != Ico_U32))
4197         vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
4198      if (mode64 && (tag != Ico_U64))
4199         vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
4200      ri_dst = iselWordExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
4201      cc     = iselCondCode(env,stmt->Ist.Exit.guard);
4202      addInstr(env, PPCInstr_RdWrLR(True, env->savedLR));
4203      addInstr(env, PPCInstr_Goto(stmt->Ist.Exit.jk, cc, ri_dst));
4204      return;
4205   }
4206
4207   default: break;
4208   }
4209  stmt_fail:
4210   ppIRStmt(stmt);
4211   vpanic("iselStmt(ppc)");
4212}
4213
4214
4215/*---------------------------------------------------------*/
4216/*--- ISEL: Basic block terminators (Nexts)             ---*/
4217/*---------------------------------------------------------*/
4218
4219static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
4220{
4221   PPCCondCode cond;
4222   PPCRI* ri;
4223   if (vex_traceflags & VEX_TRACE_VCODE) {
4224      vex_printf("\n-- goto {");
4225      ppIRJumpKind(jk);
4226      vex_printf("} ");
4227      ppIRExpr(next);
4228      vex_printf("\n");
4229   }
4230   cond = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
4231   ri = iselWordExpr_RI(env, next);
4232   addInstr(env, PPCInstr_RdWrLR(True, env->savedLR));
4233   addInstr(env, PPCInstr_Goto(jk, cond, ri));
4234}
4235
4236
4237/*---------------------------------------------------------*/
4238/*--- Insn selector top-level                           ---*/
4239/*---------------------------------------------------------*/
4240
4241/* Translate an entire BS to ppc code. */
4242
4243HInstrArray* iselSB_PPC ( IRSB* bb, VexArch      arch_host,
4244                                    VexArchInfo* archinfo_host,
4245                                    VexAbiInfo*  vbi )
4246{
4247   Int      i, j;
4248   HReg     hreg, hregHI;
4249   ISelEnv* env;
4250   UInt     hwcaps_host = archinfo_host->hwcaps;
4251   Bool     mode64 = False;
4252   UInt     mask32, mask64;
4253
4254   vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
4255   mode64 = arch_host == VexArchPPC64;
4256
4257   /* do some sanity checks */
4258   mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
4259            | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX;
4260
4261   mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
4262	   | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX;
4263
4264   if (mode64) {
4265      vassert((hwcaps_host & mask32) == 0);
4266   } else {
4267      vassert((hwcaps_host & mask64) == 0);
4268   }
4269
4270   /* Make up an initial environment to use. */
4271   env = LibVEX_Alloc(sizeof(ISelEnv));
4272   env->vreg_ctr = 0;
4273
4274   /* Are we being ppc32 or ppc64? */
4275   env->mode64 = mode64;
4276
4277   /* Set up output code array. */
4278   env->code = newHInstrArray();
4279
4280   /* Copy BB's type env. */
4281   env->type_env = bb->tyenv;
4282
4283   /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
4284      change as we go along. */
4285   env->n_vregmap = bb->tyenv->types_used;
4286   env->vregmap   = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4287   env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4288
4289   /* and finally ... */
4290   env->hwcaps      = hwcaps_host;
4291   env->previous_rm = NULL;
4292   env->vbi         = vbi;
4293
4294   /* For each IR temporary, allocate a suitably-kinded virtual
4295      register. */
4296   j = 0;
4297   for (i = 0; i < env->n_vregmap; i++) {
4298      hregHI = hreg = INVALID_HREG;
4299      switch (bb->tyenv->types[i]) {
4300      case Ity_I1:
4301      case Ity_I8:
4302      case Ity_I16:
4303      case Ity_I32:
4304         if (mode64) { hreg   = mkHReg(j++, HRcInt64,  True); break;
4305         } else {      hreg   = mkHReg(j++, HRcInt32,  True); break;
4306         }
4307      case Ity_I64:
4308         if (mode64) { hreg   = mkHReg(j++, HRcInt64,  True); break;
4309         } else {      hreg   = mkHReg(j++, HRcInt32,  True);
4310                       hregHI = mkHReg(j++, HRcInt32,  True); break;
4311         }
4312      case Ity_I128:   vassert(mode64);
4313                       hreg   = mkHReg(j++, HRcInt64,  True);
4314                       hregHI = mkHReg(j++, HRcInt64,  True); break;
4315      case Ity_F32:
4316      case Ity_F64:    hreg   = mkHReg(j++, HRcFlt64,  True); break;
4317      case Ity_V128:   hreg   = mkHReg(j++, HRcVec128, True); break;
4318      default:
4319         ppIRType(bb->tyenv->types[i]);
4320         vpanic("iselBB(ppc): IRTemp type");
4321      }
4322      env->vregmap[i]   = hreg;
4323      env->vregmapHI[i] = hregHI;
4324   }
4325   env->vreg_ctr = j;
4326
4327   /* Keep a copy of the link reg, so helper functions don't kill it. */
4328   env->savedLR = newVRegI(env);
4329   addInstr(env, PPCInstr_RdWrLR(False, env->savedLR));
4330
4331   /* Ok, finally we can iterate over the statements. */
4332   for (i = 0; i < bb->stmts_used; i++)
4333      if (bb->stmts[i])
4334         iselStmt(env,bb->stmts[i]);
4335
4336   iselNext(env,bb->next,bb->jumpkind);
4337
4338   /* record the number of vregs we used. */
4339   env->code->n_vregs = env->vreg_ctr;
4340   return env->code;
4341}
4342
4343
4344/*---------------------------------------------------------------*/
4345/*--- end                                     host_ppc_isel.c ---*/
4346/*---------------------------------------------------------------*/
4347