]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/VEX/priv/host_ppc_isel.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / VEX / priv / host_ppc_isel.c
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-2010 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
119 What                 exns -> CR1 ?   Sets FPRF ?   Observes RM ?
120 -------------------------------------------------------------
121
122 fmr[.]                   if .             n             n
123 fneg[.]                  if .             n             n
124 fabs[.]                  if .             n             n
125 fnabs[.]                 if .             n             n
126
127 fadd[.]                  if .             y             y
128 fadds[.]                 if .             y             y
129 fcfid[.] (Si64->dbl)     if .             y             y
130 fcfidU[.] (Ui64->dbl)    if .             y             y
131 fcfids[.] (Si64->sngl)   if .             Y             Y
132 fcfidus[.] (Ui64->sngl)  if .             Y             Y
133 fcmpo (cmp, result       n                n             n
134 fcmpu  to crfD)          n                n             n
135 fctid[.]  (dbl->i64)     if .       ->undef             y
136 fctidz[.] (dbl->i64)     if .       ->undef    rounds-to-zero
137 fctiw[.]  (dbl->i32)     if .       ->undef             y
138 fctiwz[.] (dbl->i32)     if .       ->undef    rounds-to-zero
139 fdiv[.]                  if .             y             y
140 fdivs[.]                 if .             y             y
141 fmadd[.]                 if .             y             y
142 fmadds[.]                if .             y             y
143 fmsub[.]                 if .             y             y
144 fmsubs[.]                if .             y             y
145 fmul[.]                  if .             y             y
146 fmuls[.]                 if .             y             y
147
148 (note: for fnm*, rounding happens before final negation)
149 fnmadd[.]                if .             y             y
150 fnmadds[.]               if .             y             y
151 fnmsub[.]                if .             y             y
152 fnmsubs[.]               if .             y             y
153
154 fre[.]                   if .             y             y
155 fres[.]                  if .             y             y
156
157 frsqrte[.]               if .             y       apparently not
158
159 fsqrt[.]                 if .             y             y
160 fsqrts[.]                if .             y             y
161 fsub[.]                  if .             y             y
162 fsubs[.]                 if .             y             y
163
164
165 fpscr: 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
169 ppc fe(guest) makes fpscr read as all zeros except RM (and maybe FPRF
170 in future) 
171
172 mcrfs     - move fpscr field to CR field
173 mtfsfi[.] - 4 bit imm moved to fpscr field
174 mtfsf[.]  - move frS[low 1/2] to fpscr but using 8-bit field mask
175 mtfsb1[.] - set given fpscr bit
176 mtfsb0[.] - clear given fpscr bit
177 mffs[.]   - move all fpscr to frD[low 1/2]
178
179 For [.] presumably cr1 is set with exn summary bits, as per 
180 main FP insns
181
182 A single precision store truncates/denormalises the in-register value,
183 but does not round it.  This is so that flds followed by fsts is
184 always the identity.
185 */
186
187
188 /*---------------------------------------------------------*/
189 /*--- misc helpers                                      ---*/
190 /*---------------------------------------------------------*/
191
192 /* These are duplicated in guest-ppc/toIR.c */
193 static IRExpr* unop ( IROp op, IRExpr* a )
194 {
195    return IRExpr_Unop(op, a);
196 }
197
198 static IRExpr* mkU32 ( UInt i )
199 {
200    return IRExpr_Const(IRConst_U32(i));
201 }
202
203 static 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  
253 typedef
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  
279 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
280 {
281    vassert(tmp >= 0);
282    vassert(tmp < env->n_vregmap);
283    return env->vregmap[tmp];
284 }
285
286 static 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
297 static 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
306 static 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
314 static 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
321 static 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. */
346 static HReg          iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e );
347 static 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 */
358 static PPCRH*        iselWordExpr_RH_wrk ( ISelEnv* env, 
359                                            Bool syned, IRExpr* e );
360 static 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). */
365 static PPCRI*        iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e );
366 static 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. */
371 static PPCRH*        iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e );
372 static 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. */
377 static PPCRH*        iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e );
378 static 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. */
391 static PPCAMode*     iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy );
392 static PPCAMode*     iselWordExpr_AMode     ( ISelEnv* env, IRExpr* e, IRType xferTy );
393
394 /* 32-bit mode ONLY: compute an I64 into a GPR pair. */
395 static void          iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, 
396                                          ISelEnv* env, IRExpr* e );
397 static void          iselInt64Expr     ( HReg* rHi, HReg* rLo, 
398                                          ISelEnv* env, IRExpr* e );
399
400 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
401 static void          iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, 
402                                           ISelEnv* env, IRExpr* e );
403 static void          iselInt128Expr     ( HReg* rHi, HReg* rLo, 
404                                           ISelEnv* env, IRExpr* e );
405
406 static PPCCondCode   iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
407 static PPCCondCode   iselCondCode     ( ISelEnv* env, IRExpr* e );
408
409 static HReg          iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );
410 static HReg          iselDblExpr     ( ISelEnv* env, IRExpr* e );
411
412 static HReg          iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );
413 static HReg          iselFltExpr     ( ISelEnv* env, IRExpr* e );
414
415 static HReg          iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );
416 static HReg          iselVecExpr     ( ISelEnv* env, IRExpr* e );
417
418
419 /*---------------------------------------------------------*/
420 /*--- ISEL: Misc helpers                                ---*/
421 /*---------------------------------------------------------*/
422
423 /* Make an int reg-reg move. */
424
425 static 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
435 static 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
443 static 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 */
457 static 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 */
475 static 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 */
501 static 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
526 static 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.  */
542 static
543 PPCAMode* 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 */
609 static
610 Bool 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
625 static
626 void 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 */
888 static 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 */
949 static
950 void 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 */
993 static 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 */
1002 static 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 */
1018 static 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 */
1098 static 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
1142 static 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 ! */
1156 static 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          Bool syned  = toBool(e->Iex.Binop.op == Iop_DivS32);
1289          HReg r_dst  = newVRegI(env);
1290          HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1291          HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1292          addInstr(env, PPCInstr_Div(syned, True/*32bit div*/,
1293                                     r_dst, r_srcL, r_srcR));
1294          return r_dst;
1295       }
1296       if (e->Iex.Binop.op == Iop_DivS64 || 
1297           e->Iex.Binop.op == Iop_DivU64) {
1298          Bool syned  = toBool(e->Iex.Binop.op == Iop_DivS64);
1299          HReg r_dst  = newVRegI(env);
1300          HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1301          HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1302          vassert(mode64);
1303          addInstr(env, PPCInstr_Div(syned, False/*64bit div*/,
1304                                     r_dst, r_srcL, r_srcR));
1305          return r_dst;
1306       }
1307
1308       /* No? Anyone for a mul? */
1309       if (e->Iex.Binop.op == Iop_Mul32
1310           || e->Iex.Binop.op == Iop_Mul64) {
1311          Bool syned       = False;
1312          Bool sz32        = (e->Iex.Binop.op != Iop_Mul64);
1313          HReg r_dst       = newVRegI(env);
1314          HReg r_srcL      = iselWordExpr_R(env, e->Iex.Binop.arg1);
1315          HReg r_srcR      = iselWordExpr_R(env, e->Iex.Binop.arg2);
1316          addInstr(env, PPCInstr_MulL(syned, False/*lo32*/, sz32,
1317                                      r_dst, r_srcL, r_srcR));
1318          return r_dst;
1319       }      
1320
1321       /* 32 x 32 -> 64 multiply */
1322       if (mode64
1323           && (e->Iex.Binop.op == Iop_MullU32
1324               || e->Iex.Binop.op == Iop_MullS32)) {
1325          HReg tLo    = newVRegI(env);
1326          HReg tHi    = newVRegI(env);
1327          HReg r_dst  = newVRegI(env);
1328          Bool syned  = toBool(e->Iex.Binop.op == Iop_MullS32);
1329          HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1330          HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1331          addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 
1332                                      False/*lo32*/, True/*32bit mul*/,
1333                                      tLo, r_srcL, r_srcR));
1334          addInstr(env, PPCInstr_MulL(syned,
1335                                      True/*hi32*/, True/*32bit mul*/,
1336                                      tHi, r_srcL, r_srcR));
1337          addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1338                                      r_dst, tHi, PPCRH_Imm(False,32)));
1339          addInstr(env, PPCInstr_Alu(Palu_OR,
1340                                     r_dst, r_dst, PPCRH_Reg(tLo)));
1341          return r_dst;
1342       }
1343
1344       /* El-mutanto 3-way compare? */
1345       if (e->Iex.Binop.op == Iop_CmpORD32S
1346           || e->Iex.Binop.op == Iop_CmpORD32U) {
1347          Bool   syned = toBool(e->Iex.Binop.op == Iop_CmpORD32S);
1348          HReg   dst   = newVRegI(env);
1349          HReg   srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1350          PPCRH* srcR  = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
1351          addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
1352                                     7/*cr*/, srcL, srcR));
1353          addInstr(env, PPCInstr_MfCR(dst));
1354          addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1355                                     PPCRH_Imm(False,7<<1)));
1356          return dst;
1357       }
1358
1359       if (e->Iex.Binop.op == Iop_CmpORD64S
1360           || e->Iex.Binop.op == Iop_CmpORD64U) {
1361          Bool   syned = toBool(e->Iex.Binop.op == Iop_CmpORD64S);
1362          HReg   dst   = newVRegI(env);
1363          HReg   srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1364          PPCRH* srcR  = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
1365          vassert(mode64);
1366          addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
1367                                     7/*cr*/, srcL, srcR));
1368          addInstr(env, PPCInstr_MfCR(dst));
1369          addInstr(env, PPCInstr_Alu(Palu_AND, dst, dst,
1370                                     PPCRH_Imm(False,7<<1)));
1371          return dst;
1372       }
1373
1374       if (e->Iex.Binop.op == Iop_Max32U) {
1375          HReg        r1   = iselWordExpr_R(env, e->Iex.Binop.arg1);
1376          HReg        r2   = iselWordExpr_R(env, e->Iex.Binop.arg2);
1377          HReg        rdst = newVRegI(env);
1378          PPCCondCode cc   = mk_PPCCondCode( Pct_TRUE, Pcf_7LT );
1379          addInstr(env, mk_iMOVds_RR(rdst, r1));
1380          addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1381                                     7/*cr*/, rdst, PPCRH_Reg(r2)));
1382          addInstr(env, PPCInstr_CMov(cc, rdst, PPCRI_Reg(r2)));
1383          return rdst;
1384       }
1385
1386       if (e->Iex.Binop.op == Iop_32HLto64) {
1387          HReg   r_Hi  = iselWordExpr_R(env, e->Iex.Binop.arg1);
1388          HReg   r_Lo  = iselWordExpr_R(env, e->Iex.Binop.arg2);
1389          HReg   r_dst = newVRegI(env);
1390          HReg   msk   = newVRegI(env);
1391          vassert(mode64);
1392          /* r_dst = OR( r_Hi<<32, r_Lo ) */
1393          addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1394                                      r_dst, r_Hi, PPCRH_Imm(False,32)));
1395          addInstr(env, PPCInstr_LI(msk, 0xFFFFFFFF, mode64));
1396          addInstr(env, PPCInstr_Alu( Palu_AND, r_Lo, r_Lo,
1397                                      PPCRH_Reg(msk) ));
1398          addInstr(env, PPCInstr_Alu( Palu_OR, r_dst, r_dst,
1399                                      PPCRH_Reg(r_Lo) ));
1400          return r_dst;
1401       }
1402
1403       if (e->Iex.Binop.op == Iop_CmpF64) {
1404          HReg fr_srcL    = iselDblExpr(env, e->Iex.Binop.arg1);
1405          HReg fr_srcR    = iselDblExpr(env, e->Iex.Binop.arg2);
1406
1407          HReg r_ccPPC   = newVRegI(env);
1408          HReg r_ccIR    = newVRegI(env);
1409          HReg r_ccIR_b0 = newVRegI(env);
1410          HReg r_ccIR_b2 = newVRegI(env);
1411          HReg r_ccIR_b6 = newVRegI(env);
1412
1413          addInstr(env, PPCInstr_FpCmp(r_ccPPC, fr_srcL, fr_srcR));
1414
1415          /* Map compare result from PPC to IR,
1416             conforming to CmpF64 definition. */
1417          /*
1418            FP cmp result | PPC | IR
1419            --------------------------
1420            UN            | 0x1 | 0x45
1421            EQ            | 0x2 | 0x40
1422            GT            | 0x4 | 0x00
1423            LT            | 0x8 | 0x01
1424          */
1425
1426          // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
1427          addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1428                                      r_ccIR_b0, r_ccPPC,
1429                                      PPCRH_Imm(False,0x3)));
1430          addInstr(env, PPCInstr_Alu(Palu_OR,  r_ccIR_b0,
1431                                     r_ccPPC,   PPCRH_Reg(r_ccIR_b0)));
1432          addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b0,
1433                                     r_ccIR_b0, PPCRH_Imm(False,0x1)));
1434          
1435          // r_ccIR_b2 = r_ccPPC[0]
1436          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1437                                      r_ccIR_b2, r_ccPPC,
1438                                      PPCRH_Imm(False,0x2)));
1439          addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b2,
1440                                     r_ccIR_b2, PPCRH_Imm(False,0x4)));
1441
1442          // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
1443          addInstr(env, PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1444                                      r_ccIR_b6, r_ccPPC,
1445                                      PPCRH_Imm(False,0x1)));
1446          addInstr(env, PPCInstr_Alu(Palu_OR,  r_ccIR_b6,
1447                                     r_ccPPC, PPCRH_Reg(r_ccIR_b6)));
1448          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1449                                      r_ccIR_b6, r_ccIR_b6,
1450                                      PPCRH_Imm(False,0x6)));
1451          addInstr(env, PPCInstr_Alu(Palu_AND, r_ccIR_b6,
1452                                     r_ccIR_b6, PPCRH_Imm(False,0x40)));
1453
1454          // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
1455          addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1456                                     r_ccIR_b0, PPCRH_Reg(r_ccIR_b2)));
1457          addInstr(env, PPCInstr_Alu(Palu_OR, r_ccIR,
1458                                     r_ccIR,    PPCRH_Reg(r_ccIR_b6)));
1459          return r_ccIR;
1460       }
1461
1462       if (e->Iex.Binop.op == Iop_F64toI32S) {
1463          /* This works in both mode64 and mode32. */
1464          HReg      r1      = StackFramePtr(env->mode64);
1465          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1466          HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2);
1467          HReg      ftmp    = newVRegF(env);
1468          HReg      idst    = newVRegI(env);
1469
1470          /* Set host rounding mode */
1471          set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
1472
1473          sub_from_sp( env, 16 );
1474          addInstr(env, PPCInstr_FpCftI(False/*F->I*/, True/*int32*/,
1475                                        True/*syned*/, True/*flt64*/,
1476                                        ftmp, fsrc));
1477          addInstr(env, PPCInstr_FpSTFIW(r1, ftmp));
1478          addInstr(env, PPCInstr_Load(4, idst, zero_r1, mode64));
1479
1480          /* in 64-bit mode we need to sign-widen idst. */
1481          if (mode64)
1482             addInstr(env, PPCInstr_Unary(Pun_EXTSW, idst, idst));
1483
1484          add_to_sp( env, 16 );
1485
1486          ///* Restore default FPU rounding. */
1487          //set_FPU_rounding_default( env );
1488          return idst;
1489       }
1490
1491       if (e->Iex.Binop.op == Iop_F64toI64S) {
1492          if (mode64) {
1493             HReg      r1      = StackFramePtr(env->mode64);
1494             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
1495             HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2);
1496             HReg      idst    = newVRegI(env);         
1497             HReg      ftmp    = newVRegF(env);
1498
1499             /* Set host rounding mode */
1500             set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
1501
1502             sub_from_sp( env, 16 );
1503             addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, True,
1504                                           True, ftmp, fsrc));
1505             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
1506             addInstr(env, PPCInstr_Load(8, idst, zero_r1, True/*mode64*/));
1507             add_to_sp( env, 16 );
1508
1509             ///* Restore default FPU rounding. */
1510             //set_FPU_rounding_default( env );
1511             return idst;
1512          }
1513       }
1514
1515       break;
1516    }
1517
1518    /* --------- UNARY OP --------- */
1519    case Iex_Unop: {
1520       IROp op_unop = e->Iex.Unop.op;
1521
1522       /* 1Uto8(32to1(expr32)) */
1523       DEFINE_PATTERN(p_32to1_then_1Uto8,
1524                      unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1525       if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1526          IRExpr* expr32 = mi.bindee[0];
1527          HReg r_dst = newVRegI(env);
1528          HReg r_src = iselWordExpr_R(env, expr32);
1529          addInstr(env, PPCInstr_Alu(Palu_AND, r_dst,
1530                                     r_src, PPCRH_Imm(False,1)));
1531          return r_dst;
1532       }
1533
1534       /* 16Uto32(LDbe:I16(expr32)) */
1535       {
1536          DECLARE_PATTERN(p_LDbe16_then_16Uto32);
1537          DEFINE_PATTERN(p_LDbe16_then_16Uto32,
1538                         unop(Iop_16Uto32,
1539                              IRExpr_Load(Iend_BE,Ity_I16,bind(0))) );
1540          if (matchIRExpr(&mi,p_LDbe16_then_16Uto32,e)) {
1541             HReg r_dst = newVRegI(env);
1542             PPCAMode* amode
1543                = iselWordExpr_AMode( env, mi.bindee[0], Ity_I16/*xfer*/ );
1544             addInstr(env, PPCInstr_Load(2,r_dst,amode, mode64));
1545             return r_dst;
1546          }
1547       }
1548
1549       switch (op_unop) {
1550       case Iop_8Uto16:
1551       case Iop_8Uto32:
1552       case Iop_8Uto64:
1553       case Iop_16Uto32:
1554       case Iop_16Uto64: {
1555          HReg   r_dst = newVRegI(env);
1556          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1557          UShort mask  = toUShort(op_unop==Iop_16Uto64 ? 0xFFFF :
1558                                  op_unop==Iop_16Uto32 ? 0xFFFF : 0xFF);
1559          addInstr(env, PPCInstr_Alu(Palu_AND,r_dst,r_src,
1560                                     PPCRH_Imm(False,mask)));
1561          return r_dst;
1562       }
1563       case Iop_32Uto64: {
1564          HReg r_dst = newVRegI(env);
1565          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1566          vassert(mode64);
1567          addInstr(env,
1568                   PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1569                                 r_dst, r_src, PPCRH_Imm(False,32)));
1570          addInstr(env,
1571                   PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1572                                 r_dst, r_dst, PPCRH_Imm(False,32)));
1573          return r_dst;
1574       }
1575       case Iop_8Sto16:
1576       case Iop_8Sto32:
1577       case Iop_16Sto32: {
1578          HReg   r_dst = newVRegI(env);
1579          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1580          UShort amt   = toUShort(op_unop==Iop_16Sto32 ? 16 : 24);
1581          addInstr(env,
1582                   PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1583                                 r_dst, r_src, PPCRH_Imm(False,amt)));
1584          addInstr(env,
1585                   PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1586                                 r_dst, r_dst, PPCRH_Imm(False,amt)));
1587          return r_dst;
1588       }
1589       case Iop_8Sto64:
1590       case Iop_16Sto64: {
1591          HReg   r_dst = newVRegI(env);
1592          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1593          UShort amt   = toUShort(op_unop==Iop_8Sto64  ? 56 :
1594                                  op_unop==Iop_16Sto64 ? 48 : 32);
1595          vassert(mode64);
1596          addInstr(env,
1597                   PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1598                                 r_dst, r_src, PPCRH_Imm(False,amt)));
1599          addInstr(env,
1600                   PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1601                                 r_dst, r_dst, PPCRH_Imm(False,amt)));
1602          return r_dst;
1603       }
1604       case Iop_32Sto64: {
1605          HReg   r_dst = newVRegI(env);
1606          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1607          vassert(mode64);
1608          /* According to the IBM docs, in 64 bit mode, srawi r,r,0
1609             sign extends the lower 32 bits into the upper 32 bits. */
1610          addInstr(env,
1611                   PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1612                                 r_dst, r_src, PPCRH_Imm(False,0)));
1613          return r_dst;
1614       }
1615       case Iop_Not8:
1616       case Iop_Not16:
1617       case Iop_Not32:
1618       case Iop_Not64: {
1619          if (op_unop == Iop_Not64) vassert(mode64);
1620          HReg r_dst = newVRegI(env);
1621          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1622          addInstr(env, PPCInstr_Unary(Pun_NOT,r_dst,r_src));
1623          return r_dst;
1624       }
1625       case Iop_64HIto32: {
1626          if (!mode64) {
1627             HReg rHi, rLo;
1628             iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1629             return rHi; /* and abandon rLo .. poor wee thing :-) */
1630          } else {
1631             HReg   r_dst = newVRegI(env);
1632             HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1633             addInstr(env,
1634                      PPCInstr_Shft(Pshft_SHR, False/*64bit shift*/,
1635                                    r_dst, r_src, PPCRH_Imm(False,32)));
1636             return r_dst;
1637          }
1638       }
1639       case Iop_64to32: {
1640          if (!mode64) {
1641             HReg rHi, rLo;
1642             iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1643             return rLo; /* similar stupid comment to the above ... */
1644          } else {
1645             /* This is a no-op. */
1646             return iselWordExpr_R(env, e->Iex.Unop.arg);
1647          }
1648       }
1649       case Iop_64to16: {
1650          if (mode64) { /* This is a no-op. */
1651             return iselWordExpr_R(env, e->Iex.Unop.arg);
1652          }
1653          break; /* evidently not used in 32-bit mode */
1654       }
1655       case Iop_16HIto8:
1656       case Iop_32HIto16: {
1657          HReg   r_dst = newVRegI(env);
1658          HReg   r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1659          UShort shift = toUShort(op_unop == Iop_16HIto8 ? 8 : 16);
1660          addInstr(env,
1661                   PPCInstr_Shft(Pshft_SHR, True/*32bit shift*/,
1662                                 r_dst, r_src, PPCRH_Imm(False,shift)));
1663          return r_dst;
1664       }
1665       case Iop_128HIto64: 
1666          if (mode64) {
1667             HReg rHi, rLo;
1668             iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1669             return rHi; /* and abandon rLo .. poor wee thing :-) */
1670          }
1671          break;
1672       case Iop_128to64:
1673          if (mode64) {
1674             HReg rHi, rLo;
1675             iselInt128Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1676             return rLo; /* similar stupid comment to the above ... */
1677          }
1678          break;
1679       case Iop_1Uto32:
1680       case Iop_1Uto8: {
1681          HReg        r_dst = newVRegI(env);
1682          PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg);
1683          addInstr(env, PPCInstr_Set(cond,r_dst));
1684          return r_dst;
1685       }
1686       case Iop_1Sto8:
1687       case Iop_1Sto16:
1688       case Iop_1Sto32: {
1689          /* could do better than this, but for now ... */
1690          HReg        r_dst = newVRegI(env);
1691          PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg);
1692          addInstr(env, PPCInstr_Set(cond,r_dst));
1693          addInstr(env,
1694                   PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
1695                                 r_dst, r_dst, PPCRH_Imm(False,31)));
1696          addInstr(env,
1697                   PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
1698                                 r_dst, r_dst, PPCRH_Imm(False,31)));
1699          return r_dst;
1700       }
1701       case Iop_1Sto64: 
1702          if (mode64) {
1703             /* could do better than this, but for now ... */
1704             HReg        r_dst = newVRegI(env);
1705             PPCCondCode cond  = iselCondCode(env, e->Iex.Unop.arg);
1706             addInstr(env, PPCInstr_Set(cond,r_dst));
1707             addInstr(env, PPCInstr_Shft(Pshft_SHL, False/*64bit shift*/,
1708                                         r_dst, r_dst, PPCRH_Imm(False,63)));
1709             addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/,
1710                                         r_dst, r_dst, PPCRH_Imm(False,63)));
1711             return r_dst;
1712          }
1713          break;
1714       case Iop_Clz32:
1715       case Iop_Clz64: {
1716          HReg r_src, r_dst;
1717          PPCUnaryOp op_clz = (op_unop == Iop_Clz32) ? Pun_CLZ32 :
1718                                                       Pun_CLZ64;
1719          if (op_unop == Iop_Clz64 && !mode64)
1720             goto irreducible;
1721          /* Count leading zeroes. */
1722          r_dst = newVRegI(env);
1723          r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1724          addInstr(env, PPCInstr_Unary(op_clz,r_dst,r_src));
1725          return r_dst;
1726       }
1727
1728       case Iop_Left8:
1729       case Iop_Left32: 
1730       case Iop_Left64: {
1731          HReg r_src, r_dst;
1732          if (op_unop == Iop_Left64 && !mode64)
1733             goto irreducible;
1734          r_dst = newVRegI(env);
1735          r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1736          addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1737          addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1738          return r_dst;
1739       }
1740
1741       case Iop_CmpwNEZ32: {
1742          HReg r_dst = newVRegI(env);
1743          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1744          addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1745          addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1746          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 
1747                                      r_dst, r_dst, PPCRH_Imm(False, 31)));
1748          return r_dst;
1749       }
1750
1751       case Iop_CmpwNEZ64: {
1752          HReg r_dst = newVRegI(env);
1753          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1754          if (!mode64) goto irreducible;
1755          addInstr(env, PPCInstr_Unary(Pun_NEG,r_dst,r_src));
1756          addInstr(env, PPCInstr_Alu(Palu_OR, r_dst, r_dst, PPCRH_Reg(r_src)));
1757          addInstr(env, PPCInstr_Shft(Pshft_SAR, False/*64bit shift*/, 
1758                                      r_dst, r_dst, PPCRH_Imm(False, 63)));
1759          return r_dst;
1760       }
1761
1762       case Iop_V128to32: {
1763          HReg        r_aligned16;
1764          HReg        dst  = newVRegI(env);
1765          HReg        vec  = iselVecExpr(env, e->Iex.Unop.arg);
1766          PPCAMode *am_off0, *am_off12;
1767          sub_from_sp( env, 32 );     // Move SP down 32 bytes
1768
1769          // get a quadword aligned address within our stack space
1770          r_aligned16 = get_sp_aligned16( env );
1771          am_off0  = PPCAMode_IR( 0, r_aligned16 );
1772          am_off12 = PPCAMode_IR( 12,r_aligned16 );
1773
1774          // store vec, load low word to dst
1775          addInstr(env,
1776                   PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
1777          addInstr(env,
1778                   PPCInstr_Load( 4, dst, am_off12, mode64 ));
1779
1780          add_to_sp( env, 32 );       // Reset SP
1781          return dst;
1782       }
1783
1784       case Iop_V128to64:
1785       case Iop_V128HIto64: 
1786          if (mode64) {
1787             HReg     r_aligned16;
1788             HReg     dst = newVRegI(env);
1789             HReg     vec = iselVecExpr(env, e->Iex.Unop.arg);
1790             PPCAMode *am_off0, *am_off8;
1791             sub_from_sp( env, 32 );     // Move SP down 32 bytes
1792
1793             // get a quadword aligned address within our stack space
1794             r_aligned16 = get_sp_aligned16( env );
1795             am_off0 = PPCAMode_IR( 0, r_aligned16 );
1796             am_off8 = PPCAMode_IR( 8 ,r_aligned16 );
1797
1798             // store vec, load low word (+8) or high (+0) to dst
1799             addInstr(env,
1800                      PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
1801             addInstr(env,
1802                      PPCInstr_Load( 
1803                         8, dst, 
1804                         op_unop == Iop_V128HIto64 ? am_off0 : am_off8, 
1805                         mode64 ));
1806
1807             add_to_sp( env, 32 );       // Reset SP
1808             return dst;
1809          }
1810          break;
1811       case Iop_16to8:
1812       case Iop_32to8:
1813       case Iop_32to16:
1814       case Iop_64to8:
1815          /* These are no-ops. */
1816          return iselWordExpr_R(env, e->Iex.Unop.arg);
1817          
1818       /* ReinterpF64asI64(e) */
1819       /* Given an IEEE754 double, produce an I64 with the same bit
1820          pattern. */
1821       case Iop_ReinterpF64asI64: 
1822          if (mode64) {
1823             PPCAMode *am_addr;
1824             HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
1825             HReg r_dst  = newVRegI(env);
1826
1827             sub_from_sp( env, 16 );     // Move SP down 16 bytes
1828             am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
1829
1830             // store as F64
1831             addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
1832                                            fr_src, am_addr ));
1833             // load as Ity_I64
1834             addInstr(env, PPCInstr_Load( 8, r_dst, am_addr, mode64 ));
1835
1836             add_to_sp( env, 16 );       // Reset SP
1837             return r_dst;
1838          }
1839          break;
1840
1841       /* ReinterpF32asI32(e) */
1842       /* Given an IEEE754 float, produce an I32 with the same bit
1843          pattern. */
1844       case Iop_ReinterpF32asI32: {
1845          /* I believe this generates correct code for both 32- and
1846             64-bit hosts. */
1847          PPCAMode *am_addr;
1848          HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1849          HReg r_dst  = newVRegI(env);
1850
1851          sub_from_sp( env, 16 );     // Move SP down 16 bytes
1852          am_addr = PPCAMode_IR( 0, StackFramePtr(mode64) );
1853
1854          // store as F32
1855          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
1856                                         fr_src, am_addr ));
1857          // load as Ity_I32
1858          addInstr(env, PPCInstr_Load( 4, r_dst, am_addr, mode64 ));
1859
1860          add_to_sp( env, 16 );       // Reset SP
1861          return r_dst;
1862       }
1863
1864       default: 
1865          break;
1866       }
1867       break;
1868    }
1869
1870    /* --------- GET --------- */
1871    case Iex_Get: {
1872       if (ty == Ity_I8  || ty == Ity_I16 ||
1873           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
1874          HReg r_dst = newVRegI(env);
1875          PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
1876                                           GuestStatePtr(mode64) );
1877          addInstr(env, PPCInstr_Load( toUChar(sizeofIRType(ty)), 
1878                                       r_dst, am_addr, mode64 ));
1879          return r_dst;
1880       }
1881       break;
1882    }
1883
1884    case Iex_GetI: {
1885       PPCAMode* src_am
1886          = genGuestArrayOffset( env, e->Iex.GetI.descr,
1887                                      e->Iex.GetI.ix, e->Iex.GetI.bias );
1888       HReg r_dst = newVRegI(env);
1889       if (mode64 && ty == Ity_I64) {
1890          addInstr(env, PPCInstr_Load( toUChar(8),
1891                                       r_dst, src_am, mode64 ));
1892          return r_dst;
1893       }
1894       if ((!mode64) && ty == Ity_I32) {
1895          addInstr(env, PPCInstr_Load( toUChar(4),
1896                                       r_dst, src_am, mode64 ));
1897          return r_dst;
1898       }
1899       break;
1900    }
1901
1902    /* --------- CCALL --------- */
1903    case Iex_CCall: {
1904       HReg    r_dst = newVRegI(env);
1905       vassert(ty == Ity_I32);
1906
1907       /* be very restrictive for now.  Only 32/64-bit ints allowed
1908          for args, and 32 bits for return type. */
1909       if (e->Iex.CCall.retty != Ity_I32)
1910          goto irreducible;
1911       
1912       /* Marshal args, do the call, clear stack. */
1913       doHelperCall( env, False, NULL,
1914                     e->Iex.CCall.cee, e->Iex.CCall.args );
1915
1916       /* GPR3 now holds the destination address from Pin_Goto */
1917       addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
1918       return r_dst;
1919    }
1920       
1921    /* --------- LITERAL --------- */
1922    /* 32/16/8-bit literals */
1923    case Iex_Const: {
1924       Long l;
1925       HReg r_dst = newVRegI(env);
1926       IRConst* con = e->Iex.Const.con;
1927       switch (con->tag) {
1928          case Ico_U64: if (!mode64) goto irreducible;
1929                        l = (Long)            con->Ico.U64; break;
1930          case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
1931          case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
1932          case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
1933          default:      vpanic("iselIntExpr_R.const(ppc)");
1934       }
1935       addInstr(env, PPCInstr_LI(r_dst, (ULong)l, mode64));
1936       return r_dst;
1937    }
1938
1939    /* --------- MULTIPLEX --------- */
1940    case Iex_Mux0X: {
1941       if ((ty == Ity_I8  || ty == Ity_I16 ||
1942            ty == Ity_I32 || ((ty == Ity_I64) && mode64)) &&
1943           typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1944          PPCCondCode  cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
1945          HReg   r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
1946          HReg   rX     = iselWordExpr_R(env, e->Iex.Mux0X.exprX);
1947          PPCRI* r0     = iselWordExpr_RI(env, e->Iex.Mux0X.expr0);
1948          HReg   r_dst  = newVRegI(env);
1949          HReg   r_tmp  = newVRegI(env);
1950          addInstr(env, mk_iMOVds_RR(r_dst,rX));
1951          addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp,
1952                                     r_cond, PPCRH_Imm(False,0xFF)));
1953          addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
1954                                     7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
1955          addInstr(env, PPCInstr_CMov(cc,r_dst,r0));
1956          return r_dst;
1957       }
1958       break;
1959    }
1960       
1961    default: 
1962       break;
1963    } /* switch (e->tag) */
1964
1965
1966    /* We get here if no pattern matched. */
1967  irreducible:
1968    ppIRExpr(e);
1969    vpanic("iselIntExpr_R(ppc): cannot reduce tree");
1970 }
1971
1972
1973 /*---------------------------------------------------------*/
1974 /*--- ISEL: Integer expression auxiliaries              ---*/
1975 /*---------------------------------------------------------*/
1976
1977 /* --------------------- AMODEs --------------------- */
1978
1979 /* Return an AMode which computes the value of the specified
1980    expression, possibly also adding insns to the code list as a
1981    result.  The expression may only be a word-size one.
1982 */
1983
1984 static Bool uInt_fits_in_16_bits ( UInt u ) 
1985 {
1986    /* Is u the same as the sign-extend of its lower 16 bits? */
1987    Int i = u & 0xFFFF;
1988    i <<= 16;
1989    i >>= 16;
1990    return toBool(u == (UInt)i);
1991 }
1992
1993 static Bool uLong_fits_in_16_bits ( ULong u ) 
1994 {
1995    /* Is u the same as the sign-extend of its lower 16 bits? */
1996    Long i = u & 0xFFFFULL;
1997    i <<= 48;
1998    i >>= 48;
1999    return toBool(u == (ULong)i);
2000 }
2001
2002 static Bool uLong_is_4_aligned ( ULong u )
2003 {
2004    return toBool((u & 3ULL) == 0);
2005 }
2006
2007 static Bool sane_AMode ( ISelEnv* env, PPCAMode* am )
2008 {
2009    Bool mode64 = env->mode64;
2010    switch (am->tag) {
2011    case Pam_IR:
2012       /* Using uInt_fits_in_16_bits in 64-bit mode seems a bit bogus,
2013          somehow, but I think it's OK. */
2014       return toBool( hregClass(am->Pam.IR.base) == HRcGPR(mode64) && 
2015                      hregIsVirtual(am->Pam.IR.base) && 
2016                      uInt_fits_in_16_bits(am->Pam.IR.index) );
2017    case Pam_RR:
2018       return toBool( hregClass(am->Pam.RR.base) == HRcGPR(mode64) && 
2019                      hregIsVirtual(am->Pam.RR.base) &&
2020                      hregClass(am->Pam.RR.index) == HRcGPR(mode64) &&
2021                      hregIsVirtual(am->Pam.IR.index) );
2022    default:
2023       vpanic("sane_AMode: unknown ppc amode tag");
2024    }
2025 }
2026
2027 static 
2028 PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e, IRType xferTy )
2029 {
2030    PPCAMode* am = iselWordExpr_AMode_wrk(env, e, xferTy);
2031    vassert(sane_AMode(env, am));
2032    return am;
2033 }
2034
2035 /* DO NOT CALL THIS DIRECTLY ! */
2036 static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e, IRType xferTy )
2037 {
2038    IRType ty = typeOfIRExpr(env->type_env,e);
2039
2040    if (env->mode64) {
2041
2042       /* If the data load/store type is I32 or I64, this amode might
2043          be destined for use in ld/ldu/lwa/st/stu.  In which case
2044          insist that if it comes out as an _IR, the immediate must
2045          have its bottom two bits be zero.  This does assume that for
2046          any other type (I8/I16/I128/F32/F64/V128) the amode will not
2047          be parked in any such instruction.  But that seems a
2048          reasonable assumption.  */
2049       Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
2050
2051       vassert(ty == Ity_I64);
2052    
2053       /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
2054       if (e->tag == Iex_Binop 
2055           && e->Iex.Binop.op == Iop_Add64
2056           && e->Iex.Binop.arg2->tag == Iex_Const
2057           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
2058           && (aligned4imm  ? uLong_is_4_aligned(e->Iex.Binop.arg2
2059                                                  ->Iex.Const.con->Ico.U64)
2060                            : True)
2061           && uLong_fits_in_16_bits(e->Iex.Binop.arg2
2062                                     ->Iex.Const.con->Ico.U64)) {
2063          return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
2064                              iselWordExpr_R(env, e->Iex.Binop.arg1) );
2065       }
2066       
2067       /* Add64(expr,expr) */
2068       if (e->tag == Iex_Binop 
2069           && e->Iex.Binop.op == Iop_Add64) {
2070          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
2071          HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2072          return PPCAMode_RR( r_idx, r_base );
2073       }
2074
2075    } else {
2076
2077       vassert(ty == Ity_I32);
2078    
2079       /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
2080       if (e->tag == Iex_Binop 
2081           && e->Iex.Binop.op == Iop_Add32
2082           && e->Iex.Binop.arg2->tag == Iex_Const
2083           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
2084           && uInt_fits_in_16_bits(e->Iex.Binop.arg2
2085                                    ->Iex.Const.con->Ico.U32)) {
2086          return PPCAMode_IR( (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
2087                              iselWordExpr_R(env, e->Iex.Binop.arg1) );
2088       }
2089       
2090       /* Add32(expr,expr) */
2091       if (e->tag == Iex_Binop 
2092           && e->Iex.Binop.op == Iop_Add32) {
2093          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
2094          HReg r_idx  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2095          return PPCAMode_RR( r_idx, r_base );
2096       }
2097
2098    }
2099
2100    /* Doesn't match anything in particular.  Generate it into
2101       a register and use that. */
2102    return PPCAMode_IR( 0, iselWordExpr_R(env,e) );
2103 }
2104
2105
2106 /* --------------------- RH --------------------- */
2107
2108 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2109    (reg-or-halfword-immediate).  It's important to specify whether the
2110    immediate is to be regarded as signed or not.  If yes, this will
2111    never return -32768 as an immediate; this guaranteed that all
2112    signed immediates that are return can have their sign inverted if
2113    need be. */
2114
2115 static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e )
2116 {
2117    PPCRH* ri = iselWordExpr_RH_wrk(env, syned, e);
2118    /* sanity checks ... */
2119    switch (ri->tag) {
2120    case Prh_Imm:
2121       vassert(ri->Prh.Imm.syned == syned);
2122       if (syned)
2123          vassert(ri->Prh.Imm.imm16 != 0x8000);
2124       return ri;
2125    case Prh_Reg:
2126       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2127       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2128       return ri;
2129    default:
2130       vpanic("iselIntExpr_RH: unknown ppc RH tag");
2131    }
2132 }
2133
2134 /* DO NOT CALL THIS DIRECTLY ! */
2135 static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e )
2136 {
2137    ULong u;
2138    Long  l;
2139    IRType ty = typeOfIRExpr(env->type_env,e);
2140    vassert(ty == Ity_I8  || ty == Ity_I16 ||
2141            ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2142
2143    /* special case: immediate */
2144    if (e->tag == Iex_Const) {
2145       IRConst* con = e->Iex.Const.con;
2146       /* What value are we aiming to generate? */
2147       switch (con->tag) {
2148       /* Note: Not sign-extending - we carry 'syned' around */
2149       case Ico_U64: vassert(env->mode64);
2150                     u =              con->Ico.U64; break;
2151       case Ico_U32: u = 0xFFFFFFFF & con->Ico.U32; break;
2152       case Ico_U16: u = 0x0000FFFF & con->Ico.U16; break;
2153       case Ico_U8:  u = 0x000000FF & con->Ico.U8; break;
2154       default:      vpanic("iselIntExpr_RH.Iex_Const(ppch)");
2155       }
2156       l = (Long)u;
2157       /* Now figure out if it's representable. */
2158       if (!syned && u <= 65535) {
2159          return PPCRH_Imm(False/*unsigned*/, toUShort(u & 0xFFFF));
2160       }
2161       if (syned && l >= -32767 && l <= 32767) {
2162          return PPCRH_Imm(True/*signed*/, toUShort(u & 0xFFFF));
2163       }
2164       /* no luck; use the Slow Way. */
2165    }
2166
2167    /* default case: calculate into a register and return that */
2168    return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2169 }
2170
2171
2172 /* --------------------- RIs --------------------- */
2173
2174 /* Calculate an expression into an PPCRI operand.  As with
2175    iselIntExpr_R, the expression can have type 32, 16 or 8 bits, or,
2176    in 64-bit mode, 64 bits. */
2177
2178 static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e )
2179 {
2180    PPCRI* ri = iselWordExpr_RI_wrk(env, e);
2181    /* sanity checks ... */
2182    switch (ri->tag) {
2183    case Pri_Imm:
2184       return ri;
2185    case Pri_Reg:
2186       vassert(hregClass(ri->Pri.Reg) == HRcGPR(env->mode64));
2187       vassert(hregIsVirtual(ri->Pri.Reg));
2188       return ri;
2189    default:
2190       vpanic("iselIntExpr_RI: unknown ppc RI tag");
2191    }
2192 }
2193
2194 /* DO NOT CALL THIS DIRECTLY ! */
2195 static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e )
2196 {
2197    Long  l;
2198    IRType ty = typeOfIRExpr(env->type_env,e);
2199    vassert(ty == Ity_I8  || ty == Ity_I16 ||
2200            ty == Ity_I32 || ((ty == Ity_I64) && env->mode64));
2201
2202    /* special case: immediate */
2203    if (e->tag == Iex_Const) {
2204       IRConst* con = e->Iex.Const.con;
2205       switch (con->tag) {
2206       case Ico_U64: vassert(env->mode64);
2207                     l = (Long)            con->Ico.U64; break;
2208       case Ico_U32: l = (Long)(Int)       con->Ico.U32; break;
2209       case Ico_U16: l = (Long)(Int)(Short)con->Ico.U16; break;
2210       case Ico_U8:  l = (Long)(Int)(Char )con->Ico.U8;  break;
2211       default:      vpanic("iselIntExpr_RI.Iex_Const(ppch)");
2212       }
2213       return PPCRI_Imm((ULong)l);
2214    }
2215
2216    /* default case: calculate into a register and return that */
2217    return PPCRI_Reg( iselWordExpr_R ( env, e ) );
2218 }
2219
2220
2221 /* --------------------- RH5u --------------------- */
2222
2223 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2224    being an immediate in the range 1 .. 31 inclusive.  Used for doing
2225    shift amounts.  Only used in 32-bit mode. */
2226
2227 static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e )
2228 {
2229    PPCRH* ri;
2230    vassert(!env->mode64);
2231    ri = iselWordExpr_RH5u_wrk(env, e);
2232    /* sanity checks ... */
2233    switch (ri->tag) {
2234    case Prh_Imm:
2235       vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 31);
2236       vassert(!ri->Prh.Imm.syned);
2237       return ri;
2238    case Prh_Reg:
2239       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2240       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2241       return ri;
2242    default:
2243       vpanic("iselIntExpr_RH5u: unknown ppc RI tag");
2244    }
2245 }
2246
2247 /* DO NOT CALL THIS DIRECTLY ! */
2248 static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e )
2249 {
2250    IRType ty = typeOfIRExpr(env->type_env,e);
2251    vassert(ty == Ity_I8);
2252
2253    /* special case: immediate */
2254    if (e->tag == Iex_Const
2255        && e->Iex.Const.con->tag == Ico_U8
2256        && e->Iex.Const.con->Ico.U8 >= 1
2257        && e->Iex.Const.con->Ico.U8 <= 31) {
2258       return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2259    }
2260
2261    /* default case: calculate into a register and return that */
2262    return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2263 }
2264
2265
2266 /* --------------------- RH6u --------------------- */
2267
2268 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter
2269    being an immediate in the range 1 .. 63 inclusive.  Used for doing
2270    shift amounts.  Only used in 64-bit mode. */
2271
2272 static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e )
2273 {
2274    PPCRH* ri; 
2275    vassert(env->mode64);
2276    ri = iselWordExpr_RH6u_wrk(env, e);
2277    /* sanity checks ... */
2278    switch (ri->tag) {
2279    case Prh_Imm:
2280       vassert(ri->Prh.Imm.imm16 >= 1 && ri->Prh.Imm.imm16 <= 63);
2281       vassert(!ri->Prh.Imm.syned);
2282       return ri;
2283    case Prh_Reg:
2284       vassert(hregClass(ri->Prh.Reg.reg) == HRcGPR(env->mode64));
2285       vassert(hregIsVirtual(ri->Prh.Reg.reg));
2286       return ri;
2287    default:
2288       vpanic("iselIntExpr_RH6u: unknown ppc64 RI tag");
2289    }
2290 }
2291
2292 /* DO NOT CALL THIS DIRECTLY ! */
2293 static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e )
2294 {
2295    IRType ty = typeOfIRExpr(env->type_env,e);
2296    vassert(ty == Ity_I8);
2297
2298    /* special case: immediate */
2299    if (e->tag == Iex_Const
2300        && e->Iex.Const.con->tag == Ico_U8
2301        && e->Iex.Const.con->Ico.U8 >= 1
2302        && e->Iex.Const.con->Ico.U8 <= 63) {
2303       return PPCRH_Imm(False/*unsigned*/, e->Iex.Const.con->Ico.U8);
2304    }
2305
2306    /* default case: calculate into a register and return that */
2307    return PPCRH_Reg( iselWordExpr_R ( env, e ) );
2308 }
2309
2310
2311 /* --------------------- CONDCODE --------------------- */
2312
2313 /* Generate code to evaluated a bit-typed expression, returning the
2314    condition code which would correspond when the expression would
2315    notionally have returned 1. */
2316
2317 static PPCCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
2318 {
2319    /* Uh, there's nothing we can sanity check here, unfortunately. */
2320    return iselCondCode_wrk(env,e);
2321 }
2322
2323 /* DO NOT CALL THIS DIRECTLY ! */
2324 static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
2325 {
2326    vassert(e);
2327    vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
2328
2329    /* Constant 1:Bit */
2330    if (e->tag == Iex_Const && e->Iex.Const.con->Ico.U1 == True) {
2331       // Make a compare that will always be true:
2332       HReg r_zero = newVRegI(env);
2333       addInstr(env, PPCInstr_LI(r_zero, 0, env->mode64));
2334       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2335                                  7/*cr*/, r_zero, PPCRH_Reg(r_zero)));
2336       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2337    }
2338
2339    /* Not1(...) */
2340    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
2341       /* Generate code for the arg, and negate the test condition */
2342       PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2343       cond.test = invertCondTest(cond.test);
2344       return cond;
2345    }
2346
2347    /* --- patterns rooted at: 32to1 or 64to1 --- */
2348
2349    /* 32to1, 64to1 */
2350    if (e->tag == Iex_Unop &&
2351        (e->Iex.Unop.op == Iop_32to1 || e->Iex.Unop.op == Iop_64to1)) {
2352       HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2353       HReg tmp = newVRegI(env);
2354       /* could do better, probably -- andi. */
2355       addInstr(env, PPCInstr_Alu(Palu_AND, tmp,
2356                                  src, PPCRH_Imm(False,1)));
2357       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2358                                  7/*cr*/, tmp, PPCRH_Imm(False,1)));
2359       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2360    }
2361
2362    /* --- patterns rooted at: CmpNEZ8 --- */
2363
2364    /* CmpNEZ8(x) */
2365    /* could do better -- andi. */
2366    if (e->tag == Iex_Unop
2367        && e->Iex.Unop.op == Iop_CmpNEZ8) {
2368       HReg arg = iselWordExpr_R(env, e->Iex.Unop.arg);
2369       HReg tmp = newVRegI(env);
2370       addInstr(env, PPCInstr_Alu(Palu_AND, tmp, arg,
2371                                  PPCRH_Imm(False,0xFF)));
2372       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2373                                  7/*cr*/, tmp, PPCRH_Imm(False,0)));
2374       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2375    }
2376
2377    /* --- patterns rooted at: CmpNEZ32 --- */
2378
2379    /* CmpNEZ32(x) */
2380    if (e->tag == Iex_Unop
2381        && e->Iex.Unop.op == Iop_CmpNEZ32) {
2382       HReg r1 = iselWordExpr_R(env, e->Iex.Unop.arg);
2383       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2384                                  7/*cr*/, r1, PPCRH_Imm(False,0)));
2385       return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2386    }
2387
2388    /* --- patterns rooted at: Cmp*32* --- */
2389
2390    /* Cmp*32*(x,y) */
2391    if (e->tag == Iex_Binop 
2392        && (e->Iex.Binop.op == Iop_CmpEQ32
2393            || e->Iex.Binop.op == Iop_CmpNE32
2394            || e->Iex.Binop.op == Iop_CmpLT32S
2395            || e->Iex.Binop.op == Iop_CmpLT32U
2396            || e->Iex.Binop.op == Iop_CmpLE32S
2397            || e->Iex.Binop.op == Iop_CmpLE32U)) {
2398       Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S ||
2399                     e->Iex.Binop.op == Iop_CmpLE32S);
2400       HReg   r1  = iselWordExpr_R(env, e->Iex.Binop.arg1);
2401       PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
2402       addInstr(env, PPCInstr_Cmp(syned, True/*32bit cmp*/,
2403                                  7/*cr*/, r1, ri2));
2404
2405       switch (e->Iex.Binop.op) {
2406       case Iop_CmpEQ32:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2407       case Iop_CmpNE32:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2408       case Iop_CmpLT32U: case Iop_CmpLT32S:
2409          return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2410       case Iop_CmpLE32U: case Iop_CmpLE32S:
2411          return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2412       default: vpanic("iselCondCode(ppc): CmpXX32");
2413       }
2414    }
2415
2416    /* --- patterns rooted at: CmpNEZ64 --- */
2417
2418    /* CmpNEZ64 */
2419    if (e->tag == Iex_Unop 
2420        && e->Iex.Unop.op == Iop_CmpNEZ64) {
2421       if (!env->mode64) {
2422          HReg hi, lo;
2423          HReg tmp = newVRegI(env);
2424          iselInt64Expr( &hi, &lo, env, e->Iex.Unop.arg );
2425          addInstr(env, PPCInstr_Alu(Palu_OR, tmp, lo, PPCRH_Reg(hi)));
2426          addInstr(env, PPCInstr_Cmp(False/*sign*/, True/*32bit cmp*/,
2427                                     7/*cr*/, tmp,PPCRH_Imm(False,0)));
2428          return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2429       } else {  // mode64
2430          HReg r_src = iselWordExpr_R(env, e->Iex.Binop.arg1);
2431          addInstr(env, PPCInstr_Cmp(False/*sign*/, False/*64bit cmp*/,
2432                                     7/*cr*/, r_src,PPCRH_Imm(False,0)));
2433          return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2434       }
2435    }
2436
2437    /* --- patterns rooted at: Cmp*64* --- */
2438
2439    /* Cmp*64*(x,y) */
2440    if (e->tag == Iex_Binop 
2441        && (e->Iex.Binop.op == Iop_CmpEQ64
2442            || e->Iex.Binop.op == Iop_CmpNE64
2443            || e->Iex.Binop.op == Iop_CmpLT64S
2444            || e->Iex.Binop.op == Iop_CmpLT64U
2445            || e->Iex.Binop.op == Iop_CmpLE64S
2446            || e->Iex.Binop.op == Iop_CmpLE64U)) {
2447       Bool   syned = (e->Iex.Binop.op == Iop_CmpLT64S ||
2448                       e->Iex.Binop.op == Iop_CmpLE64S);
2449       HReg    r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2450       PPCRH* ri2 = iselWordExpr_RH(env, syned, e->Iex.Binop.arg2);
2451       vassert(env->mode64);
2452       addInstr(env, PPCInstr_Cmp(syned, False/*64bit cmp*/,
2453                                  7/*cr*/, r1, ri2));
2454
2455       switch (e->Iex.Binop.op) {
2456       case Iop_CmpEQ64:  return mk_PPCCondCode( Pct_TRUE,  Pcf_7EQ );
2457       case Iop_CmpNE64:  return mk_PPCCondCode( Pct_FALSE, Pcf_7EQ );
2458       case Iop_CmpLT64U: return mk_PPCCondCode( Pct_TRUE,  Pcf_7LT );
2459       case Iop_CmpLE64U: return mk_PPCCondCode( Pct_FALSE, Pcf_7GT );
2460       default: vpanic("iselCondCode(ppc): CmpXX64");
2461       }
2462    }
2463
2464    /* var */
2465    if (e->tag == Iex_RdTmp) {
2466       HReg r_src      = lookupIRTemp(env, e->Iex.RdTmp.tmp);
2467       HReg src_masked = newVRegI(env);
2468       addInstr(env,
2469                PPCInstr_Alu(Palu_AND, src_masked,
2470                             r_src, PPCRH_Imm(False,1)));
2471       addInstr(env,
2472                PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
2473                             7/*cr*/, src_masked, PPCRH_Imm(False,1)));
2474       return mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2475    }
2476
2477    vex_printf("iselCondCode(ppc): No such tag(%u)\n", e->tag);
2478    ppIRExpr(e);
2479    vpanic("iselCondCode(ppc)");
2480 }
2481
2482
2483 /*---------------------------------------------------------*/
2484 /*--- ISEL: Integer expressions (128 bit)               ---*/
2485 /*---------------------------------------------------------*/
2486
2487 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
2488    which is returned as the first two parameters.  As with
2489    iselWordExpr_R, these may be either real or virtual regs; in any
2490    case they must not be changed by subsequent code emitted by the
2491    caller.  */
2492
2493 static void iselInt128Expr ( HReg* rHi, HReg* rLo,
2494                              ISelEnv* env, IRExpr* e )
2495 {
2496    vassert(env->mode64);
2497    iselInt128Expr_wrk(rHi, rLo, env, e);
2498 #  if 0
2499    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2500 #  endif
2501    vassert(hregClass(*rHi) == HRcGPR(env->mode64));
2502    vassert(hregIsVirtual(*rHi));
2503    vassert(hregClass(*rLo) == HRcGPR(env->mode64));
2504    vassert(hregIsVirtual(*rLo));
2505 }
2506
2507 /* DO NOT CALL THIS DIRECTLY ! */
2508 static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo,
2509                                  ISelEnv* env, IRExpr* e )
2510 {
2511    vassert(e);
2512    vassert(typeOfIRExpr(env->type_env,e) == Ity_I128);
2513
2514    /* read 128-bit IRTemp */
2515    if (e->tag == Iex_RdTmp) {
2516       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
2517       return;
2518    }
2519
2520    /* --------- BINARY ops --------- */
2521    if (e->tag == Iex_Binop) {
2522       switch (e->Iex.Binop.op) {
2523       /* 64 x 64 -> 128 multiply */
2524       case Iop_MullU64:
2525       case Iop_MullS64: {
2526          HReg     tLo     = newVRegI(env);
2527          HReg     tHi     = newVRegI(env);
2528          Bool     syned   = toBool(e->Iex.Binop.op == Iop_MullS64);
2529          HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
2530          HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2531          addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 
2532                                      False/*lo64*/, False/*64bit mul*/,
2533                                      tLo, r_srcL, r_srcR));
2534          addInstr(env, PPCInstr_MulL(syned,
2535                                      True/*hi64*/, False/*64bit mul*/,
2536                                      tHi, r_srcL, r_srcR));
2537          *rHi = tHi;
2538          *rLo = tLo;
2539          return;
2540       }
2541
2542       /* 64HLto128(e1,e2) */
2543       case Iop_64HLto128:
2544          *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2545          *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2546          return;
2547
2548       default: 
2549          break;
2550       }
2551    } /* if (e->tag == Iex_Binop) */
2552
2553
2554    /* --------- UNARY ops --------- */
2555    if (e->tag == Iex_Unop) {
2556       switch (e->Iex.Unop.op) {
2557       default:
2558          break;
2559       }
2560    } /* if (e->tag == Iex_Unop) */
2561
2562    vex_printf("iselInt128Expr(ppc64): No such tag(%u)\n", e->tag);
2563    ppIRExpr(e);
2564    vpanic("iselInt128Expr(ppc64)");
2565 }
2566
2567
2568 /*---------------------------------------------------------*/
2569 /*--- ISEL: Integer expressions (64 bit)                ---*/
2570 /*---------------------------------------------------------*/
2571
2572 /* 32-bit mode ONLY: compute a 64-bit value into a register pair,
2573    which is returned as the first two parameters.  As with
2574    iselIntExpr_R, these may be either real or virtual regs; in any
2575    case they must not be changed by subsequent code emitted by the
2576    caller.  */
2577
2578 static void iselInt64Expr ( HReg* rHi, HReg* rLo,
2579                             ISelEnv* env, IRExpr* e )
2580 {
2581    vassert(!env->mode64);
2582    iselInt64Expr_wrk(rHi, rLo, env, e);
2583 #  if 0
2584    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2585 #  endif
2586    vassert(hregClass(*rHi) == HRcInt32);
2587    vassert(hregIsVirtual(*rHi));
2588    vassert(hregClass(*rLo) == HRcInt32);
2589    vassert(hregIsVirtual(*rLo));
2590 }
2591
2592 /* DO NOT CALL THIS DIRECTLY ! */
2593 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
2594                                 ISelEnv* env, IRExpr* e )
2595 {
2596    vassert(e);
2597    vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
2598
2599    /* 64-bit load */
2600    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
2601       HReg tLo    = newVRegI(env);
2602       HReg tHi    = newVRegI(env);
2603       HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
2604       vassert(!env->mode64);
2605       addInstr(env, PPCInstr_Load( 4/*byte-load*/,
2606                                    tHi, PPCAMode_IR( 0, r_addr ), 
2607                                    False/*32-bit insn please*/) );
2608       addInstr(env, PPCInstr_Load( 4/*byte-load*/, 
2609                                    tLo, PPCAMode_IR( 4, r_addr ), 
2610                                    False/*32-bit insn please*/) );
2611       *rHi = tHi;
2612       *rLo = tLo;
2613       return;
2614    }
2615
2616    /* 64-bit literal */
2617    if (e->tag == Iex_Const) {
2618       ULong w64 = e->Iex.Const.con->Ico.U64;
2619       UInt  wHi = ((UInt)(w64 >> 32)) & 0xFFFFFFFF;
2620       UInt  wLo = ((UInt)w64) & 0xFFFFFFFF;
2621       HReg  tLo = newVRegI(env);
2622       HReg  tHi = newVRegI(env);
2623       vassert(e->Iex.Const.con->tag == Ico_U64);
2624       addInstr(env, PPCInstr_LI(tHi, (Long)(Int)wHi, False/*mode32*/));
2625       addInstr(env, PPCInstr_LI(tLo, (Long)(Int)wLo, False/*mode32*/));
2626       *rHi = tHi;
2627       *rLo = tLo;
2628       return;
2629    }
2630
2631    /* read 64-bit IRTemp */
2632    if (e->tag == Iex_RdTmp) {
2633       lookupIRTempPair( rHi, rLo, env, e->Iex.RdTmp.tmp);
2634       return;
2635    }
2636
2637    /* 64-bit GET */
2638    if (e->tag == Iex_Get) {
2639       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2640                                        GuestStatePtr(False/*mode32*/) );
2641       PPCAMode* am_addr4 = advance4(env, am_addr);
2642       HReg tLo = newVRegI(env);
2643       HReg tHi = newVRegI(env);
2644       addInstr(env, PPCInstr_Load( 4, tHi, am_addr,  False/*mode32*/ ));
2645       addInstr(env, PPCInstr_Load( 4, tLo, am_addr4, False/*mode32*/ ));
2646       *rHi = tHi;
2647       *rLo = tLo;
2648       return;
2649    }
2650
2651    /* 64-bit Mux0X */
2652    if (e->tag == Iex_Mux0X) {
2653       HReg e0Lo, e0Hi, eXLo, eXHi;
2654       HReg tLo = newVRegI(env);
2655       HReg tHi = newVRegI(env);
2656       
2657       PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
2658       HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
2659       HReg r_tmp  = newVRegI(env);
2660       
2661       iselInt64Expr(&e0Hi, &e0Lo, env, e->Iex.Mux0X.expr0);
2662       iselInt64Expr(&eXHi, &eXLo, env, e->Iex.Mux0X.exprX);
2663       addInstr(env, mk_iMOVds_RR(tHi,eXHi));
2664       addInstr(env, mk_iMOVds_RR(tLo,eXLo));
2665       
2666       addInstr(env, PPCInstr_Alu(Palu_AND, 
2667                                  r_tmp, r_cond, PPCRH_Imm(False,0xFF)));
2668       addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/, 
2669                                  7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
2670       
2671       addInstr(env, PPCInstr_CMov(cc,tHi,PPCRI_Reg(e0Hi)));
2672       addInstr(env, PPCInstr_CMov(cc,tLo,PPCRI_Reg(e0Lo)));
2673       *rHi = tHi;
2674       *rLo = tLo;
2675       return;
2676    }
2677
2678    /* --------- BINARY ops --------- */
2679    if (e->tag == Iex_Binop) {
2680       IROp op_binop = e->Iex.Binop.op;
2681       switch (op_binop) {
2682          /* 32 x 32 -> 64 multiply */
2683          case Iop_MullU32:
2684          case Iop_MullS32: {
2685             HReg     tLo     = newVRegI(env);
2686             HReg     tHi     = newVRegI(env);
2687             Bool     syned   = toBool(op_binop == Iop_MullS32);
2688             HReg     r_srcL  = iselWordExpr_R(env, e->Iex.Binop.arg1);
2689             HReg     r_srcR  = iselWordExpr_R(env, e->Iex.Binop.arg2);
2690             addInstr(env, PPCInstr_MulL(False/*signedness irrelevant*/, 
2691                                         False/*lo32*/, True/*32bit mul*/,
2692                                         tLo, r_srcL, r_srcR));
2693             addInstr(env, PPCInstr_MulL(syned,
2694                                         True/*hi32*/, True/*32bit mul*/,
2695                                         tHi, r_srcL, r_srcR));
2696             *rHi = tHi;
2697             *rLo = tLo;
2698             return;
2699          }
2700
2701          /* Or64/And64/Xor64 */
2702          case Iop_Or64:
2703          case Iop_And64:
2704          case Iop_Xor64: {
2705             HReg xLo, xHi, yLo, yHi;
2706             HReg tLo = newVRegI(env);
2707             HReg tHi = newVRegI(env);
2708             PPCAluOp op = (op_binop == Iop_Or64) ? Palu_OR :
2709                           (op_binop == Iop_And64) ? Palu_AND : Palu_XOR;
2710             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2711             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2712             addInstr(env, PPCInstr_Alu(op, tHi, xHi, PPCRH_Reg(yHi)));
2713             addInstr(env, PPCInstr_Alu(op, tLo, xLo, PPCRH_Reg(yLo)));
2714             *rHi = tHi;
2715             *rLo = tLo;
2716             return;
2717          }
2718
2719          /* Add64 */
2720          case Iop_Add64: {
2721             HReg xLo, xHi, yLo, yHi;
2722             HReg tLo = newVRegI(env);
2723             HReg tHi = newVRegI(env);
2724             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2725             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2726             addInstr(env, PPCInstr_AddSubC( True/*add*/, True /*set carry*/,
2727                                             tLo, xLo, yLo));
2728             addInstr(env, PPCInstr_AddSubC( True/*add*/, False/*read carry*/,
2729                                             tHi, xHi, yHi));
2730             *rHi = tHi;
2731             *rLo = tLo;
2732             return;
2733          }
2734
2735          /* 32HLto64(e1,e2) */
2736          case Iop_32HLto64:
2737             *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2738             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2739             return;
2740
2741          /* F64toI64S */
2742          case Iop_F64toI64S: {
2743             HReg      tLo     = newVRegI(env);
2744             HReg      tHi     = newVRegI(env);
2745             HReg      r1      = StackFramePtr(env->mode64);
2746             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
2747             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
2748             HReg      fsrc    = iselDblExpr(env, e->Iex.Binop.arg2);
2749             HReg      ftmp    = newVRegF(env);
2750
2751             vassert(!env->mode64);
2752             /* Set host rounding mode */
2753             set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
2754
2755             sub_from_sp( env, 16 );
2756             addInstr(env, PPCInstr_FpCftI(False/*F->I*/, False/*int64*/, True,
2757                                           True, ftmp, fsrc));
2758             addInstr(env, PPCInstr_FpLdSt(False/*store*/, 8, ftmp, zero_r1));
2759             addInstr(env, PPCInstr_Load(4, tHi, zero_r1, False/*mode32*/));
2760             addInstr(env, PPCInstr_Load(4, tLo, four_r1, False/*mode32*/));
2761             add_to_sp( env, 16 );
2762
2763             ///* Restore default FPU rounding. */
2764             //set_FPU_rounding_default( env );
2765             *rHi = tHi;
2766             *rLo = tLo;
2767             return;
2768          }
2769
2770          default: 
2771             break;
2772       }
2773    } /* if (e->tag == Iex_Binop) */
2774
2775
2776    /* --------- UNARY ops --------- */
2777    if (e->tag == Iex_Unop) {
2778       switch (e->Iex.Unop.op) {
2779
2780       /* CmpwNEZ64(e) */
2781       case Iop_CmpwNEZ64: {
2782          HReg argHi, argLo;
2783          HReg tmp1  = newVRegI(env);
2784          HReg tmp2  = newVRegI(env);
2785          iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
2786          /* tmp1 = argHi | argLo */
2787          addInstr(env, PPCInstr_Alu(Palu_OR, tmp1, argHi, PPCRH_Reg(argLo)));
2788          /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2789          addInstr(env, PPCInstr_Unary(Pun_NEG,tmp2,tmp1));
2790          addInstr(env, PPCInstr_Alu(Palu_OR, tmp2, tmp2, PPCRH_Reg(tmp1)));
2791          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/, 
2792                                      tmp2, tmp2, PPCRH_Imm(False, 31)));
2793          *rHi = tmp2;
2794          *rLo = tmp2; /* yes, really tmp2 */
2795          return;
2796       }
2797
2798       /* Left64 */
2799       case Iop_Left64: {
2800          HReg argHi, argLo;
2801          HReg zero32 = newVRegI(env);
2802          HReg resHi  = newVRegI(env);
2803          HReg resLo  = newVRegI(env);
2804          iselInt64Expr(&argHi, &argLo, env, e->Iex.Unop.arg);
2805          vassert(env->mode64 == False);
2806          addInstr(env, PPCInstr_LI(zero32, 0, env->mode64));
2807          /* resHi:resLo = - argHi:argLo */
2808          addInstr(env, PPCInstr_AddSubC( False/*sub*/, True/*set carry*/,
2809                                          resLo, zero32, argLo ));
2810          addInstr(env, PPCInstr_AddSubC( False/*sub*/, False/*read carry*/,
2811                                          resHi, zero32, argHi ));
2812          /* resHi:resLo |= srcHi:srcLo */
2813          addInstr(env, PPCInstr_Alu(Palu_OR, resLo, resLo, PPCRH_Reg(argLo)));
2814          addInstr(env, PPCInstr_Alu(Palu_OR, resHi, resHi, PPCRH_Reg(argHi)));
2815          *rHi = resHi;
2816          *rLo = resLo;
2817          return;
2818       }
2819
2820       /* 32Sto64(e) */
2821       case Iop_32Sto64: {
2822          HReg tHi = newVRegI(env);
2823          HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2824          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2825                                      tHi, src, PPCRH_Imm(False,31)));
2826          *rHi = tHi;
2827          *rLo = src;
2828          return;
2829       }
2830
2831       /* 32Uto64(e) */
2832       case Iop_32Uto64: {
2833          HReg tHi = newVRegI(env);
2834          HReg tLo = iselWordExpr_R(env, e->Iex.Unop.arg);
2835          addInstr(env, PPCInstr_LI(tHi, 0, False/*mode32*/));
2836          *rHi = tHi;
2837          *rLo = tLo;
2838          return;
2839       }
2840
2841       /* V128{HI}to64 */
2842       case Iop_V128HIto64:
2843       case Iop_V128to64: {
2844          HReg r_aligned16;
2845          Int  off = e->Iex.Unop.op==Iop_V128HIto64 ? 0 : 8;
2846          HReg tLo = newVRegI(env);
2847          HReg tHi = newVRegI(env);
2848          HReg vec = iselVecExpr(env, e->Iex.Unop.arg);
2849          PPCAMode *am_off0, *am_offLO, *am_offHI;
2850          sub_from_sp( env, 32 );     // Move SP down 32 bytes
2851          
2852          // get a quadword aligned address within our stack space
2853          r_aligned16 = get_sp_aligned16( env );
2854          am_off0  = PPCAMode_IR( 0,     r_aligned16 );
2855          am_offHI = PPCAMode_IR( off,   r_aligned16 );
2856          am_offLO = PPCAMode_IR( off+4, r_aligned16 );
2857          
2858          // store as Vec128
2859          addInstr(env,
2860                   PPCInstr_AvLdSt( False/*store*/, 16, vec, am_off0 ));
2861          
2862          // load hi,lo words (of hi/lo half of vec) as Ity_I32's
2863          addInstr(env,
2864                   PPCInstr_Load( 4, tHi, am_offHI, False/*mode32*/ ));
2865          addInstr(env,
2866                   PPCInstr_Load( 4, tLo, am_offLO, False/*mode32*/ ));
2867          
2868          add_to_sp( env, 32 );       // Reset SP
2869          *rHi = tHi;
2870          *rLo = tLo;
2871          return;
2872       }
2873
2874       /* could do better than this, but for now ... */
2875       case Iop_1Sto64: {
2876          HReg tLo = newVRegI(env);
2877          HReg tHi = newVRegI(env);
2878          PPCCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
2879          addInstr(env, PPCInstr_Set(cond,tLo));
2880          addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/,
2881                                      tLo, tLo, PPCRH_Imm(False,31)));
2882          addInstr(env, PPCInstr_Shft(Pshft_SAR, True/*32bit shift*/,
2883                                      tLo, tLo, PPCRH_Imm(False,31)));
2884          addInstr(env, mk_iMOVds_RR(tHi, tLo));
2885          *rHi = tHi;
2886          *rLo = tLo;
2887          return;
2888       }
2889
2890       case Iop_Not64: {
2891          HReg xLo, xHi;
2892          HReg tmpLo = newVRegI(env);
2893          HReg tmpHi = newVRegI(env);
2894          iselInt64Expr(&xHi, &xLo, env, e->Iex.Unop.arg);
2895          addInstr(env, PPCInstr_Unary(Pun_NOT,tmpLo,xLo));
2896          addInstr(env, PPCInstr_Unary(Pun_NOT,tmpHi,xHi));
2897          *rHi = tmpHi;
2898          *rLo = tmpLo;
2899          return;
2900       }
2901
2902       /* ReinterpF64asI64(e) */
2903       /* Given an IEEE754 double, produce an I64 with the same bit
2904          pattern. */
2905       case Iop_ReinterpF64asI64: {
2906          PPCAMode *am_addr0, *am_addr1;
2907          HReg fr_src  = iselDblExpr(env, e->Iex.Unop.arg);
2908          HReg r_dstLo = newVRegI(env);
2909          HReg r_dstHi = newVRegI(env);
2910          
2911          sub_from_sp( env, 16 );     // Move SP down 16 bytes
2912          am_addr0 = PPCAMode_IR( 0, StackFramePtr(False/*mode32*/) );
2913          am_addr1 = PPCAMode_IR( 4, StackFramePtr(False/*mode32*/) );
2914
2915          // store as F64
2916          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
2917                                         fr_src, am_addr0 ));
2918          
2919          // load hi,lo as Ity_I32's
2920          addInstr(env, PPCInstr_Load( 4, r_dstHi,
2921                                       am_addr0, False/*mode32*/ ));
2922          addInstr(env, PPCInstr_Load( 4, r_dstLo,
2923                                       am_addr1, False/*mode32*/ ));
2924          *rHi = r_dstHi;
2925          *rLo = r_dstLo;
2926          
2927          add_to_sp( env, 16 );       // Reset SP
2928          return;
2929       }
2930
2931       default:
2932          break;
2933       }
2934    } /* if (e->tag == Iex_Unop) */
2935
2936    vex_printf("iselInt64Expr(ppc): No such tag(%u)\n", e->tag);
2937    ppIRExpr(e);
2938    vpanic("iselInt64Expr(ppc)");
2939 }
2940
2941
2942 /*---------------------------------------------------------*/
2943 /*--- ISEL: Floating point expressions (32 bit)         ---*/
2944 /*---------------------------------------------------------*/
2945
2946 /* Nothing interesting here; really just wrappers for
2947    64-bit stuff. */
2948
2949 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
2950 {
2951    HReg r = iselFltExpr_wrk( env, e );
2952 #  if 0
2953    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
2954 #  endif
2955    vassert(hregClass(r) == HRcFlt64); /* yes, really Flt64 */
2956    vassert(hregIsVirtual(r));
2957    return r;
2958 }
2959
2960 /* DO NOT CALL THIS DIRECTLY */
2961 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
2962 {
2963    Bool        mode64 = env->mode64;
2964
2965    IRType ty = typeOfIRExpr(env->type_env,e);
2966    vassert(ty == Ity_F32);
2967
2968    if (e->tag == Iex_RdTmp) {
2969       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2970    }
2971
2972    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
2973       PPCAMode* am_addr;
2974       HReg r_dst = newVRegF(env);
2975       vassert(e->Iex.Load.ty == Ity_F32);
2976       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F32/*xfer*/);
2977       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 4, r_dst, am_addr));
2978       return r_dst;
2979    }
2980
2981    if (e->tag == Iex_Get) {
2982       HReg r_dst = newVRegF(env);
2983       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
2984                                        GuestStatePtr(env->mode64) );
2985       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4, r_dst, am_addr ));
2986       return r_dst;
2987    }
2988
2989    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
2990       /* This is quite subtle.  The only way to do the relevant
2991          truncation is to do a single-precision store and then a
2992          double precision load to get it back into a register.  The
2993          problem is, if the data is then written to memory a second
2994          time, as in
2995
2996             STbe(...) = TruncF64asF32(...)
2997
2998          then will the second truncation further alter the value?  The
2999          answer is no: flds (as generated here) followed by fsts
3000          (generated for the STbe) is the identity function on 32-bit
3001          floats, so we are safe.
3002
3003          Another upshot of this is that if iselStmt can see the
3004          entirety of
3005
3006             STbe(...) = TruncF64asF32(arg)
3007
3008          then it can short circuit having to deal with TruncF64asF32
3009          individually; instead just compute arg into a 64-bit FP
3010          register and do 'fsts' (since that itself does the
3011          truncation).
3012
3013          We generate pretty poor code here (should be ok both for
3014          32-bit and 64-bit mode); but it is expected that for the most
3015          part the latter optimisation will apply and hence this code
3016          will not often be used.
3017       */
3018       HReg      fsrc    = iselDblExpr(env, e->Iex.Unop.arg);
3019       HReg      fdst    = newVRegF(env);
3020       PPCAMode* zero_r1 = PPCAMode_IR( 0, StackFramePtr(env->mode64) );
3021
3022       sub_from_sp( env, 16 );
3023       // store as F32, hence truncating
3024       addInstr(env, PPCInstr_FpLdSt( False/*store*/, 4,
3025                                      fsrc, zero_r1 ));
3026       // and reload.  Good huh?! (sigh)
3027       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 4,
3028                                      fdst, zero_r1 ));
3029       add_to_sp( env, 16 );
3030       return fdst;
3031    }
3032
3033    if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64UtoF32) {
3034       if (mode64) {
3035          HReg fdst = newVRegF(env);
3036          HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
3037          HReg r1   = StackFramePtr(env->mode64);
3038          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3039
3040          /* Set host rounding mode */
3041          set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3042
3043          sub_from_sp( env, 16 );
3044
3045          addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3046          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3047          addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 
3048                                        False, False,
3049                                        fdst, fdst));
3050
3051          add_to_sp( env, 16 );
3052
3053          ///* Restore default FPU rounding. */
3054          //set_FPU_rounding_default( env );
3055          return fdst;
3056       } else {
3057          /* 32-bit mode */
3058          HReg fdst = newVRegF(env);
3059          HReg isrcHi, isrcLo;
3060          HReg r1   = StackFramePtr(env->mode64);
3061          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3062          PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3063
3064          iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2);
3065
3066          /* Set host rounding mode */
3067          set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3068
3069          sub_from_sp( env, 16 );
3070
3071          addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3072          addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3073          addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3074          addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 
3075                                        False, False,
3076                                        fdst, fdst));
3077
3078          add_to_sp( env, 16 );
3079
3080          ///* Restore default FPU rounding. */
3081          //set_FPU_rounding_default( env );
3082          return fdst;
3083       }
3084
3085    }
3086
3087    vex_printf("iselFltExpr(ppc): No such tag(%u)\n", e->tag);
3088    ppIRExpr(e);
3089    vpanic("iselFltExpr_wrk(ppc)");
3090 }
3091
3092
3093 /*---------------------------------------------------------*/
3094 /*--- ISEL: Floating point expressions (64 bit)         ---*/
3095 /*---------------------------------------------------------*/
3096
3097 /* Compute a 64-bit floating point value into a register, the identity
3098    of which is returned.  As with iselIntExpr_R, the reg may be either
3099    real or virtual; in any case it must not be changed by subsequent
3100    code emitted by the caller.  */
3101
3102 /* IEEE 754 formats.  From http://www.freesoft.org/CIE/RFC/1832/32.htm:
3103
3104     Type                  S (1 bit)   E (11 bits)   F (52 bits)
3105     ----                  ---------   -----------   -----------
3106     signalling NaN        u           2047 (max)    .0uuuuu---u
3107                                                     (with at least
3108                                                      one 1 bit)
3109     quiet NaN             u           2047 (max)    .1uuuuu---u
3110
3111     negative infinity     1           2047 (max)    .000000---0
3112
3113     positive infinity     0           2047 (max)    .000000---0
3114
3115     negative zero         1           0             .000000---0
3116
3117     positive zero         0           0             .000000---0
3118 */
3119
3120 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
3121 {
3122    HReg r = iselDblExpr_wrk( env, e );
3123 #  if 0
3124    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3125 #  endif
3126    vassert(hregClass(r) == HRcFlt64);
3127    vassert(hregIsVirtual(r));
3128    return r;
3129 }
3130
3131 /* DO NOT CALL THIS DIRECTLY */
3132 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
3133 {
3134    Bool mode64 = env->mode64;
3135    IRType ty = typeOfIRExpr(env->type_env,e);
3136    vassert(e);
3137    vassert(ty == Ity_F64);
3138
3139    if (e->tag == Iex_RdTmp) {
3140       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3141    }
3142
3143    /* --------- LITERAL --------- */
3144    if (e->tag == Iex_Const) {
3145       union { UInt u32x2[2]; ULong u64; Double f64; } u;
3146       vassert(sizeof(u) == 8);
3147       vassert(sizeof(u.u64) == 8);
3148       vassert(sizeof(u.f64) == 8);
3149       vassert(sizeof(u.u32x2) == 8);
3150
3151       if (e->Iex.Const.con->tag == Ico_F64) {
3152          u.f64 = e->Iex.Const.con->Ico.F64;
3153       }
3154       else if (e->Iex.Const.con->tag == Ico_F64i) {
3155          u.u64 = e->Iex.Const.con->Ico.F64i;
3156       }
3157       else
3158          vpanic("iselDblExpr(ppc): const");
3159
3160       if (!mode64) {
3161          HReg r_srcHi = newVRegI(env);
3162          HReg r_srcLo = newVRegI(env);
3163          addInstr(env, PPCInstr_LI(r_srcHi, u.u32x2[0], mode64));
3164          addInstr(env, PPCInstr_LI(r_srcLo, u.u32x2[1], mode64));
3165          return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3166       } else { // mode64
3167          HReg r_src = newVRegI(env);
3168          addInstr(env, PPCInstr_LI(r_src, u.u64, mode64));
3169          return mk_LoadR64toFPR( env, r_src );         // 1*I64 -> F64
3170       }
3171    }
3172
3173    /* --------- LOAD --------- */
3174    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
3175       HReg r_dst = newVRegF(env);
3176       PPCAMode* am_addr;
3177       vassert(e->Iex.Load.ty == Ity_F64);
3178       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_F64/*xfer*/);
3179       addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, r_dst, am_addr));
3180       return r_dst;
3181    }
3182
3183    /* --------- GET --------- */
3184    if (e->tag == Iex_Get) {
3185       HReg r_dst = newVRegF(env);
3186       PPCAMode* am_addr = PPCAMode_IR( e->Iex.Get.offset,
3187                                        GuestStatePtr(mode64) );
3188       addInstr(env, PPCInstr_FpLdSt( True/*load*/, 8, r_dst, am_addr ));
3189       return r_dst;
3190    }
3191
3192    /* --------- OPS --------- */
3193    if (e->tag == Iex_Qop) {
3194       PPCFpOp fpop = Pfp_INVALID;
3195       switch (e->Iex.Qop.op) {
3196          case Iop_MAddF64:    fpop = Pfp_MADDD; break;
3197          case Iop_MAddF64r32: fpop = Pfp_MADDS; break;
3198          case Iop_MSubF64:    fpop = Pfp_MSUBD; break;
3199          case Iop_MSubF64r32: fpop = Pfp_MSUBS; break;
3200          default: break;
3201       }
3202       if (fpop != Pfp_INVALID) {
3203          HReg r_dst  = newVRegF(env);
3204          HReg r_srcML  = iselDblExpr(env, e->Iex.Qop.arg2);
3205          HReg r_srcMR  = iselDblExpr(env, e->Iex.Qop.arg3);
3206          HReg r_srcAcc = iselDblExpr(env, e->Iex.Qop.arg4);
3207          set_FPU_rounding_mode( env, e->Iex.Qop.arg1 );
3208          addInstr(env, PPCInstr_FpMulAcc(fpop, r_dst, 
3209                                                r_srcML, r_srcMR, r_srcAcc));
3210          return r_dst;
3211       }
3212    }
3213
3214    if (e->tag == Iex_Triop) {
3215       PPCFpOp fpop = Pfp_INVALID;
3216       switch (e->Iex.Triop.op) {
3217          case Iop_AddF64:    fpop = Pfp_ADDD; break;
3218          case Iop_SubF64:    fpop = Pfp_SUBD; break;
3219          case Iop_MulF64:    fpop = Pfp_MULD; break;
3220          case Iop_DivF64:    fpop = Pfp_DIVD; break;
3221          case Iop_AddF64r32: fpop = Pfp_ADDS; break;
3222          case Iop_SubF64r32: fpop = Pfp_SUBS; break;
3223          case Iop_MulF64r32: fpop = Pfp_MULS; break;
3224          case Iop_DivF64r32: fpop = Pfp_DIVS; break;
3225          default: break;
3226       }
3227       if (fpop != Pfp_INVALID) {
3228          HReg r_dst  = newVRegF(env);
3229          HReg r_srcL = iselDblExpr(env, e->Iex.Triop.arg2);
3230          HReg r_srcR = iselDblExpr(env, e->Iex.Triop.arg3);
3231          set_FPU_rounding_mode( env, e->Iex.Triop.arg1 );
3232          addInstr(env, PPCInstr_FpBinary(fpop, r_dst, r_srcL, r_srcR));
3233          return r_dst;
3234       }
3235    }
3236
3237    if (e->tag == Iex_Binop) {
3238       PPCFpOp fpop = Pfp_INVALID;
3239       switch (e->Iex.Binop.op) {
3240          case Iop_SqrtF64: fpop = Pfp_SQRT; break;
3241          default: break;
3242       }
3243       if (fpop != Pfp_INVALID) {
3244          HReg fr_dst = newVRegF(env);
3245          HReg fr_src = iselDblExpr(env, e->Iex.Binop.arg2);
3246          set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3247          addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
3248          return fr_dst;
3249       }
3250    }
3251
3252    if (e->tag == Iex_Binop) {
3253
3254       if (e->Iex.Binop.op == Iop_RoundF64toF32) {
3255          HReg r_dst = newVRegF(env);
3256          HReg r_src = iselDblExpr(env, e->Iex.Binop.arg2);
3257          set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3258          addInstr(env, PPCInstr_FpRSP(r_dst, r_src));
3259          //set_FPU_rounding_default( env );
3260          return r_dst;
3261       }
3262
3263       if (e->Iex.Binop.op == Iop_I64StoF64 || e->Iex.Binop.op == Iop_I64UtoF64) {
3264          if (mode64) {
3265             HReg fdst = newVRegF(env);
3266             HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
3267             HReg r1   = StackFramePtr(env->mode64);
3268             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3269
3270             /* Set host rounding mode */
3271             set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3272
3273             sub_from_sp( env, 16 );
3274
3275             addInstr(env, PPCInstr_Store(8, zero_r1, isrc, True/*mode64*/));
3276             addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3277             addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 
3278                                           e->Iex.Binop.op == Iop_I64StoF64,
3279                                           True/*fdst is 64 bit*/,
3280                                           fdst, fdst));
3281
3282             add_to_sp( env, 16 );
3283
3284             ///* Restore default FPU rounding. */
3285             //set_FPU_rounding_default( env );
3286             return fdst;
3287          } else {
3288             /* 32-bit mode */
3289             HReg fdst = newVRegF(env);
3290             HReg isrcHi, isrcLo;
3291             HReg r1   = StackFramePtr(env->mode64);
3292             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
3293             PPCAMode* four_r1 = PPCAMode_IR( 4, r1 );
3294
3295             iselInt64Expr(&isrcHi, &isrcLo, env, e->Iex.Binop.arg2);
3296
3297             /* Set host rounding mode */
3298             set_FPU_rounding_mode( env, e->Iex.Binop.arg1 );
3299
3300             sub_from_sp( env, 16 );
3301
3302             addInstr(env, PPCInstr_Store(4, zero_r1, isrcHi, False/*mode32*/));
3303             addInstr(env, PPCInstr_Store(4, four_r1, isrcLo, False/*mode32*/));
3304             addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fdst, zero_r1));
3305             addInstr(env, PPCInstr_FpCftI(True/*I->F*/, False/*int64*/, 
3306                                           e->Iex.Binop.op == Iop_I64StoF64,
3307                                           True/*fdst is 64 bit*/,
3308                                           fdst, fdst));
3309
3310             add_to_sp( env, 16 );
3311
3312             ///* Restore default FPU rounding. */
3313             //set_FPU_rounding_default( env );
3314             return fdst;
3315          }
3316       }
3317
3318    }
3319
3320    if (e->tag == Iex_Unop) {
3321       PPCFpOp fpop = Pfp_INVALID;
3322       switch (e->Iex.Unop.op) {
3323          case Iop_NegF64:     fpop = Pfp_NEG; break;
3324          case Iop_AbsF64:     fpop = Pfp_ABS; break;
3325          case Iop_Est5FRSqrt: fpop = Pfp_RSQRTE; break;
3326          case Iop_RoundF64toF64_NegINF:  fpop = Pfp_FRIM; break;
3327          case Iop_RoundF64toF64_PosINF:  fpop = Pfp_FRIP; break;
3328          case Iop_RoundF64toF64_NEAREST: fpop = Pfp_FRIN; break;
3329          case Iop_RoundF64toF64_ZERO:    fpop = Pfp_FRIZ; break;
3330          default: break;
3331       }
3332       if (fpop != Pfp_INVALID) {
3333          HReg fr_dst = newVRegF(env);
3334          HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
3335          addInstr(env, PPCInstr_FpUnary(fpop, fr_dst, fr_src));
3336          return fr_dst;
3337       }
3338    }
3339
3340    if (e->tag == Iex_Unop) {
3341       switch (e->Iex.Unop.op) {
3342          case Iop_ReinterpI64asF64: {
3343             /* Given an I64, produce an IEEE754 double with the same
3344                bit pattern. */
3345             if (!mode64) {
3346                HReg r_srcHi, r_srcLo;
3347                iselInt64Expr( &r_srcHi, &r_srcLo, env, e->Iex.Unop.arg);
3348                return mk_LoadRR32toFPR( env, r_srcHi, r_srcLo );
3349             } else {
3350                HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3351                return mk_LoadR64toFPR( env, r_src );
3352             }
3353          }
3354          case Iop_F32toF64: {
3355             /* this is a no-op */
3356             HReg res = iselFltExpr(env, e->Iex.Unop.arg);
3357             return res;
3358          }
3359          default: 
3360             break;
3361       }
3362    }
3363
3364    /* --------- MULTIPLEX --------- */
3365    if (e->tag == Iex_Mux0X) {
3366       if (ty == Ity_F64
3367           && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
3368          PPCCondCode cc = mk_PPCCondCode( Pct_TRUE, Pcf_7EQ );
3369          HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
3370          HReg frX    = iselDblExpr(env, e->Iex.Mux0X.exprX);
3371          HReg fr0    = iselDblExpr(env, e->Iex.Mux0X.expr0);
3372          HReg fr_dst = newVRegF(env);
3373          HReg r_tmp  = newVRegI(env);
3374          addInstr(env, PPCInstr_Alu(Palu_AND, r_tmp,
3375                                     r_cond, PPCRH_Imm(False,0xFF)));
3376          addInstr(env, PPCInstr_FpUnary( Pfp_MOV, fr_dst, frX ));
3377          addInstr(env, PPCInstr_Cmp(False/*unsigned*/, True/*32bit cmp*/,
3378                                     7/*cr*/, r_tmp, PPCRH_Imm(False,0)));
3379          addInstr(env, PPCInstr_FpCMov( cc, fr_dst, fr0 ));
3380          return fr_dst;
3381       }
3382    }
3383
3384    vex_printf("iselDblExpr(ppc): No such tag(%u)\n", e->tag);
3385    ppIRExpr(e);
3386    vpanic("iselDblExpr_wrk(ppc)");
3387 }
3388
3389
3390 /*---------------------------------------------------------*/
3391 /*--- ISEL: SIMD (Vector) expressions, 128 bit.         ---*/
3392 /*---------------------------------------------------------*/
3393
3394 static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
3395 {
3396    HReg r = iselVecExpr_wrk( env, e );
3397 #  if 0
3398    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
3399 #  endif
3400    vassert(hregClass(r) == HRcVec128);
3401    vassert(hregIsVirtual(r));
3402    return r;
3403 }
3404
3405 /* DO NOT CALL THIS DIRECTLY */
3406 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
3407 {
3408    Bool mode64 = env->mode64;
3409    PPCAvOp op = Pav_INVALID;
3410    PPCAvFpOp fpop = Pavfp_INVALID;
3411    IRType  ty = typeOfIRExpr(env->type_env,e);
3412    vassert(e);
3413    vassert(ty == Ity_V128);
3414
3415    if (e->tag == Iex_RdTmp) {
3416       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3417    }
3418
3419    if (e->tag == Iex_Get) {
3420       /* Guest state vectors are 16byte aligned,
3421          so don't need to worry here */
3422       HReg dst = newVRegV(env);
3423       addInstr(env,
3424                PPCInstr_AvLdSt( True/*load*/, 16, dst,
3425                                 PPCAMode_IR( e->Iex.Get.offset,
3426                                              GuestStatePtr(mode64) )));
3427       return dst;
3428    }
3429
3430    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_BE) {
3431       PPCAMode* am_addr;
3432       HReg v_dst = newVRegV(env);
3433       vassert(e->Iex.Load.ty == Ity_V128);
3434       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, Ity_V128/*xfer*/);
3435       addInstr(env, PPCInstr_AvLdSt( True/*load*/, 16, v_dst, am_addr));
3436       return v_dst;
3437    }
3438
3439    if (e->tag == Iex_Unop) {
3440       switch (e->Iex.Unop.op) {
3441
3442       case Iop_NotV128: {
3443          HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3444          HReg dst = newVRegV(env);
3445          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, arg));
3446          return dst;
3447       }
3448
3449       case Iop_CmpNEZ8x16: {
3450          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg);
3451          HReg zero = newVRegV(env);
3452          HReg dst  = newVRegV(env);
3453          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3454          addInstr(env, PPCInstr_AvBin8x16(Pav_CMPEQU, dst, arg, zero));
3455          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3456          return dst;
3457       }
3458
3459       case Iop_CmpNEZ16x8: {
3460          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg);
3461          HReg zero = newVRegV(env);
3462          HReg dst  = newVRegV(env);
3463          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3464          addInstr(env, PPCInstr_AvBin16x8(Pav_CMPEQU, dst, arg, zero));
3465          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3466          return dst;
3467       }
3468
3469       case Iop_CmpNEZ32x4: {
3470          HReg arg  = iselVecExpr(env, e->Iex.Unop.arg);
3471          HReg zero = newVRegV(env);
3472          HReg dst  = newVRegV(env);
3473          addInstr(env, PPCInstr_AvBinary(Pav_XOR, zero, zero, zero));
3474          addInstr(env, PPCInstr_AvBin32x4(Pav_CMPEQU, dst, arg, zero));
3475          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3476          return dst;
3477       }
3478
3479       case Iop_Recip32Fx4:    fpop = Pavfp_RCPF;    goto do_32Fx4_unary;
3480       case Iop_RSqrt32Fx4:    fpop = Pavfp_RSQRTF;  goto do_32Fx4_unary;
3481       case Iop_I32UtoFx4:     fpop = Pavfp_CVTU2F;  goto do_32Fx4_unary;
3482       case Iop_I32StoFx4:     fpop = Pavfp_CVTS2F;  goto do_32Fx4_unary;
3483       case Iop_QFtoI32Ux4_RZ: fpop = Pavfp_QCVTF2U; goto do_32Fx4_unary;
3484       case Iop_QFtoI32Sx4_RZ: fpop = Pavfp_QCVTF2S; goto do_32Fx4_unary;
3485       case Iop_RoundF32x4_RM: fpop = Pavfp_ROUNDM;  goto do_32Fx4_unary;
3486       case Iop_RoundF32x4_RP: fpop = Pavfp_ROUNDP;  goto do_32Fx4_unary;
3487       case Iop_RoundF32x4_RN: fpop = Pavfp_ROUNDN;  goto do_32Fx4_unary;
3488       case Iop_RoundF32x4_RZ: fpop = Pavfp_ROUNDZ;  goto do_32Fx4_unary;
3489       do_32Fx4_unary:
3490       {
3491          HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
3492          HReg dst = newVRegV(env);
3493          addInstr(env, PPCInstr_AvUn32Fx4(fpop, dst, arg));
3494          return dst;
3495       }
3496
3497       case Iop_32UtoV128: {
3498          HReg r_aligned16, r_zeros;
3499          HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3500          HReg   dst = newVRegV(env);
3501          PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
3502          sub_from_sp( env, 32 );     // Move SP down
3503
3504          /* Get a quadword aligned address within our stack space */
3505          r_aligned16 = get_sp_aligned16( env );
3506          am_off0  = PPCAMode_IR( 0,  r_aligned16 );
3507          am_off4  = PPCAMode_IR( 4,  r_aligned16 );
3508          am_off8  = PPCAMode_IR( 8,  r_aligned16 );
3509          am_off12 = PPCAMode_IR( 12, r_aligned16 );
3510
3511          /* Store zeros */
3512          r_zeros = newVRegI(env);
3513          addInstr(env, PPCInstr_LI(r_zeros, 0x0, mode64));
3514          addInstr(env, PPCInstr_Store( 4, am_off0, r_zeros, mode64 ));
3515          addInstr(env, PPCInstr_Store( 4, am_off4, r_zeros, mode64 ));
3516          addInstr(env, PPCInstr_Store( 4, am_off8, r_zeros, mode64 ));
3517
3518          /* Store r_src in low word of quadword-aligned mem */
3519          addInstr(env, PPCInstr_Store( 4, am_off12, r_src, mode64 ));
3520
3521          /* Load word into low word of quadword vector reg */
3522          addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, dst, am_off12 ));
3523
3524          add_to_sp( env, 32 );       // Reset SP
3525          return dst;
3526       }
3527
3528       case Iop_Dup8x16:
3529       case Iop_Dup16x8:
3530       case Iop_Dup32x4:
3531          return mk_AvDuplicateRI(env, e->Iex.Binop.arg1);
3532
3533       default:
3534          break;
3535       } /* switch (e->Iex.Unop.op) */
3536    } /* if (e->tag == Iex_Unop) */
3537
3538    if (e->tag == Iex_Binop) {
3539       switch (e->Iex.Binop.op) {
3540
3541       case Iop_64HLtoV128: {
3542          if (!mode64) {
3543             HReg     r3, r2, r1, r0, r_aligned16;
3544             PPCAMode *am_off0, *am_off4, *am_off8, *am_off12;
3545             HReg     dst = newVRegV(env);
3546             /* do this via the stack (easy, convenient, etc) */
3547             sub_from_sp( env, 32 );        // Move SP down
3548             
3549             // get a quadword aligned address within our stack space
3550             r_aligned16 = get_sp_aligned16( env );
3551             am_off0  = PPCAMode_IR( 0,  r_aligned16 );
3552             am_off4  = PPCAMode_IR( 4,  r_aligned16 );
3553             am_off8  = PPCAMode_IR( 8,  r_aligned16 );
3554             am_off12 = PPCAMode_IR( 12, r_aligned16 );
3555             
3556             /* Do the less significant 64 bits */
3557             iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2);
3558             addInstr(env, PPCInstr_Store( 4, am_off12, r0, mode64 ));
3559             addInstr(env, PPCInstr_Store( 4, am_off8,  r1, mode64 ));
3560             /* Do the more significant 64 bits */
3561             iselInt64Expr(&r3, &r2, env, e->Iex.Binop.arg1);
3562             addInstr(env, PPCInstr_Store( 4, am_off4, r2, mode64 ));
3563             addInstr(env, PPCInstr_Store( 4, am_off0, r3, mode64 ));
3564             
3565             /* Fetch result back from stack. */
3566             addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
3567             
3568             add_to_sp( env, 32 );          // Reset SP
3569             return dst;
3570          } else {
3571             HReg     rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
3572             HReg     rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
3573             HReg     dst = newVRegV(env);
3574             HReg     r_aligned16;
3575             PPCAMode *am_off0, *am_off8;
3576             /* do this via the stack (easy, convenient, etc) */
3577             sub_from_sp( env, 32 );        // Move SP down
3578             
3579             // get a quadword aligned address within our stack space
3580             r_aligned16 = get_sp_aligned16( env );
3581             am_off0  = PPCAMode_IR( 0,  r_aligned16 );
3582             am_off8  = PPCAMode_IR( 8,  r_aligned16 );
3583             
3584             /* Store 2*I64 to stack */
3585             addInstr(env, PPCInstr_Store( 8, am_off0, rHi, mode64 ));
3586             addInstr(env, PPCInstr_Store( 8, am_off8, rLo, mode64 ));
3587
3588             /* Fetch result back from stack. */
3589             addInstr(env, PPCInstr_AvLdSt(True/*ld*/, 16, dst, am_off0));
3590             
3591             add_to_sp( env, 32 );          // Reset SP
3592             return dst;
3593          }
3594       }
3595
3596       case Iop_Add32Fx4:   fpop = Pavfp_ADDF;   goto do_32Fx4;
3597       case Iop_Sub32Fx4:   fpop = Pavfp_SUBF;   goto do_32Fx4;
3598       case Iop_Max32Fx4:   fpop = Pavfp_MAXF;   goto do_32Fx4;
3599       case Iop_Min32Fx4:   fpop = Pavfp_MINF;   goto do_32Fx4;
3600       case Iop_Mul32Fx4:   fpop = Pavfp_MULF;   goto do_32Fx4;
3601       case Iop_CmpEQ32Fx4: fpop = Pavfp_CMPEQF; goto do_32Fx4;
3602       case Iop_CmpGT32Fx4: fpop = Pavfp_CMPGTF; goto do_32Fx4;
3603       case Iop_CmpGE32Fx4: fpop = Pavfp_CMPGEF; goto do_32Fx4;
3604       do_32Fx4:
3605       {
3606          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3607          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3608          HReg dst = newVRegV(env);
3609          addInstr(env, PPCInstr_AvBin32Fx4(fpop, dst, argL, argR));
3610          return dst;
3611       }
3612
3613       case Iop_CmpLE32Fx4: {
3614          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
3615          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
3616          HReg dst = newVRegV(env);
3617          
3618          /* stay consistent with native ppc compares:
3619             if a left/right lane holds a nan, return zeros for that lane
3620             so: le == NOT(gt OR isNan)
3621           */
3622          HReg isNanLR = newVRegV(env);
3623          HReg isNanL = isNan(env, argL);
3624          HReg isNanR = isNan(env, argR);
3625          addInstr(env, PPCInstr_AvBinary(Pav_OR, isNanLR,
3626                                          isNanL, isNanR));
3627
3628          addInstr(env, PPCInstr_AvBin32Fx4(Pavfp_CMPGTF, dst,
3629                                            argL, argR));
3630          addInstr(env, PPCInstr_AvBinary(Pav_OR, dst, dst, isNanLR));
3631          addInstr(env, PPCInstr_AvUnary(Pav_NOT, dst, dst));
3632          return dst;
3633       }
3634
3635       case Iop_AndV128:    op = Pav_AND;      goto do_AvBin;
3636       case Iop_OrV128:     op = Pav_OR;       goto do_AvBin;
3637       case Iop_XorV128:    op = Pav_XOR;      goto do_AvBin;
3638       do_AvBin: {
3639          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3640          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3641          HReg dst  = newVRegV(env);
3642          addInstr(env, PPCInstr_AvBinary(op, dst, arg1, arg2));
3643          return dst;
3644       }
3645
3646       case Iop_Shl8x16:    op = Pav_SHL;    goto do_AvBin8x16;
3647       case Iop_Shr8x16:    op = Pav_SHR;    goto do_AvBin8x16;
3648       case Iop_Sar8x16:    op = Pav_SAR;    goto do_AvBin8x16;
3649       case Iop_Rol8x16:    op = Pav_ROTL;   goto do_AvBin8x16;
3650       case Iop_InterleaveHI8x16: op = Pav_MRGHI;  goto do_AvBin8x16;
3651       case Iop_InterleaveLO8x16: op = Pav_MRGLO;  goto do_AvBin8x16;
3652       case Iop_Add8x16:    op = Pav_ADDU;   goto do_AvBin8x16;
3653       case Iop_QAdd8Ux16:  op = Pav_QADDU;  goto do_AvBin8x16;
3654       case Iop_QAdd8Sx16:  op = Pav_QADDS;  goto do_AvBin8x16;
3655       case Iop_Sub8x16:    op = Pav_SUBU;   goto do_AvBin8x16;
3656       case Iop_QSub8Ux16:  op = Pav_QSUBU;  goto do_AvBin8x16;
3657       case Iop_QSub8Sx16:  op = Pav_QSUBS;  goto do_AvBin8x16;
3658       case Iop_Avg8Ux16:   op = Pav_AVGU;   goto do_AvBin8x16;
3659       case Iop_Avg8Sx16:   op = Pav_AVGS;   goto do_AvBin8x16;
3660       case Iop_Max8Ux16:   op = Pav_MAXU;   goto do_AvBin8x16;
3661       case Iop_Max8Sx16:   op = Pav_MAXS;   goto do_AvBin8x16;
3662       case Iop_Min8Ux16:   op = Pav_MINU;   goto do_AvBin8x16;
3663       case Iop_Min8Sx16:   op = Pav_MINS;   goto do_AvBin8x16;
3664       case Iop_MullEven8Ux16: op = Pav_OMULU;  goto do_AvBin8x16;
3665       case Iop_MullEven8Sx16: op = Pav_OMULS;  goto do_AvBin8x16;
3666       case Iop_CmpEQ8x16:  op = Pav_CMPEQU; goto do_AvBin8x16;
3667       case Iop_CmpGT8Ux16: op = Pav_CMPGTU; goto do_AvBin8x16;
3668       case Iop_CmpGT8Sx16: op = Pav_CMPGTS; goto do_AvBin8x16;
3669       do_AvBin8x16: {
3670          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3671          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3672          HReg dst  = newVRegV(env);
3673          addInstr(env, PPCInstr_AvBin8x16(op, dst, arg1, arg2));
3674          return dst;
3675       }
3676
3677       case Iop_Shl16x8:    op = Pav_SHL;    goto do_AvBin16x8;
3678       case Iop_Shr16x8:    op = Pav_SHR;    goto do_AvBin16x8;
3679       case Iop_Sar16x8:    op = Pav_SAR;    goto do_AvBin16x8;
3680       case Iop_Rol16x8:    op = Pav_ROTL;   goto do_AvBin16x8;
3681       case Iop_Narrow16x8:       op = Pav_PACKUU;  goto do_AvBin16x8;
3682       case Iop_QNarrow16Ux8:     op = Pav_QPACKUU; goto do_AvBin16x8;
3683       case Iop_QNarrow16Sx8:     op = Pav_QPACKSS; goto do_AvBin16x8;
3684       case Iop_InterleaveHI16x8: op = Pav_MRGHI;  goto do_AvBin16x8;
3685       case Iop_InterleaveLO16x8: op = Pav_MRGLO;  goto do_AvBin16x8;
3686       case Iop_Add16x8:    op = Pav_ADDU;   goto do_AvBin16x8;
3687       case Iop_QAdd16Ux8:  op = Pav_QADDU;  goto do_AvBin16x8;
3688       case Iop_QAdd16Sx8:  op = Pav_QADDS;  goto do_AvBin16x8;
3689       case Iop_Sub16x8:    op = Pav_SUBU;   goto do_AvBin16x8;
3690       case Iop_QSub16Ux8:  op = Pav_QSUBU;  goto do_AvBin16x8;
3691       case Iop_QSub16Sx8:  op = Pav_QSUBS;  goto do_AvBin16x8;
3692       case Iop_Avg16Ux8:   op = Pav_AVGU;   goto do_AvBin16x8;
3693       case Iop_Avg16Sx8:   op = Pav_AVGS;   goto do_AvBin16x8;
3694       case Iop_Max16Ux8:   op = Pav_MAXU;   goto do_AvBin16x8;
3695       case Iop_Max16Sx8:   op = Pav_MAXS;   goto do_AvBin16x8;
3696       case Iop_Min16Ux8:   op = Pav_MINU;   goto do_AvBin16x8;
3697       case Iop_Min16Sx8:   op = Pav_MINS;   goto do_AvBin16x8;
3698       case Iop_MullEven16Ux8: op = Pav_OMULU;  goto do_AvBin16x8;
3699       case Iop_MullEven16Sx8: op = Pav_OMULS;  goto do_AvBin16x8;
3700       case Iop_CmpEQ16x8:  op = Pav_CMPEQU; goto do_AvBin16x8;
3701       case Iop_CmpGT16Ux8: op = Pav_CMPGTU; goto do_AvBin16x8;
3702       case Iop_CmpGT16Sx8: op = Pav_CMPGTS; goto do_AvBin16x8;
3703       do_AvBin16x8: {
3704          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3705          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3706          HReg dst  = newVRegV(env);
3707          addInstr(env, PPCInstr_AvBin16x8(op, dst, arg1, arg2));
3708          return dst;
3709       }
3710
3711       case Iop_Shl32x4:    op = Pav_SHL;    goto do_AvBin32x4;
3712       case Iop_Shr32x4:    op = Pav_SHR;    goto do_AvBin32x4;
3713       case Iop_Sar32x4:    op = Pav_SAR;    goto do_AvBin32x4;
3714       case Iop_Rol32x4:    op = Pav_ROTL;   goto do_AvBin32x4;
3715       case Iop_Narrow32x4:       op = Pav_PACKUU;  goto do_AvBin32x4;
3716       case Iop_QNarrow32Ux4:     op = Pav_QPACKUU; goto do_AvBin32x4;
3717       case Iop_QNarrow32Sx4:     op = Pav_QPACKSS; goto do_AvBin32x4;
3718       case Iop_InterleaveHI32x4: op = Pav_MRGHI;  goto do_AvBin32x4;
3719       case Iop_InterleaveLO32x4: op = Pav_MRGLO;  goto do_AvBin32x4;
3720       case Iop_Add32x4:    op = Pav_ADDU;   goto do_AvBin32x4;
3721       case Iop_QAdd32Ux4:  op = Pav_QADDU;  goto do_AvBin32x4;
3722       case Iop_QAdd32Sx4:  op = Pav_QADDS;  goto do_AvBin32x4;
3723       case Iop_Sub32x4:    op = Pav_SUBU;   goto do_AvBin32x4;
3724       case Iop_QSub32Ux4:  op = Pav_QSUBU;  goto do_AvBin32x4;
3725       case Iop_QSub32Sx4:  op = Pav_QSUBS;  goto do_AvBin32x4;
3726       case Iop_Avg32Ux4:   op = Pav_AVGU;   goto do_AvBin32x4;
3727       case Iop_Avg32Sx4:   op = Pav_AVGS;   goto do_AvBin32x4;
3728       case Iop_Max32Ux4:   op = Pav_MAXU;   goto do_AvBin32x4;
3729       case Iop_Max32Sx4:   op = Pav_MAXS;   goto do_AvBin32x4;
3730       case Iop_Min32Ux4:   op = Pav_MINU;   goto do_AvBin32x4;
3731       case Iop_Min32Sx4:   op = Pav_MINS;   goto do_AvBin32x4;
3732       case Iop_CmpEQ32x4:  op = Pav_CMPEQU; goto do_AvBin32x4;
3733       case Iop_CmpGT32Ux4: op = Pav_CMPGTU; goto do_AvBin32x4;
3734       case Iop_CmpGT32Sx4: op = Pav_CMPGTS; goto do_AvBin32x4;
3735       do_AvBin32x4: {
3736          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
3737          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
3738          HReg dst  = newVRegV(env);
3739          addInstr(env, PPCInstr_AvBin32x4(op, dst, arg1, arg2));
3740          return dst;
3741       }
3742
3743       case Iop_ShlN8x16: op = Pav_SHL; goto do_AvShift8x16;
3744       case Iop_SarN8x16: op = Pav_SAR; goto do_AvShift8x16;
3745       do_AvShift8x16: {
3746          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3747          HReg dst    = newVRegV(env);
3748          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3749          addInstr(env, PPCInstr_AvBin8x16(op, dst, r_src, v_shft));
3750          return dst;
3751       }
3752
3753       case Iop_ShlN16x8: op = Pav_SHL; goto do_AvShift16x8;
3754       case Iop_ShrN16x8: op = Pav_SHR; goto do_AvShift16x8;
3755       case Iop_SarN16x8: op = Pav_SAR; goto do_AvShift16x8;
3756       do_AvShift16x8: {
3757          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3758          HReg dst    = newVRegV(env);
3759          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3760          addInstr(env, PPCInstr_AvBin16x8(op, dst, r_src, v_shft));
3761          return dst;
3762       }
3763
3764       case Iop_ShlN32x4: op = Pav_SHL; goto do_AvShift32x4;
3765       case Iop_ShrN32x4: op = Pav_SHR; goto do_AvShift32x4;
3766       case Iop_SarN32x4: op = Pav_SAR; goto do_AvShift32x4;
3767       do_AvShift32x4: {
3768          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3769          HReg dst    = newVRegV(env);
3770          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3771          addInstr(env, PPCInstr_AvBin32x4(op, dst, r_src, v_shft));
3772          return dst;
3773       }
3774
3775       case Iop_ShrV128: op = Pav_SHR; goto do_AvShiftV128;
3776       case Iop_ShlV128: op = Pav_SHL; goto do_AvShiftV128;
3777       do_AvShiftV128: {
3778          HReg dst    = newVRegV(env);
3779          HReg r_src  = iselVecExpr(env, e->Iex.Binop.arg1);
3780          HReg v_shft = mk_AvDuplicateRI(env, e->Iex.Binop.arg2);
3781          /* Note: shift value gets masked by 127 */
3782          addInstr(env, PPCInstr_AvBinary(op, dst, r_src, v_shft));
3783          return dst;
3784       }
3785
3786       case Iop_Perm8x16: {
3787          HReg dst   = newVRegV(env);
3788          HReg v_src = iselVecExpr(env, e->Iex.Binop.arg1);
3789          HReg v_ctl = iselVecExpr(env, e->Iex.Binop.arg2);
3790          addInstr(env, PPCInstr_AvPerm(dst, v_src, v_src, v_ctl));
3791          return dst;
3792       }
3793
3794       default:
3795          break;
3796       } /* switch (e->Iex.Binop.op) */
3797    } /* if (e->tag == Iex_Binop) */
3798
3799    if (e->tag == Iex_Const ) {
3800       vassert(e->Iex.Const.con->tag == Ico_V128);
3801       if (e->Iex.Const.con->Ico.V128 == 0x0000) {
3802          return generate_zeroes_V128(env);
3803       } 
3804       else if (e->Iex.Const.con->Ico.V128 == 0xffff) {
3805          return generate_ones_V128(env);
3806       }
3807    }
3808
3809    vex_printf("iselVecExpr(ppc) (subarch = %s): can't reduce\n",
3810               LibVEX_ppVexHwCaps(mode64 ? VexArchPPC64 : VexArchPPC32,
3811                                  env->hwcaps));
3812    ppIRExpr(e);
3813    vpanic("iselVecExpr_wrk(ppc)");
3814 }
3815
3816
3817 /*---------------------------------------------------------*/
3818 /*--- ISEL: Statements                                  ---*/
3819 /*---------------------------------------------------------*/
3820
3821 static void iselStmt ( ISelEnv* env, IRStmt* stmt )
3822 {
3823    Bool mode64 = env->mode64;
3824    if (vex_traceflags & VEX_TRACE_VCODE) {
3825       vex_printf("\n -- ");
3826       ppIRStmt(stmt);
3827       vex_printf("\n");
3828    }
3829
3830    switch (stmt->tag) {
3831
3832    /* --------- STORE --------- */
3833    case Ist_Store: {
3834       IRType    tya   = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
3835       IRType    tyd   = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3836       IREndness end   = stmt->Ist.Store.end;
3837
3838       if (end != Iend_BE)
3839          goto stmt_fail;
3840       if (!mode64 && (tya != Ity_I32))
3841          goto stmt_fail;
3842       if (mode64 && (tya != Ity_I64))
3843          goto stmt_fail;
3844
3845       if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
3846           (mode64 && (tyd == Ity_I64))) {
3847          PPCAMode* am_addr
3848             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3849          HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
3850          addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(tyd)), 
3851                                        am_addr, r_src, mode64 ));
3852          return;
3853       }
3854       if (tyd == Ity_F64) {
3855          PPCAMode* am_addr
3856             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3857          HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
3858          addInstr(env,
3859                   PPCInstr_FpLdSt(False/*store*/, 8, fr_src, am_addr));
3860          return;
3861       }
3862       if (tyd == Ity_F32) {
3863          PPCAMode* am_addr
3864             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3865          HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3866          addInstr(env,
3867                   PPCInstr_FpLdSt(False/*store*/, 4, fr_src, am_addr));
3868          return;
3869       }
3870       if (tyd == Ity_V128) {
3871          PPCAMode* am_addr
3872             = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd/*of xfer*/);
3873          HReg v_src = iselVecExpr(env, stmt->Ist.Store.data);
3874          addInstr(env,
3875                   PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
3876          return;
3877       }
3878       if (tyd == Ity_I64 && !mode64) {
3879          /* Just calculate the address in the register.  Life is too
3880             short to arse around trying and possibly failing to adjust
3881             the offset in a 'reg+offset' style amode. */
3882          HReg rHi32, rLo32;
3883          HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
3884          iselInt64Expr( &rHi32, &rLo32, env, stmt->Ist.Store.data );
3885          addInstr(env, PPCInstr_Store( 4/*byte-store*/,
3886                                        PPCAMode_IR( 0, r_addr ), 
3887                                        rHi32,
3888                                        False/*32-bit insn please*/) );
3889          addInstr(env, PPCInstr_Store( 4/*byte-store*/, 
3890                                        PPCAMode_IR( 4, r_addr ), 
3891                                        rLo32,
3892                                        False/*32-bit insn please*/) );
3893          return;
3894       }
3895       break;
3896    }
3897
3898    /* --------- PUT --------- */
3899    case Ist_Put: {
3900       IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3901       if (ty == Ity_I8  || ty == Ity_I16 ||
3902           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
3903          HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
3904          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3905                                           GuestStatePtr(mode64) );
3906          addInstr(env, PPCInstr_Store( toUChar(sizeofIRType(ty)), 
3907                                        am_addr, r_src, mode64 ));
3908          return;
3909       }
3910       if (!mode64 && ty == Ity_I64) {
3911          HReg rHi, rLo;
3912          PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
3913                                            GuestStatePtr(mode64) );
3914          PPCAMode* am_addr4 = advance4(env, am_addr);
3915          iselInt64Expr(&rHi,&rLo, env, stmt->Ist.Put.data);
3916          addInstr(env, PPCInstr_Store( 4, am_addr,  rHi, mode64 ));
3917          addInstr(env, PPCInstr_Store( 4, am_addr4, rLo, mode64 ));
3918          return;
3919      }
3920      if (ty == Ity_V128) {
3921          /* Guest state vectors are 16byte aligned,
3922             so don't need to worry here */
3923          HReg v_src = iselVecExpr(env, stmt->Ist.Put.data);
3924          PPCAMode* am_addr  = PPCAMode_IR( stmt->Ist.Put.offset,
3925                                            GuestStatePtr(mode64) );
3926          addInstr(env,
3927                   PPCInstr_AvLdSt(False/*store*/, 16, v_src, am_addr));
3928          return;
3929       }
3930       if (ty == Ity_F64) {
3931          HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data);
3932          PPCAMode* am_addr = PPCAMode_IR( stmt->Ist.Put.offset,
3933                                           GuestStatePtr(mode64) );
3934          addInstr(env, PPCInstr_FpLdSt( False/*store*/, 8,
3935                                         fr_src, am_addr ));
3936          return;
3937       }
3938       break;
3939    }
3940       
3941    /* --------- Indexed PUT --------- */
3942    case Ist_PutI: {
3943       PPCAMode* dst_am
3944          = genGuestArrayOffset(
3945               env, stmt->Ist.PutI.descr, 
3946                    stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
3947       IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
3948       if (mode64 && ty == Ity_I64) {
3949          HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data);
3950          addInstr(env, PPCInstr_Store( toUChar(8),
3951                                        dst_am, r_src, mode64 ));
3952          return;
3953       }
3954       if ((!mode64) && ty == Ity_I32) {
3955          HReg r_src = iselWordExpr_R(env, stmt->Ist.PutI.data);
3956          addInstr(env, PPCInstr_Store( toUChar(4),
3957                                        dst_am, r_src, mode64 ));
3958          return;
3959       }
3960       break;
3961    }
3962
3963    /* --------- TMP --------- */
3964    case Ist_WrTmp: {
3965       IRTemp tmp = stmt->Ist.WrTmp.tmp;
3966       IRType ty = typeOfIRTemp(env->type_env, tmp);
3967       if (ty == Ity_I8  || ty == Ity_I16 ||
3968           ty == Ity_I32 || ((ty == Ity_I64) && mode64)) {
3969          HReg r_dst = lookupIRTemp(env, tmp);
3970          HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3971          addInstr(env, mk_iMOVds_RR( r_dst, r_src ));
3972          return;
3973       }
3974       if (!mode64 && ty == Ity_I64) {
3975          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
3976          iselInt64Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
3977          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
3978          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
3979          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
3980          return;
3981       }
3982       if (mode64 && ty == Ity_I128) {
3983          HReg r_srcHi, r_srcLo, r_dstHi, r_dstLo;
3984          iselInt128Expr(&r_srcHi,&r_srcLo, env, stmt->Ist.WrTmp.data);
3985          lookupIRTempPair( &r_dstHi, &r_dstLo, env, tmp);
3986          addInstr(env, mk_iMOVds_RR(r_dstHi, r_srcHi) );
3987          addInstr(env, mk_iMOVds_RR(r_dstLo, r_srcLo) );
3988          return;
3989       }
3990       if (ty == Ity_I1) {
3991          PPCCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
3992          HReg r_dst = lookupIRTemp(env, tmp);
3993          addInstr(env, PPCInstr_Set(cond, r_dst));
3994          return;
3995       }
3996       if (ty == Ity_F64) {
3997          HReg fr_dst = lookupIRTemp(env, tmp);
3998          HReg fr_src = iselDblExpr(env, stmt->Ist.WrTmp.data);
3999          addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
4000          return;
4001       }
4002       if (ty == Ity_F32) {
4003          HReg fr_dst = lookupIRTemp(env, tmp);
4004          HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
4005          addInstr(env, PPCInstr_FpUnary(Pfp_MOV, fr_dst, fr_src));
4006          return;
4007       }
4008       if (ty == Ity_V128) {
4009          HReg v_dst = lookupIRTemp(env, tmp);
4010          HReg v_src = iselVecExpr(env, stmt->Ist.WrTmp.data);
4011          addInstr(env, PPCInstr_AvUnary(Pav_MOV, v_dst, v_src));
4012          return;
4013       }
4014       break;
4015    }
4016
4017    /* --------- Load Linked or Store Conditional --------- */
4018    case Ist_LLSC: {
4019       IRTemp res    = stmt->Ist.LLSC.result;
4020       IRType tyRes  = typeOfIRTemp(env->type_env, res);
4021       IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
4022
4023       if (stmt->Ist.LLSC.end != Iend_BE)
4024          goto stmt_fail;
4025       if (!mode64 && (tyAddr != Ity_I32))
4026          goto stmt_fail;
4027       if (mode64 && (tyAddr != Ity_I64))
4028          goto stmt_fail;
4029
4030       if (stmt->Ist.LLSC.storedata == NULL) {
4031          /* LL */
4032          HReg r_addr = iselWordExpr_R( env, stmt->Ist.LLSC.addr );
4033          HReg r_dst  = lookupIRTemp(env, res);
4034          if (tyRes == Ity_I32) {
4035             addInstr(env, PPCInstr_LoadL( 4, r_dst, r_addr, mode64 ));
4036             return;
4037          }
4038          if (tyRes == Ity_I64 && mode64) {
4039             addInstr(env, PPCInstr_LoadL( 8, r_dst, r_addr, mode64 ));
4040             return;
4041          }
4042          /* fallthru */;
4043       } else {
4044          /* SC */
4045          HReg   r_res  = lookupIRTemp(env, res); /* :: Ity_I1 */
4046          HReg   r_a    = iselWordExpr_R(env, stmt->Ist.LLSC.addr);
4047          HReg   r_src  = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
4048          HReg   r_tmp  = newVRegI(env);
4049          IRType tyData = typeOfIRExpr(env->type_env,
4050                                       stmt->Ist.LLSC.storedata);
4051          vassert(tyRes == Ity_I1);
4052          if (tyData == Ity_I32 || (tyData == Ity_I64 && mode64)) {
4053             addInstr(env, PPCInstr_StoreC( tyData==Ity_I32 ? 4 : 8,
4054                                            r_a, r_src, mode64 ));
4055             addInstr(env, PPCInstr_MfCR( r_tmp ));
4056             addInstr(env, PPCInstr_Shft(
4057                              Pshft_SHR,
4058                              env->mode64 ? False : True
4059                                 /*F:64-bit, T:32-bit shift*/,
4060                              r_tmp, r_tmp, 
4061                              PPCRH_Imm(False/*unsigned*/, 29)));
4062             /* Probably unnecessary, since the IR dest type is Ity_I1,
4063                and so we are entitled to leave whatever junk we like
4064                drifting round in the upper 31 or 63 bits of r_res.
4065                However, for the sake of conservativeness .. */
4066             addInstr(env, PPCInstr_Alu(
4067                              Palu_AND, 
4068                              r_res, r_tmp, 
4069                              PPCRH_Imm(False/*signed*/, 1)));
4070             return;
4071          }
4072          /* fallthru */
4073       }
4074       goto stmt_fail;
4075       /*NOTREACHED*/
4076    }
4077
4078    /* --------- Call to DIRTY helper --------- */
4079    case Ist_Dirty: {
4080       IRType   retty;
4081       IRDirty* d = stmt->Ist.Dirty.details;
4082       Bool     passBBP = False;
4083
4084       if (d->nFxState == 0)
4085          vassert(!d->needsBBP);
4086       passBBP = toBool(d->nFxState > 0 && d->needsBBP);
4087
4088       /* Marshal args, do the call, clear stack. */
4089       doHelperCall( env, passBBP, d->guard, d->cee, d->args );
4090
4091       /* Now figure out what to do with the returned value, if any. */
4092       if (d->tmp == IRTemp_INVALID)
4093          /* No return value.  Nothing to do. */
4094          return;
4095
4096       retty = typeOfIRTemp(env->type_env, d->tmp);
4097       if (!mode64 && retty == Ity_I64) {
4098          HReg r_dstHi, r_dstLo;
4099          /* The returned value is in %r3:%r4.  Park it in the
4100             register-pair associated with tmp. */
4101          lookupIRTempPair( &r_dstHi, &r_dstLo, env, d->tmp);
4102          addInstr(env, mk_iMOVds_RR(r_dstHi, hregPPC_GPR3(mode64)));
4103          addInstr(env, mk_iMOVds_RR(r_dstLo, hregPPC_GPR4(mode64)));
4104          return;
4105       }
4106       if (retty == Ity_I8  || retty == Ity_I16 ||
4107           retty == Ity_I32 || ((retty == Ity_I64) && mode64)) {
4108          /* The returned value is in %r3.  Park it in the register
4109             associated with tmp. */
4110          HReg r_dst = lookupIRTemp(env, d->tmp);
4111          addInstr(env, mk_iMOVds_RR(r_dst, hregPPC_GPR3(mode64)));
4112          return;
4113       }
4114       break;
4115    }
4116
4117    /* --------- MEM FENCE --------- */
4118    case Ist_MBE:
4119       switch (stmt->Ist.MBE.event) {
4120          case Imbe_Fence:
4121             addInstr(env, PPCInstr_MFence());
4122             return;
4123          default:
4124             break;
4125       }
4126       break;
4127
4128    /* --------- INSTR MARK --------- */
4129    /* Doesn't generate any executable code ... */
4130    case Ist_IMark:
4131        return;
4132
4133    /* --------- ABI HINT --------- */
4134    /* These have no meaning (denotation in the IR) and so we ignore
4135       them ... if any actually made it this far. */
4136    case Ist_AbiHint:
4137        return;
4138
4139    /* --------- NO-OP --------- */
4140    /* Fairly self-explanatory, wouldn't you say? */
4141    case Ist_NoOp:
4142        return;
4143
4144    /* --------- EXIT --------- */
4145    case Ist_Exit: {
4146       PPCRI*      ri_dst;
4147       PPCCondCode cc;
4148       IRConstTag tag = stmt->Ist.Exit.dst->tag;
4149       if (!mode64 && (tag != Ico_U32))
4150          vpanic("iselStmt(ppc): Ist_Exit: dst is not a 32-bit value");
4151       if (mode64 && (tag != Ico_U64))
4152          vpanic("iselStmt(ppc64): Ist_Exit: dst is not a 64-bit value");
4153       ri_dst = iselWordExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
4154       cc     = iselCondCode(env,stmt->Ist.Exit.guard);
4155       addInstr(env, PPCInstr_RdWrLR(True, env->savedLR));
4156       addInstr(env, PPCInstr_Goto(stmt->Ist.Exit.jk, cc, ri_dst));
4157       return;
4158    }
4159
4160    default: break;
4161    }
4162   stmt_fail:
4163    ppIRStmt(stmt);
4164    vpanic("iselStmt(ppc)");
4165 }
4166  
4167
4168 /*---------------------------------------------------------*/
4169 /*--- ISEL: Basic block terminators (Nexts)             ---*/
4170 /*---------------------------------------------------------*/
4171
4172 static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
4173 {
4174    PPCCondCode cond;
4175    PPCRI* ri;
4176    if (vex_traceflags & VEX_TRACE_VCODE) {
4177       vex_printf("\n-- goto {");
4178       ppIRJumpKind(jk);
4179       vex_printf("} ");
4180       ppIRExpr(next);
4181       vex_printf("\n");
4182    }
4183    cond = mk_PPCCondCode( Pct_ALWAYS, Pcf_NONE );
4184    ri = iselWordExpr_RI(env, next);
4185    addInstr(env, PPCInstr_RdWrLR(True, env->savedLR));
4186    addInstr(env, PPCInstr_Goto(jk, cond, ri));
4187 }
4188
4189
4190 /*---------------------------------------------------------*/
4191 /*--- Insn selector top-level                           ---*/
4192 /*---------------------------------------------------------*/
4193
4194 /* Translate an entire BS to ppc code. */
4195
4196 HInstrArray* iselSB_PPC ( IRSB* bb, VexArch      arch_host,
4197                                     VexArchInfo* archinfo_host,
4198                                     VexAbiInfo*  vbi )
4199 {
4200    Int      i, j;
4201    HReg     hreg, hregHI;
4202    ISelEnv* env;
4203    UInt     hwcaps_host = archinfo_host->hwcaps;
4204    Bool     mode64 = False;
4205    UInt     mask32, mask64;
4206
4207    vassert(arch_host == VexArchPPC32 || arch_host == VexArchPPC64);
4208    mode64 = arch_host == VexArchPPC64;
4209
4210    /* do some sanity checks */
4211    mask32 = VEX_HWCAPS_PPC32_F | VEX_HWCAPS_PPC32_V
4212             | VEX_HWCAPS_PPC32_FX | VEX_HWCAPS_PPC32_GX | VEX_HWCAPS_PPC32_VX;
4213
4214    mask64 = VEX_HWCAPS_PPC64_V | VEX_HWCAPS_PPC64_FX
4215            | VEX_HWCAPS_PPC64_GX | VEX_HWCAPS_PPC64_VX;
4216
4217    if (mode64) {
4218       vassert((hwcaps_host & mask32) == 0);
4219    } else {
4220       vassert((hwcaps_host & mask64) == 0);
4221    }
4222
4223    /* Make up an initial environment to use. */
4224    env = LibVEX_Alloc(sizeof(ISelEnv));
4225    env->vreg_ctr = 0;
4226
4227    /* Are we being ppc32 or ppc64? */
4228    env->mode64 = mode64;
4229
4230    /* Set up output code array. */
4231    env->code = newHInstrArray();
4232
4233    /* Copy BB's type env. */
4234    env->type_env = bb->tyenv;
4235
4236    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
4237       change as we go along. */
4238    env->n_vregmap = bb->tyenv->types_used;
4239    env->vregmap   = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4240    env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
4241
4242    /* and finally ... */
4243    env->hwcaps      = hwcaps_host;
4244    env->previous_rm = NULL;
4245    env->vbi         = vbi;
4246
4247    /* For each IR temporary, allocate a suitably-kinded virtual
4248       register. */
4249    j = 0;
4250    for (i = 0; i < env->n_vregmap; i++) {
4251       hregHI = hreg = INVALID_HREG;
4252       switch (bb->tyenv->types[i]) {
4253       case Ity_I1:
4254       case Ity_I8:
4255       case Ity_I16:
4256       case Ity_I32:
4257          if (mode64) { hreg   = mkHReg(j++, HRcInt64,  True); break;
4258          } else {      hreg   = mkHReg(j++, HRcInt32,  True); break;
4259          }
4260       case Ity_I64:  
4261          if (mode64) { hreg   = mkHReg(j++, HRcInt64,  True); break;
4262          } else {      hreg   = mkHReg(j++, HRcInt32,  True);
4263                        hregHI = mkHReg(j++, HRcInt32,  True); break;
4264          }
4265       case Ity_I128:   vassert(mode64);
4266                        hreg   = mkHReg(j++, HRcInt64,  True);
4267                        hregHI = mkHReg(j++, HRcInt64,  True); break;
4268       case Ity_F32:
4269       case Ity_F64:    hreg   = mkHReg(j++, HRcFlt64,  True); break;
4270       case Ity_V128:   hreg   = mkHReg(j++, HRcVec128, True); break;
4271       default:
4272          ppIRType(bb->tyenv->types[i]);
4273          vpanic("iselBB(ppc): IRTemp type");
4274       }
4275       env->vregmap[i]   = hreg;
4276       env->vregmapHI[i] = hregHI;
4277    }
4278    env->vreg_ctr = j;
4279
4280    /* Keep a copy of the link reg, so helper functions don't kill it. */
4281    env->savedLR = newVRegI(env);
4282    addInstr(env, PPCInstr_RdWrLR(False, env->savedLR));
4283
4284    /* Ok, finally we can iterate over the statements. */
4285    for (i = 0; i < bb->stmts_used; i++)
4286       if (bb->stmts[i])
4287          iselStmt(env,bb->stmts[i]);
4288
4289    iselNext(env,bb->next,bb->jumpkind);
4290
4291    /* record the number of vregs we used. */
4292    env->code->n_vregs = env->vreg_ctr;
4293    return env->code;
4294 }
4295
4296
4297 /*---------------------------------------------------------------*/
4298 /*--- end                                     host_ppc_isel.c ---*/
4299 /*---------------------------------------------------------------*/