]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/VEX/priv/host_arm_isel.c
ed41b8e91e64478e3e4ca6e546b38940ebbf0b69
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / VEX / priv / host_arm_isel.c
1
2 /*---------------------------------------------------------------*/
3 /*--- begin                                   host_arm_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
31 #include "libvex_basictypes.h"
32 #include "libvex_ir.h"
33 #include "libvex.h"
34
35 #include "main_util.h"
36 #include "main_globals.h"
37 #include "host_generic_regs.h"
38 #include "host_arm_defs.h"
39
40
41 /*---------------------------------------------------------*/
42 /*--- ARMvfp control word stuff                         ---*/
43 /*---------------------------------------------------------*/
44
45 /* Vex-generated code expects to run with the FPU set as follows: all
46    exceptions masked, round-to-nearest, non-vector mode, with the NZCV
47    flags cleared, and FZ (flush to zero) disabled.  Curiously enough,
48    this corresponds to a FPSCR value of zero.
49
50    fpscr should therefore be zero on entry to Vex-generated code, and
51    should be unchanged at exit.  (Or at least the bottom 28 bits
52    should be zero).
53 */
54
55 #define DEFAULT_FPSCR 0
56
57
58 /*---------------------------------------------------------*/
59 /*--- ISelEnv                                           ---*/
60 /*---------------------------------------------------------*/
61
62 /* This carries around:
63
64    - A mapping from IRTemp to IRType, giving the type of any IRTemp we
65      might encounter.  This is computed before insn selection starts,
66      and does not change.
67
68    - A mapping from IRTemp to HReg.  This tells the insn selector
69      which virtual register(s) are associated with each IRTemp
70      temporary.  This is computed before insn selection starts, and
71      does not change.  We expect this mapping to map precisely the
72      same set of IRTemps as the type mapping does.
73
74         - vregmap   holds the primary register for the IRTemp.
75         - vregmapHI is only used for 64-bit integer-typed
76              IRTemps.  It holds the identity of a second
77              32-bit virtual HReg, which holds the high half
78              of the value.
79
80    - The name of the vreg in which we stash a copy of the link reg, so
81      helper functions don't kill it.
82
83    - The code array, that is, the insns selected so far.
84
85    - A counter, for generating new virtual registers.
86
87    - The host hardware capabilities word.  This is set at the start
88      and does not change.
89
90    Note, this is all host-independent.  */
91
92 typedef
93    struct {
94       IRTypeEnv*   type_env;
95
96       HReg*        vregmap;
97       HReg*        vregmapHI;
98       Int          n_vregmap;
99
100       HReg         savedLR;
101
102       HInstrArray* code;
103
104       Int          vreg_ctr;
105
106       UInt         hwcaps;
107    }
108    ISelEnv;
109
110 static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
111 {
112    vassert(tmp >= 0);
113    vassert(tmp < env->n_vregmap);
114    return env->vregmap[tmp];
115 }
116
117 static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp )
118 {
119    vassert(tmp >= 0);
120    vassert(tmp < env->n_vregmap);
121    vassert(env->vregmapHI[tmp] != INVALID_HREG);
122    *vrLO = env->vregmap[tmp];
123    *vrHI = env->vregmapHI[tmp];
124 }
125
126 static void addInstr ( ISelEnv* env, ARMInstr* instr )
127 {
128    addHInstr(env->code, instr);
129    if (vex_traceflags & VEX_TRACE_VCODE) {
130       ppARMInstr(instr);
131       vex_printf("\n");
132    }
133 }
134
135 static HReg newVRegI ( ISelEnv* env )
136 {
137    HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/);
138    env->vreg_ctr++;
139    return reg;
140 }
141
142 static HReg newVRegD ( ISelEnv* env )
143 {
144    HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/);
145    env->vreg_ctr++;
146    return reg;
147 }
148
149 static HReg newVRegF ( ISelEnv* env )
150 {
151    HReg reg = mkHReg(env->vreg_ctr, HRcFlt32, True/*virtual reg*/);
152    env->vreg_ctr++;
153    return reg;
154 }
155
156
157 /*---------------------------------------------------------*/
158 /*--- ISEL: Forward declarations                        ---*/
159 /*---------------------------------------------------------*/
160
161 /* These are organised as iselXXX and iselXXX_wrk pairs.  The
162    iselXXX_wrk do the real work, but are not to be called directly.
163    For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
164    checks that all returned registers are virtual.  You should not
165    call the _wrk version directly.
166 */
167 static ARMAMode1*  iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e );
168 static ARMAMode1*  iselIntExpr_AMode1     ( ISelEnv* env, IRExpr* e );
169
170 static ARMAMode2*  iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e );
171 static ARMAMode2*  iselIntExpr_AMode2     ( ISelEnv* env, IRExpr* e );
172
173 static ARMAModeV*  iselIntExpr_AModeV_wrk ( ISelEnv* env, IRExpr* e );
174 static ARMAModeV*  iselIntExpr_AModeV     ( ISelEnv* env, IRExpr* e );
175
176 static ARMRI84*    iselIntExpr_RI84_wrk
177         ( /*OUT*/Bool* didInv, Bool mayInv, ISelEnv* env, IRExpr* e );
178 static ARMRI84*    iselIntExpr_RI84
179         ( /*OUT*/Bool* didInv, Bool mayInv, ISelEnv* env, IRExpr* e );
180
181 static ARMRI5*     iselIntExpr_RI5_wrk    ( ISelEnv* env, IRExpr* e );
182 static ARMRI5*     iselIntExpr_RI5        ( ISelEnv* env, IRExpr* e );
183
184 static ARMCondCode iselCondCode_wrk       ( ISelEnv* env, IRExpr* e );
185 static ARMCondCode iselCondCode           ( ISelEnv* env, IRExpr* e );
186
187 static HReg        iselIntExpr_R_wrk      ( ISelEnv* env, IRExpr* e );
188 static HReg        iselIntExpr_R          ( ISelEnv* env, IRExpr* e );
189
190 static void        iselInt64Expr_wrk      ( HReg* rHi, HReg* rLo, 
191                                             ISelEnv* env, IRExpr* e );
192 static void        iselInt64Expr          ( HReg* rHi, HReg* rLo, 
193                                             ISelEnv* env, IRExpr* e );
194
195 static HReg        iselDblExpr_wrk        ( ISelEnv* env, IRExpr* e );
196 static HReg        iselDblExpr            ( ISelEnv* env, IRExpr* e );
197
198 static HReg        iselFltExpr_wrk        ( ISelEnv* env, IRExpr* e );
199 static HReg        iselFltExpr            ( ISelEnv* env, IRExpr* e );
200
201
202 /*---------------------------------------------------------*/
203 /*--- ISEL: Misc helpers                                ---*/
204 /*---------------------------------------------------------*/
205
206 static UInt ROR32 ( UInt x, UInt sh ) {
207    vassert(sh >= 0 && sh < 32);
208    if (sh == 0)
209       return x;
210    else
211       return (x << (32-sh)) | (x >> sh);
212 }
213
214 /* Figure out if 'u' fits in the special shifter-operand 8x4 immediate
215    form, and if so return the components. */
216 static Bool fitsIn8x4 ( /*OUT*/UInt* u8, /*OUT*/UInt* u4, UInt u )
217 {
218    UInt i;
219    for (i = 0; i < 16; i++) {
220       if (0 == (u & 0xFFFFFF00)) {
221          *u8 = u;
222          *u4 = i;
223          return True;
224       }
225       u = ROR32(u, 30);
226    }
227    vassert(i == 16);
228    return False;
229 }
230
231 /* Make a int reg-reg move. */
232 static ARMInstr* mk_iMOVds_RR ( HReg dst, HReg src )
233 {
234    vassert(hregClass(src) == HRcInt32);
235    vassert(hregClass(dst) == HRcInt32);
236    return ARMInstr_Mov(dst, ARMRI84_R(src));
237 }
238
239 /* Set the VFP unit's rounding mode to default (round to nearest). */
240 static void set_VFP_rounding_default ( ISelEnv* env )
241 {
242    /* mov rTmp, #DEFAULT_FPSCR
243       fmxr fpscr, rTmp
244    */
245    HReg rTmp = newVRegI(env);
246    addInstr(env, ARMInstr_Imm32(rTmp, DEFAULT_FPSCR));
247    addInstr(env, ARMInstr_FPSCR(True/*toFPSCR*/, rTmp));
248 }
249
250 /* Mess with the VFP unit's rounding mode: 'mode' is an I32-typed
251    expression denoting a value in the range 0 .. 3, indicating a round
252    mode encoded as per type IRRoundingMode.  Set FPSCR to have the
253    same rounding.
254 */
255 static
256 void set_VFP_rounding_mode ( ISelEnv* env, IRExpr* mode )
257 {
258    /* This isn't simple, because 'mode' carries an IR rounding
259       encoding, and we need to translate that to an ARMvfp one:
260       The IR encoding:
261          00  to nearest (the default)
262          10  to +infinity
263          01  to -infinity
264          11  to zero
265       The ARMvfp encoding:
266          00  to nearest
267          01  to +infinity
268          10  to -infinity
269          11  to zero
270       Easy enough to do; just swap the two bits.
271    */
272    HReg irrm = iselIntExpr_R(env, mode);
273    HReg tL   = newVRegI(env);
274    HReg tR   = newVRegI(env);
275    HReg t3   = newVRegI(env);
276    /* tL = irrm << 1;
277       tR = irrm >> 1;  if we're lucky, these will issue together
278       tL &= 2;
279       tR &= 1;         ditto
280       t3 = tL | tR;
281       t3 <<= 22;
282       fmxr fpscr, t3
283    */
284    addInstr(env, ARMInstr_Shift(ARMsh_SHL, tL, irrm, ARMRI5_I5(1)));
285    addInstr(env, ARMInstr_Shift(ARMsh_SHR, tR, irrm, ARMRI5_I5(1)));
286    addInstr(env, ARMInstr_Alu(ARMalu_AND, tL, tL, ARMRI84_I84(2,0)));
287    addInstr(env, ARMInstr_Alu(ARMalu_AND, tR, tR, ARMRI84_I84(1,0)));
288    addInstr(env, ARMInstr_Alu(ARMalu_OR, t3, tL, ARMRI84_R(tR)));
289    addInstr(env, ARMInstr_Shift(ARMsh_SHL, t3, t3, ARMRI5_I5(22)));
290    addInstr(env, ARMInstr_FPSCR(True/*toFPSCR*/, t3));
291 }
292
293
294 /*---------------------------------------------------------*/
295 /*--- ISEL: Function call helpers                       ---*/
296 /*---------------------------------------------------------*/
297
298 /* Used only in doHelperCall.  See big comment in doHelperCall re
299    handling of register-parameter args.  This function figures out
300    whether evaluation of an expression might require use of a fixed
301    register.  If in doubt return True (safe but suboptimal).
302 */
303 static
304 Bool mightRequireFixedRegs ( IRExpr* e )
305 {
306    switch (e->tag) {
307    case Iex_RdTmp: case Iex_Const: case Iex_Get:
308       return False;
309    default:
310       return True;
311    }
312 }
313
314
315 /* Do a complete function call.  guard is a Ity_Bit expression
316    indicating whether or not the call happens.  If guard==NULL, the
317    call is unconditional.  Returns True iff it managed to handle this
318    combination of arg/return types, else returns False. */
319
320 static
321 Bool doHelperCall ( ISelEnv* env,
322                     Bool passBBP,
323                     IRExpr* guard, IRCallee* cee, IRExpr** args )
324 {
325    ARMCondCode cc;
326    HReg        argregs[ARM_N_ARGREGS];
327    HReg        tmpregs[ARM_N_ARGREGS];
328    Bool        go_fast;
329    Int         n_args, i, nextArgReg;
330    ULong       target;
331
332    vassert(ARM_N_ARGREGS == 4);
333
334    /* Marshal args for a call and do the call.
335
336       If passBBP is True, r8 (the baseblock pointer) is to be passed
337       as the first arg.
338
339       This function only deals with a tiny set of possibilities, which
340       cover all helpers in practice.  The restrictions are that only
341       arguments in registers are supported, hence only ARM_N_REGPARMS
342       x 32 integer bits in total can be passed.  In fact the only
343       supported arg types are I32 and I64.
344
345       Generating code which is both efficient and correct when
346       parameters are to be passed in registers is difficult, for the
347       reasons elaborated in detail in comments attached to
348       doHelperCall() in priv/host-x86/isel.c.  Here, we use a variant
349       of the method described in those comments.
350
351       The problem is split into two cases: the fast scheme and the
352       slow scheme.  In the fast scheme, arguments are computed
353       directly into the target (real) registers.  This is only safe
354       when we can be sure that computation of each argument will not
355       trash any real registers set by computation of any other
356       argument.
357
358       In the slow scheme, all args are first computed into vregs, and
359       once they are all done, they are moved to the relevant real
360       regs.  This always gives correct code, but it also gives a bunch
361       of vreg-to-rreg moves which are usually redundant but are hard
362       for the register allocator to get rid of.
363
364       To decide which scheme to use, all argument expressions are
365       first examined.  If they are all so simple that it is clear they
366       will be evaluated without use of any fixed registers, use the
367       fast scheme, else use the slow scheme.  Note also that only
368       unconditional calls may use the fast scheme, since having to
369       compute a condition expression could itself trash real
370       registers.
371
372       Note this requires being able to examine an expression and
373       determine whether or not evaluation of it might use a fixed
374       register.  That requires knowledge of how the rest of this insn
375       selector works.  Currently just the following 3 are regarded as
376       safe -- hopefully they cover the majority of arguments in
377       practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
378    */
379
380    /* Note that the cee->regparms field is meaningless on ARM hosts
381       (since there is only one calling convention) and so we always
382       ignore it. */
383
384    n_args = 0;
385    for (i = 0; args[i]; i++)
386       n_args++;
387
388    argregs[0] = hregARM_R0();
389    argregs[1] = hregARM_R1();
390    argregs[2] = hregARM_R2();
391    argregs[3] = hregARM_R3();
392
393    tmpregs[0] = tmpregs[1] = tmpregs[2] =
394    tmpregs[3] = INVALID_HREG;
395
396    /* First decide which scheme (slow or fast) is to be used.  First
397       assume the fast scheme, and select slow if any contraindications
398       (wow) appear. */
399
400    go_fast = True;
401
402    if (guard) {
403       if (guard->tag == Iex_Const
404           && guard->Iex.Const.con->tag == Ico_U1
405           && guard->Iex.Const.con->Ico.U1 == True) {
406          /* unconditional */
407       } else {
408          /* Not manifestly unconditional -- be conservative. */
409          go_fast = False;
410       }
411    }
412
413    if (go_fast) {
414       for (i = 0; i < n_args; i++) {
415          if (mightRequireFixedRegs(args[i])) {
416             go_fast = False;
417             break;
418          }
419       }
420    }
421    /* At this point the scheme to use has been established.  Generate
422       code to get the arg values into the argument rregs.  If we run
423       out of arg regs, give up. */
424
425    if (go_fast) {
426
427       /* FAST SCHEME */
428       nextArgReg = 0;
429       if (passBBP) {
430          addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
431                                      hregARM_R8() ));
432          nextArgReg++;
433       }
434
435       for (i = 0; i < n_args; i++) {
436          IRType aTy = typeOfIRExpr(env->type_env, args[i]);
437          if (nextArgReg >= ARM_N_ARGREGS)
438             return False; /* out of argregs */
439          if (aTy == Ity_I32) {
440             addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
441                                         iselIntExpr_R(env, args[i]) ));
442             nextArgReg++;
443          }
444          else if (aTy == Ity_I64) {
445             /* 64-bit args must be passed in an a reg-pair of the form
446                n:n+1, where n is even.  Hence either r0:r1 or r2:r3.
447                On a little-endian host, the less significant word is
448                passed in the lower-numbered register. */
449             if (nextArgReg & 1) {
450                if (nextArgReg >= ARM_N_ARGREGS)
451                   return False; /* out of argregs */
452                addInstr(env, ARMInstr_Imm32( argregs[nextArgReg], 0xAA ));
453                nextArgReg++;
454             }
455             if (nextArgReg >= ARM_N_ARGREGS)
456                return False; /* out of argregs */
457             HReg raHi, raLo;
458             iselInt64Expr(&raHi, &raLo, env, args[i]);
459             addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raLo ));
460             nextArgReg++;
461             addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raHi ));
462             nextArgReg++;
463          }
464          else
465             return False; /* unhandled arg type */
466       }
467
468       /* Fast scheme only applies for unconditional calls.  Hence: */
469       cc = ARMcc_AL;
470
471    } else {
472
473       /* SLOW SCHEME; move via temporaries */
474       nextArgReg = 0;
475
476       if (passBBP) {
477          /* This is pretty stupid; better to move directly to r0
478             after the rest of the args are done. */
479          tmpregs[nextArgReg] = newVRegI(env);
480          addInstr(env, mk_iMOVds_RR( tmpregs[nextArgReg],
481                                      hregARM_R8() ));
482          nextArgReg++;
483       }
484
485       for (i = 0; i < n_args; i++) {
486          IRType aTy = typeOfIRExpr(env->type_env, args[i]);
487          if (nextArgReg >= ARM_N_ARGREGS)
488             return False; /* out of argregs */
489          if (aTy == Ity_I32) {
490             tmpregs[nextArgReg] = iselIntExpr_R(env, args[i]);
491             nextArgReg++;
492          }
493          else if (aTy == Ity_I64) {
494             /* Same comment applies as in the Fast-scheme case. */
495             if (nextArgReg & 1)
496                nextArgReg++;
497             if (nextArgReg + 1 >= ARM_N_ARGREGS)
498                return False; /* out of argregs */
499             HReg raHi, raLo;
500             iselInt64Expr(&raHi, &raLo, env, args[i]);
501             tmpregs[nextArgReg] = raLo;
502             nextArgReg++;
503             tmpregs[nextArgReg] = raHi;
504             nextArgReg++;
505          }
506       }
507
508       /* Now we can compute the condition.  We can't do it earlier
509          because the argument computations could trash the condition
510          codes.  Be a bit clever to handle the common case where the
511          guard is 1:Bit. */
512       cc = ARMcc_AL;
513       if (guard) {
514          if (guard->tag == Iex_Const
515              && guard->Iex.Const.con->tag == Ico_U1
516              && guard->Iex.Const.con->Ico.U1 == True) {
517             /* unconditional -- do nothing */
518          } else {
519             cc = iselCondCode( env, guard );
520          }
521       }
522
523       /* Move the args to their final destinations. */
524       for (i = 0; i < nextArgReg; i++) {
525          if (tmpregs[i] == INVALID_HREG) { // Skip invalid regs
526             addInstr(env, ARMInstr_Imm32( argregs[i], 0xAA ));
527             continue;
528          }
529          /* None of these insns, including any spill code that might
530             be generated, may alter the condition codes. */
531          addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
532       }
533
534    }
535
536    /* Should be assured by checks above */
537    vassert(nextArgReg <= ARM_N_ARGREGS);
538
539    target = (HWord)Ptr_to_ULong(cee->addr);
540
541    /* nextArgReg doles out argument registers.  Since these are
542       assigned in the order r0, r1, r2, r3, its numeric value at this
543       point, which must be between 0 and 4 inclusive, is going to be
544       equal to the number of arg regs in use for the call.  Hence bake
545       that number into the call (we'll need to know it when doing
546       register allocation, to know what regs the call reads.)
547
548       There is a bit of a twist -- harmless but worth recording.
549       Suppose the arg types are (Ity_I32, Ity_I64).  Then we will have
550       the first arg in r0 and the second in r3:r2, but r1 isn't used.
551       We nevertheless have nextArgReg==4 and bake that into the call
552       instruction.  This will mean the register allocator wil believe
553       this insn reads r1 when in fact it doesn't.  But that's
554       harmless; it just artificially extends the live range of r1
555       unnecessarily.  The best fix would be to put into the
556       instruction, a bitmask indicating which of r0/1/2/3 carry live
557       values.  But that's too much hassle. */
558
559    /* Finally, the call itself. */
560    addInstr(env, ARMInstr_Call( cc, target, nextArgReg ));
561
562    return True; /* success */
563 }
564
565
566 /*---------------------------------------------------------*/
567 /*--- ISEL: Integer expressions (32/16/8 bit)           ---*/
568 /*---------------------------------------------------------*/
569
570 /* Select insns for an integer-typed expression, and add them to the
571    code list.  Return a reg holding the result.  This reg will be a
572    virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
573    want to modify it, ask for a new vreg, copy it in there, and modify
574    the copy.  The register allocator will do its best to map both
575    vregs to the same real register, so the copies will often disappear
576    later in the game.
577
578    This should handle expressions of 32, 16 and 8-bit type.  All
579    results are returned in a 32-bit register.  For 16- and 8-bit
580    expressions, the upper 16/24 bits are arbitrary, so you should mask
581    or sign extend partial values if necessary.
582 */
583
584 /* --------------------- AMode1 --------------------- */
585
586 /* Return an AMode1 which computes the value of the specified
587    expression, possibly also adding insns to the code list as a
588    result.  The expression may only be a 32-bit one.
589 */
590
591 static Bool sane_AMode1 ( ARMAMode1* am )
592 {
593    switch (am->tag) {
594       case ARMam1_RI:
595          return
596             toBool( hregClass(am->ARMam1.RI.reg) == HRcInt32
597                     && (hregIsVirtual(am->ARMam1.RI.reg)
598                         || am->ARMam1.RI.reg == hregARM_R8())
599                     && am->ARMam1.RI.simm13 >= -4095
600                     && am->ARMam1.RI.simm13 <= 4095 );
601       case ARMam1_RRS:
602          return
603             toBool( hregClass(am->ARMam1.RRS.base) == HRcInt32
604                     && hregIsVirtual(am->ARMam1.RRS.base)
605                     && hregClass(am->ARMam1.RRS.index) == HRcInt32
606                     && hregIsVirtual(am->ARMam1.RRS.index)
607                     && am->ARMam1.RRS.shift >= 0
608                     && am->ARMam1.RRS.shift <= 3 );
609       default:
610          vpanic("sane_AMode: unknown ARM AMode1 tag");
611    }
612 }
613
614 static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e )
615 {
616    ARMAMode1* am = iselIntExpr_AMode1_wrk(env, e);
617    vassert(sane_AMode1(am));
618    return am;
619 }
620
621 static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e )
622 {
623    IRType ty = typeOfIRExpr(env->type_env,e);
624    vassert(ty == Ity_I32);
625
626    /* FIXME: add RRS matching */
627
628    /* {Add32,Sub32}(expr,simm13) */
629    if (e->tag == Iex_Binop
630        && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
631        && e->Iex.Binop.arg2->tag == Iex_Const
632        && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
633       Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
634       if (simm >= -4095 && simm <= 4095) {
635          HReg reg;
636          if (e->Iex.Binop.op == Iop_Sub32)
637             simm = -simm;
638          reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
639          return ARMAMode1_RI(reg, simm);
640       }
641    }
642
643    /* Doesn't match anything in particular.  Generate it into
644       a register and use that. */
645    {
646       HReg reg = iselIntExpr_R(env, e);
647       return ARMAMode1_RI(reg, 0);
648    }
649
650 }
651
652
653 /* --------------------- AMode2 --------------------- */
654
655 /* Return an AMode2 which computes the value of the specified
656    expression, possibly also adding insns to the code list as a
657    result.  The expression may only be a 32-bit one.
658 */
659
660 static Bool sane_AMode2 ( ARMAMode2* am )
661 {
662    switch (am->tag) {
663       case ARMam2_RI:
664          return
665             toBool( hregClass(am->ARMam2.RI.reg) == HRcInt32
666                     && hregIsVirtual(am->ARMam2.RI.reg)
667                     && am->ARMam2.RI.simm9 >= -255
668                     && am->ARMam2.RI.simm9 <= 255 );
669       case ARMam2_RR:
670          return
671             toBool( hregClass(am->ARMam2.RR.base) == HRcInt32
672                     && hregIsVirtual(am->ARMam2.RR.base)
673                     && hregClass(am->ARMam2.RR.index) == HRcInt32
674                     && hregIsVirtual(am->ARMam2.RR.index) );
675       default:
676          vpanic("sane_AMode: unknown ARM AMode2 tag");
677    }
678 }
679
680 static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e )
681 {
682    ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
683    vassert(sane_AMode2(am));
684    return am;
685 }
686
687 static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
688 {
689    IRType ty = typeOfIRExpr(env->type_env,e);
690    vassert(ty == Ity_I32);
691
692    /* FIXME: add RR matching */
693
694    /* {Add32,Sub32}(expr,simm8) */
695    if (e->tag == Iex_Binop
696        && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
697        && e->Iex.Binop.arg2->tag == Iex_Const
698        && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
699       Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
700       if (simm >= -255 && simm <= 255) {
701          HReg reg;
702          if (e->Iex.Binop.op == Iop_Sub32)
703             simm = -simm;
704          reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
705          return ARMAMode2_RI(reg, simm);
706       }
707    }
708
709    /* Doesn't match anything in particular.  Generate it into
710       a register and use that. */
711    {
712       HReg reg = iselIntExpr_R(env, e);
713       return ARMAMode2_RI(reg, 0);
714    }
715
716 }
717
718
719 /* --------------------- AModeV --------------------- */
720
721 /* Return an AModeV which computes the value of the specified
722    expression, possibly also adding insns to the code list as a
723    result.  The expression may only be a 32-bit one.
724 */
725
726 static Bool sane_AModeV ( ARMAModeV* am )
727 {
728   return toBool( hregClass(am->reg) == HRcInt32
729                  && hregIsVirtual(am->reg)
730                  && am->simm11 >= -1020 && am->simm11 <= 1020
731                  && 0 == (am->simm11 & 3) );
732 }
733
734 static ARMAModeV* iselIntExpr_AModeV ( ISelEnv* env, IRExpr* e )
735 {
736    ARMAModeV* am = iselIntExpr_AModeV_wrk(env, e);
737    vassert(sane_AModeV(am));
738    return am;
739 }
740
741 static ARMAModeV* iselIntExpr_AModeV_wrk ( ISelEnv* env, IRExpr* e )
742 {
743    IRType ty = typeOfIRExpr(env->type_env,e);
744    vassert(ty == Ity_I32);
745
746    /* {Add32,Sub32}(expr, simm8 << 2) */
747    if (e->tag == Iex_Binop
748        && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
749        && e->Iex.Binop.arg2->tag == Iex_Const
750        && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
751       Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
752       if (simm >= -1020 && simm <= 1020 && 0 == (simm & 3)) {
753          HReg reg;
754          if (e->Iex.Binop.op == Iop_Sub32)
755             simm = -simm;
756          reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
757          return mkARMAModeV(reg, simm);
758       }
759    }
760
761    /* Doesn't match anything in particular.  Generate it into
762       a register and use that. */
763    {
764       HReg reg = iselIntExpr_R(env, e);
765       return mkARMAModeV(reg, 0);
766    }
767
768 }
769
770
771 /* --------------------- RI84 --------------------- */
772
773 /* Select instructions to generate 'e' into a RI84.  If mayInv is
774    true, then the caller will also accept an I84 form that denotes
775    'not e'.  In this case didInv may not be NULL, and *didInv is set
776    to True.  This complication is so as to allow generation of an RI84
777    which is suitable for use in either an AND or BIC instruction,
778    without knowing (before this call) which one.
779 */
780 static ARMRI84* iselIntExpr_RI84 ( /*OUT*/Bool* didInv, Bool mayInv,
781                                    ISelEnv* env, IRExpr* e )
782 {
783    ARMRI84* ri;
784    if (mayInv)
785       vassert(didInv != NULL);
786    ri = iselIntExpr_RI84_wrk(didInv, mayInv, env, e);
787    /* sanity checks ... */
788    switch (ri->tag) {
789       case ARMri84_I84:
790          return ri;
791       case ARMri84_R:
792          vassert(hregClass(ri->ARMri84.R.reg) == HRcInt32);
793          vassert(hregIsVirtual(ri->ARMri84.R.reg));
794          return ri;
795       default:
796          vpanic("iselIntExpr_RI84: unknown arm RI84 tag");
797    }
798 }
799
800 /* DO NOT CALL THIS DIRECTLY ! */
801 static ARMRI84* iselIntExpr_RI84_wrk ( /*OUT*/Bool* didInv, Bool mayInv,
802                                        ISelEnv* env, IRExpr* e )
803 {
804    IRType ty = typeOfIRExpr(env->type_env,e);
805    vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
806
807    if (didInv) *didInv = False;
808
809    /* special case: immediate */
810    if (e->tag == Iex_Const) {
811       UInt u, u8 = 0x100, u4 = 0x10; /* both invalid */
812       switch (e->Iex.Const.con->tag) {
813          case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
814          case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
815          case Ico_U8:  u = 0xFF   & (e->Iex.Const.con->Ico.U8); break;
816          default: vpanic("iselIntExpr_RI84.Iex_Const(armh)");
817       }
818       if (fitsIn8x4(&u8, &u4, u)) {
819          return ARMRI84_I84( (UShort)u8, (UShort)u4 );
820       }
821       if (mayInv && fitsIn8x4(&u8, &u4, ~u)) {
822          vassert(didInv);
823          *didInv = True;
824          return ARMRI84_I84( (UShort)u8, (UShort)u4 );
825       }
826       /* else fail, fall through to default case */
827    }
828
829    /* default case: calculate into a register and return that */
830    {
831       HReg r = iselIntExpr_R ( env, e );
832       return ARMRI84_R(r);
833    }
834 }
835
836
837 /* --------------------- RI5 --------------------- */
838
839 /* Select instructions to generate 'e' into a RI5. */
840
841 static ARMRI5* iselIntExpr_RI5 ( ISelEnv* env, IRExpr* e )
842 {
843    ARMRI5* ri = iselIntExpr_RI5_wrk(env, e);
844    /* sanity checks ... */
845    switch (ri->tag) {
846       case ARMri5_I5:
847          return ri;
848       case ARMri5_R:
849          vassert(hregClass(ri->ARMri5.R.reg) == HRcInt32);
850          vassert(hregIsVirtual(ri->ARMri5.R.reg));
851          return ri;
852       default:
853          vpanic("iselIntExpr_RI5: unknown arm RI5 tag");
854    }
855 }
856
857 /* DO NOT CALL THIS DIRECTLY ! */
858 static ARMRI5* iselIntExpr_RI5_wrk ( ISelEnv* env, IRExpr* e )
859 {
860    IRType ty = typeOfIRExpr(env->type_env,e);
861    vassert(ty == Ity_I32 || ty == Ity_I8);
862
863    /* special case: immediate */
864    if (e->tag == Iex_Const) {
865       UInt u; /* both invalid */
866       switch (e->Iex.Const.con->tag) {
867          case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
868          case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
869          case Ico_U8:  u = 0xFF   & (e->Iex.Const.con->Ico.U8); break;
870          default: vpanic("iselIntExpr_RI5.Iex_Const(armh)");
871       }
872       if (u >= 1 && u <= 31) {
873          return ARMRI5_I5(u);
874       }
875       /* else fail, fall through to default case */
876    }
877
878    /* default case: calculate into a register and return that */
879    {
880       HReg r = iselIntExpr_R ( env, e );
881       return ARMRI5_R(r);
882    }
883 }
884
885
886 /* ------------------- CondCode ------------------- */
887
888 /* Generate code to evaluated a bit-typed expression, returning the
889    condition code which would correspond when the expression would
890    notionally have returned 1. */
891
892 static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
893 {
894    ARMCondCode cc = iselCondCode_wrk(env,e);
895    vassert(cc != ARMcc_AL && cc != ARMcc_NV);
896    return cc;
897 }
898
899 static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
900 {
901    vassert(e);
902    vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
903
904    /* var */
905    if (e->tag == Iex_RdTmp) {
906       HReg rTmp = lookupIRTemp(env, e->Iex.RdTmp.tmp);
907       /* CmpOrTst doesn't modify rTmp; so this is OK. */
908       ARMRI84* one  = ARMRI84_I84(1,0);
909       addInstr(env, ARMInstr_CmpOrTst(False/*test*/, rTmp, one));
910       return ARMcc_NE;
911    }
912
913    /* Not1(e) */
914    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
915       /* Generate code for the arg, and negate the test condition */
916       return 1 ^ iselCondCode(env, e->Iex.Unop.arg);
917    }
918
919    /* --- patterns rooted at: 32to1 --- */
920
921    if (e->tag == Iex_Unop
922        && e->Iex.Unop.op == Iop_32to1) {
923       HReg     rTmp = iselIntExpr_R(env, e->Iex.Unop.arg);
924       ARMRI84* one  = ARMRI84_I84(1,0);
925       addInstr(env, ARMInstr_CmpOrTst(False/*test*/, rTmp, one));
926       return ARMcc_NE;
927    }
928
929    /* --- patterns rooted at: CmpNEZ8 --- */
930
931    if (e->tag == Iex_Unop
932        && e->Iex.Unop.op == Iop_CmpNEZ8) {
933       HReg     r1   = iselIntExpr_R(env, e->Iex.Unop.arg);
934       ARMRI84* xFF  = ARMRI84_I84(0xFF,0);
935       addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r1, xFF));
936       return ARMcc_NE;
937    }
938
939    /* --- patterns rooted at: CmpNEZ32 --- */
940
941    if (e->tag == Iex_Unop
942        && e->Iex.Unop.op == Iop_CmpNEZ32) {
943       HReg     r1   = iselIntExpr_R(env, e->Iex.Unop.arg);
944       ARMRI84* zero = ARMRI84_I84(0,0);
945       addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, r1, zero));
946       return ARMcc_NE;
947    }
948
949    /* --- patterns rooted at: CmpNEZ64 --- */
950
951    if (e->tag == Iex_Unop
952        && e->Iex.Unop.op == Iop_CmpNEZ64) {
953       HReg     tHi, tLo;
954       HReg     tmp  = newVRegI(env);
955       ARMRI84* zero = ARMRI84_I84(0,0);
956       iselInt64Expr(&tHi, &tLo, env, e->Iex.Unop.arg);
957       addInstr(env, ARMInstr_Alu(ARMalu_OR, tmp, tHi, ARMRI84_R(tLo)));
958       addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, tmp, zero));
959       return ARMcc_NE;
960    }
961
962    /* --- Cmp*32*(x,y) --- */
963    if (e->tag == Iex_Binop
964        && (e->Iex.Binop.op == Iop_CmpEQ32
965            || e->Iex.Binop.op == Iop_CmpNE32
966            || e->Iex.Binop.op == Iop_CmpLT32S
967            || e->Iex.Binop.op == Iop_CmpLT32U
968            || e->Iex.Binop.op == Iop_CmpLE32S
969            || e->Iex.Binop.op == Iop_CmpLE32U)) {
970       HReg     argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
971       ARMRI84* argR = iselIntExpr_RI84(NULL,False, 
972                                        env, e->Iex.Binop.arg2);
973       addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, argL, argR));
974       switch (e->Iex.Binop.op) {
975          case Iop_CmpEQ32:  return ARMcc_EQ;
976          case Iop_CmpNE32:  return ARMcc_NE;
977          case Iop_CmpLT32S: return ARMcc_LT;
978          case Iop_CmpLT32U: return ARMcc_LO;
979          case Iop_CmpLE32S: return ARMcc_LE;
980          case Iop_CmpLE32U: return ARMcc_LS;
981          default: vpanic("iselCondCode(arm): CmpXX32");
982       }
983    }
984
985    ppIRExpr(e);
986    vpanic("iselCondCode");
987 }
988
989
990 /* --------------------- Reg --------------------- */
991
992 static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
993 {
994    HReg r = iselIntExpr_R_wrk(env, e);
995    /* sanity checks ... */
996 #  if 0
997    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
998 #  endif
999    vassert(hregClass(r) == HRcInt32);
1000    vassert(hregIsVirtual(r));
1001    return r;
1002 }
1003
1004 /* DO NOT CALL THIS DIRECTLY ! */
1005 static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
1006 {
1007    IRType ty = typeOfIRExpr(env->type_env,e);
1008    vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
1009
1010    switch (e->tag) {
1011
1012    /* --------- TEMP --------- */
1013    case Iex_RdTmp: {
1014       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1015    }
1016
1017    /* --------- LOAD --------- */
1018    case Iex_Load: {
1019       HReg dst  = newVRegI(env);
1020
1021       if (e->Iex.Load.end != Iend_LE)
1022          goto irreducible;
1023
1024       if (ty == Ity_I32) {
1025          ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
1026          addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, dst, amode));
1027          return dst;
1028       }
1029       if (ty == Ity_I16) {
1030          ARMAMode2* amode = iselIntExpr_AMode2 ( env, e->Iex.Load.addr );
1031          addInstr(env, ARMInstr_LdSt16(True/*isLoad*/, False/*!signedLoad*/,
1032                                        dst, amode));
1033          return dst;
1034       }
1035       if (ty == Ity_I8) {
1036          ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
1037          addInstr(env, ARMInstr_LdSt8U(True/*isLoad*/, dst, amode));
1038          return dst;
1039       }
1040
1041 //zz      if (ty == Ity_I16) {
1042 //zz         addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1043 //zz         return dst;
1044 //zz      }
1045 //zz      if (ty == Ity_I8) {
1046 //zz         addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1047 //zz         return dst;
1048 //zz      }
1049       break;
1050    }
1051
1052 //zz   /* --------- TERNARY OP --------- */
1053 //zz   case Iex_Triop: {
1054 //zz      /* C3210 flags following FPU partial remainder (fprem), both
1055 //zz         IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
1056 //zz      if (e->Iex.Triop.op == Iop_PRemC3210F64
1057 //zz          || e->Iex.Triop.op == Iop_PRem1C3210F64) {
1058 //zz         HReg junk = newVRegF(env);
1059 //zz         HReg dst  = newVRegI(env);
1060 //zz         HReg srcL = iselDblExpr(env, e->Iex.Triop.arg2);
1061 //zz         HReg srcR = iselDblExpr(env, e->Iex.Triop.arg3);
1062 //zz         /* XXXROUNDINGFIXME */
1063 //zz         /* set roundingmode here */
1064 //zz         addInstr(env, X86Instr_FpBinary(
1065 //zz                           e->Iex.Binop.op==Iop_PRemC3210F64 
1066 //zz                              ? Xfp_PREM : Xfp_PREM1,
1067 //zz                           srcL,srcR,junk
1068 //zz                 ));
1069 //zz         /* The previous pseudo-insn will have left the FPU's C3210
1070 //zz            flags set correctly.  So bag them. */
1071 //zz         addInstr(env, X86Instr_FpStSW_AX());
1072 //zz         addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
1073 //zz         addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
1074 //zz         return dst;
1075 //zz      }
1076 //zz
1077 //zz      break;
1078 //zz   }
1079
1080    /* --------- BINARY OP --------- */
1081    case Iex_Binop: {
1082
1083       ARMAluOp   aop = 0; /* invalid */
1084       ARMShiftOp sop = 0; /* invalid */
1085
1086       /* ADD/SUB/AND/OR/XOR */
1087       switch (e->Iex.Binop.op) {
1088          case Iop_And32: {
1089             Bool     didInv = False;
1090             HReg     dst    = newVRegI(env);
1091             HReg     argL   = iselIntExpr_R(env, e->Iex.Binop.arg1);
1092             ARMRI84* argR   = iselIntExpr_RI84(&didInv, True/*mayInv*/,
1093                                                env, e->Iex.Binop.arg2);
1094             addInstr(env, ARMInstr_Alu(didInv ? ARMalu_BIC : ARMalu_AND,
1095                                        dst, argL, argR));
1096             return dst;
1097          }
1098          case Iop_Or32:  aop = ARMalu_OR;  goto std_binop;
1099          case Iop_Xor32: aop = ARMalu_XOR; goto std_binop;
1100          case Iop_Sub32: aop = ARMalu_SUB; goto std_binop;
1101          case Iop_Add32: aop = ARMalu_ADD; goto std_binop;
1102          std_binop: {
1103             HReg     dst  = newVRegI(env);
1104             HReg     argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1105             ARMRI84* argR = iselIntExpr_RI84(NULL, False/*mayInv*/,
1106                                              env, e->Iex.Binop.arg2);
1107             addInstr(env, ARMInstr_Alu(aop, dst, argL, argR));
1108             return dst;
1109          }
1110          default: break;
1111       }
1112
1113       /* SHL/SHR/SAR */
1114       switch (e->Iex.Binop.op) {
1115          case Iop_Shl32: sop = ARMsh_SHL; goto sh_binop;
1116          case Iop_Shr32: sop = ARMsh_SHR; goto sh_binop;
1117          case Iop_Sar32: sop = ARMsh_SAR; goto sh_binop;
1118          sh_binop: {
1119             HReg    dst  = newVRegI(env);
1120             HReg    argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1121             ARMRI5* argR = iselIntExpr_RI5(env, e->Iex.Binop.arg2);
1122             addInstr(env, ARMInstr_Shift(sop, dst, argL, argR));
1123             vassert(ty == Ity_I32); /* else the IR is ill-typed */
1124             return dst;
1125          }
1126          default: break;
1127       }
1128
1129       /* MUL */
1130       if (e->Iex.Binop.op == Iop_Mul32) {
1131          HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1132          HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
1133          HReg dst  = newVRegI(env);
1134          addInstr(env, mk_iMOVds_RR(hregARM_R2(), argL));
1135          addInstr(env, mk_iMOVds_RR(hregARM_R3(), argR));
1136          addInstr(env, ARMInstr_Mul(ARMmul_PLAIN));
1137          addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
1138          return dst;
1139       }
1140
1141       /* Handle misc other ops. */
1142
1143       if (e->Iex.Binop.op == Iop_Max32U) {
1144          HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1145          HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
1146          HReg dst  = newVRegI(env);
1147          addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, argL, ARMRI84_R(argR)));
1148          addInstr(env, mk_iMOVds_RR(dst, argL));
1149          addInstr(env, ARMInstr_CMov(ARMcc_LO, dst, ARMRI84_R(argR)));
1150          return dst;
1151       }
1152
1153       if (e->Iex.Binop.op == Iop_CmpF64) {
1154          HReg dL = iselDblExpr(env, e->Iex.Binop.arg1);
1155          HReg dR = iselDblExpr(env, e->Iex.Binop.arg2);
1156          HReg dst = newVRegI(env);
1157          /* Do the compare (FCMPD) and set NZCV in FPSCR.  Then also do
1158             FMSTAT, so we can examine the results directly. */
1159          addInstr(env, ARMInstr_VCmpD(dL, dR));
1160          /* Create in dst, the IRCmpF64Result encoded result. */
1161          addInstr(env, ARMInstr_Imm32(dst, 0));
1162          addInstr(env, ARMInstr_CMov(ARMcc_EQ, dst, ARMRI84_I84(0x40,0))); //EQ
1163          addInstr(env, ARMInstr_CMov(ARMcc_MI, dst, ARMRI84_I84(0x01,0))); //LT
1164          addInstr(env, ARMInstr_CMov(ARMcc_GT, dst, ARMRI84_I84(0x00,0))); //GT
1165          addInstr(env, ARMInstr_CMov(ARMcc_VS, dst, ARMRI84_I84(0x45,0))); //UN
1166          return dst;
1167       }
1168
1169       if (e->Iex.Binop.op == Iop_F64toI32S
1170           || e->Iex.Binop.op == Iop_F64toI32U) {
1171          /* Wretched uglyness all round, due to having to deal
1172             with rounding modes.  Oh well. */
1173          /* FIXME: if arg1 is a constant indicating round-to-zero,
1174             then we could skip all this arsing around with FPSCR and
1175             simply emit FTO{S,U}IZD. */
1176          Bool syned = e->Iex.Binop.op == Iop_F64toI32S;
1177          HReg valD  = iselDblExpr(env, e->Iex.Binop.arg2);
1178          set_VFP_rounding_mode(env, e->Iex.Binop.arg1);
1179          /* FTO{S,U}ID valF, valD */
1180          HReg valF = newVRegF(env);
1181          addInstr(env, ARMInstr_VCvtID(False/*!iToD*/, syned,
1182                                        valF, valD));
1183          set_VFP_rounding_default(env);
1184          /* VMOV dst, valF */
1185          HReg dst = newVRegI(env);
1186          addInstr(env, ARMInstr_VXferS(False/*!toS*/, valF, dst));
1187          return dst;
1188       }
1189
1190       break;
1191    }
1192
1193    /* --------- UNARY OP --------- */
1194    case Iex_Unop: {
1195
1196 //zz      /* 1Uto8(32to1(expr32)) */
1197 //zz      if (e->Iex.Unop.op == Iop_1Uto8) { 
1198 //zz         DECLARE_PATTERN(p_32to1_then_1Uto8);
1199 //zz         DEFINE_PATTERN(p_32to1_then_1Uto8,
1200 //zz                        unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
1201 //zz         if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
1202 //zz            IRExpr* expr32 = mi.bindee[0];
1203 //zz            HReg dst = newVRegI(env);
1204 //zz            HReg src = iselIntExpr_R(env, expr32);
1205 //zz            addInstr(env, mk_iMOVsd_RR(src,dst) );
1206 //zz            addInstr(env, X86Instr_Alu32R(Xalu_AND,
1207 //zz                                          X86RMI_Imm(1), dst));
1208 //zz            return dst;
1209 //zz         }
1210 //zz      }
1211 //zz
1212 //zz      /* 8Uto32(LDle(expr32)) */
1213 //zz      if (e->Iex.Unop.op == Iop_8Uto32) {
1214 //zz         DECLARE_PATTERN(p_LDle8_then_8Uto32);
1215 //zz         DEFINE_PATTERN(p_LDle8_then_8Uto32,
1216 //zz                        unop(Iop_8Uto32,
1217 //zz                             IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
1218 //zz         if (matchIRExpr(&mi,p_LDle8_then_8Uto32,e)) {
1219 //zz            HReg dst = newVRegI(env);
1220 //zz            X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1221 //zz            addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1222 //zz            return dst;
1223 //zz         }
1224 //zz      }
1225 //zz
1226 //zz      /* 8Sto32(LDle(expr32)) */
1227 //zz      if (e->Iex.Unop.op == Iop_8Sto32) {
1228 //zz         DECLARE_PATTERN(p_LDle8_then_8Sto32);
1229 //zz         DEFINE_PATTERN(p_LDle8_then_8Sto32,
1230 //zz                        unop(Iop_8Sto32,
1231 //zz                             IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
1232 //zz         if (matchIRExpr(&mi,p_LDle8_then_8Sto32,e)) {
1233 //zz            HReg dst = newVRegI(env);
1234 //zz            X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1235 //zz            addInstr(env, X86Instr_LoadEX(1,True,amode,dst));
1236 //zz            return dst;
1237 //zz         }
1238 //zz      }
1239 //zz
1240 //zz      /* 16Uto32(LDle(expr32)) */
1241 //zz      if (e->Iex.Unop.op == Iop_16Uto32) {
1242 //zz         DECLARE_PATTERN(p_LDle16_then_16Uto32);
1243 //zz         DEFINE_PATTERN(p_LDle16_then_16Uto32,
1244 //zz                        unop(Iop_16Uto32,
1245 //zz                             IRExpr_Load(Iend_LE,Ity_I16,bind(0))) );
1246 //zz         if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
1247 //zz            HReg dst = newVRegI(env);
1248 //zz            X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
1249 //zz            addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1250 //zz            return dst;
1251 //zz         }
1252 //zz      }
1253 //zz
1254 //zz      /* 8Uto32(GET:I8) */
1255 //zz      if (e->Iex.Unop.op == Iop_8Uto32) {
1256 //zz         if (e->Iex.Unop.arg->tag == Iex_Get) {
1257 //zz            HReg      dst;
1258 //zz            X86AMode* amode;
1259 //zz            vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I8);
1260 //zz            dst = newVRegI(env);
1261 //zz            amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1262 //zz                                hregX86_EBP());
1263 //zz            addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
1264 //zz            return dst;
1265 //zz         }
1266 //zz      }
1267 //zz
1268 //zz      /* 16to32(GET:I16) */
1269 //zz      if (e->Iex.Unop.op == Iop_16Uto32) {
1270 //zz         if (e->Iex.Unop.arg->tag == Iex_Get) {
1271 //zz            HReg      dst;
1272 //zz            X86AMode* amode;
1273 //zz            vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I16);
1274 //zz            dst = newVRegI(env);
1275 //zz            amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
1276 //zz                                hregX86_EBP());
1277 //zz            addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
1278 //zz            return dst;
1279 //zz         }
1280 //zz      }
1281
1282       switch (e->Iex.Unop.op) {
1283          case Iop_8Uto32: {
1284             HReg dst = newVRegI(env);
1285             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1286             addInstr(env, ARMInstr_Alu(ARMalu_AND,
1287                                        dst, src, ARMRI84_I84(0xFF,0)));
1288             return dst;
1289          }
1290 //zz         case Iop_8Uto16:
1291 //zz         case Iop_8Uto32:
1292 //zz         case Iop_16Uto32: {
1293 //zz            HReg dst = newVRegI(env);
1294 //zz            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1295 //zz            UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF;
1296 //zz            addInstr(env, mk_iMOVsd_RR(src,dst) );
1297 //zz            addInstr(env, X86Instr_Alu32R(Xalu_AND,
1298 //zz                                          X86RMI_Imm(mask), dst));
1299 //zz            return dst;
1300 //zz         }
1301 //zz         case Iop_8Sto16:
1302 //zz         case Iop_8Sto32:
1303          case Iop_16Uto32: {
1304             HReg dst = newVRegI(env);
1305             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1306             ARMRI5* amt = ARMRI5_I5(16);
1307             addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, src, amt));
1308             addInstr(env, ARMInstr_Shift(ARMsh_SHR, dst, dst, amt));
1309             return dst;
1310          }
1311          case Iop_8Sto32:
1312          case Iop_16Sto32: {
1313             HReg dst = newVRegI(env);
1314             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1315             ARMRI5* amt = ARMRI5_I5(e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24);
1316             addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, src, amt));
1317             addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
1318             return dst;
1319          }
1320 //zz         case Iop_Not8:
1321 //zz         case Iop_Not16:
1322          case Iop_Not32: {
1323             HReg dst = newVRegI(env);
1324             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1325             addInstr(env, ARMInstr_Unary(ARMun_NOT, dst, src));
1326             return dst;
1327          }
1328          case Iop_64HIto32: {
1329             HReg rHi, rLo;
1330             iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1331             return rHi; /* and abandon rLo .. poor wee thing :-) */
1332          }
1333          case Iop_64to32: {
1334             HReg rHi, rLo;
1335             iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
1336             return rLo; /* similar stupid comment to the above ... */
1337          }
1338 //zz         case Iop_16HIto8:
1339 //zz         case Iop_32HIto16: {
1340 //zz            HReg dst  = newVRegI(env);
1341 //zz            HReg src  = iselIntExpr_R(env, e->Iex.Unop.arg);
1342 //zz            Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
1343 //zz            addInstr(env, mk_iMOVsd_RR(src,dst) );
1344 //zz            addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, dst));
1345 //zz            return dst;
1346 //zz         }
1347          case Iop_1Uto32:
1348          case Iop_1Uto8: {
1349             HReg        dst  = newVRegI(env);
1350             ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1351             addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
1352             addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
1353             return dst;
1354          }
1355
1356          case Iop_1Sto32: {
1357             HReg        dst  = newVRegI(env);
1358             ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1359             ARMRI5*     amt  = ARMRI5_I5(31);
1360             /* This is really rough.  We could do much better here;
1361                perhaps mvn{cond} dst, #0 as the second insn?
1362                (same applies to 1Sto64) */
1363             addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
1364             addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
1365             addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, dst, amt));
1366             addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
1367             return dst;
1368          }
1369
1370
1371 //zz         case Iop_1Sto8:
1372 //zz         case Iop_1Sto16:
1373 //zz         case Iop_1Sto32: {
1374 //zz            /* could do better than this, but for now ... */
1375 //zz            HReg dst         = newVRegI(env);
1376 //zz            X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1377 //zz            addInstr(env, X86Instr_Set32(cond,dst));
1378 //zz            addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, dst));
1379 //zz            addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst));
1380 //zz            return dst;
1381 //zz         }
1382 //zz         case Iop_Ctz32: {
1383 //zz            /* Count trailing zeroes, implemented by x86 'bsfl' */
1384 //zz            HReg dst = newVRegI(env);
1385 //zz            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1386 //zz            addInstr(env, X86Instr_Bsfr32(True,src,dst));
1387 //zz            return dst;
1388 //zz         }
1389          case Iop_Clz32: {
1390             /* Count leading zeroes; easy on ARM. */
1391             HReg dst = newVRegI(env);
1392             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1393             addInstr(env, ARMInstr_Unary(ARMun_CLZ, dst, src));
1394             return dst;
1395          }
1396
1397          case Iop_CmpwNEZ32: {
1398             HReg dst = newVRegI(env);
1399             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1400             addInstr(env, ARMInstr_Unary(ARMun_NEG, dst, src));
1401             addInstr(env, ARMInstr_Alu(ARMalu_OR, dst, dst, ARMRI84_R(src)));
1402             addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, ARMRI5_I5(31)));
1403             return dst;
1404          }
1405
1406          case Iop_Left32: {
1407             HReg dst = newVRegI(env);
1408             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
1409             addInstr(env, ARMInstr_Unary(ARMun_NEG, dst, src));
1410             addInstr(env, ARMInstr_Alu(ARMalu_OR, dst, dst, ARMRI84_R(src)));
1411             return dst;
1412          }
1413
1414 //zz         case Iop_V128to32: {
1415 //zz            HReg      dst  = newVRegI(env);
1416 //zz            HReg      vec  = iselVecExpr(env, e->Iex.Unop.arg);
1417 //zz            X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
1418 //zz            sub_from_esp(env, 16);
1419 //zz            addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
1420 //zz            addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst ));
1421 //zz            add_to_esp(env, 16);
1422 //zz            return dst;
1423 //zz         }
1424 //zz
1425          case Iop_ReinterpF32asI32: {
1426             HReg dst = newVRegI(env);
1427             HReg src = iselFltExpr(env, e->Iex.Unop.arg);
1428             addInstr(env, ARMInstr_VXferS(False/*!toS*/, src, dst));
1429             return dst;
1430          }
1431
1432 //zz
1433 //zz         case Iop_16to8:
1434          case Iop_32to8:
1435          case Iop_32to16:
1436             /* These are no-ops. */
1437             return iselIntExpr_R(env, e->Iex.Unop.arg);
1438
1439          default: 
1440             break;
1441       }
1442       break;
1443    }
1444
1445    /* --------- GET --------- */
1446    case Iex_Get: {
1447       if (ty == Ity_I32 
1448           && 0 == (e->Iex.Get.offset & 3)
1449           && e->Iex.Get.offset < 4096-4) {
1450          HReg dst = newVRegI(env);
1451          addInstr(env, ARMInstr_LdSt32(
1452                           True/*isLoad*/,
1453                           dst,
1454                           ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset)));
1455          return dst;
1456       }
1457 //zz      if (ty == Ity_I8 || ty == Ity_I16) {
1458 //zz         HReg dst = newVRegI(env);
1459 //zz         addInstr(env, X86Instr_LoadEX(
1460 //zz                          toUChar(ty==Ity_I8 ? 1 : 2),
1461 //zz                          False,
1462 //zz                          X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
1463 //zz                          dst));
1464 //zz         return dst;
1465 //zz      }
1466       break;
1467    }
1468
1469 //zz   case Iex_GetI: {
1470 //zz      X86AMode* am 
1471 //zz         = genGuestArrayOffset(
1472 //zz              env, e->Iex.GetI.descr, 
1473 //zz                   e->Iex.GetI.ix, e->Iex.GetI.bias );
1474 //zz      HReg dst = newVRegI(env);
1475 //zz      if (ty == Ity_I8) {
1476 //zz         addInstr(env, X86Instr_LoadEX( 1, False, am, dst ));
1477 //zz         return dst;
1478 //zz      }
1479 //zz      if (ty == Ity_I32) {
1480 //zz         addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), dst));
1481 //zz         return dst;
1482 //zz      }
1483 //zz      break;
1484 //zz   }
1485
1486    /* --------- CCALL --------- */
1487    case Iex_CCall: {
1488       HReg    dst = newVRegI(env);
1489       vassert(ty == e->Iex.CCall.retty);
1490
1491       /* be very restrictive for now.  Only 32/64-bit ints allowed
1492          for args, and 32 bits for return type. */
1493       if (e->Iex.CCall.retty != Ity_I32)
1494          goto irreducible;
1495
1496       /* Marshal args, do the call, clear stack. */
1497       Bool ok = doHelperCall( env, False,
1498                               NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
1499       if (ok) {
1500          addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
1501          return dst;
1502       }
1503       /* else fall through; will hit the irreducible: label */
1504    }
1505
1506    /* --------- LITERAL --------- */
1507    /* 32 literals */
1508    case Iex_Const: {
1509       UInt u   = 0;
1510       HReg dst = newVRegI(env);
1511       switch (e->Iex.Const.con->tag) {
1512          case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
1513          case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
1514          case Ico_U8:  u = 0xFF   & (e->Iex.Const.con->Ico.U8); break;
1515          default: vpanic("iselIntExpr_R.Iex_Const(arm)");
1516       }
1517       addInstr(env, ARMInstr_Imm32(dst, u));
1518       return dst;
1519    }
1520
1521    /* --------- MULTIPLEX --------- */
1522    case Iex_Mux0X: {
1523       IRExpr* cond = e->Iex.Mux0X.cond;
1524
1525       /* Mux0X( 32to8(1Uto32(ccexpr)), expr0, exprX ) */
1526       if (ty == Ity_I32
1527           && cond->tag == Iex_Unop
1528           && cond->Iex.Unop.op == Iop_32to8
1529           && cond->Iex.Unop.arg->tag == Iex_Unop
1530           && cond->Iex.Unop.arg->Iex.Unop.op == Iop_1Uto32) {
1531          ARMCondCode cc;
1532          HReg     rX  = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
1533          ARMRI84* r0  = iselIntExpr_RI84(NULL, False, env, e->Iex.Mux0X.expr0);
1534          HReg     dst = newVRegI(env);
1535          addInstr(env, mk_iMOVds_RR(dst, rX));
1536          cc = iselCondCode(env, cond->Iex.Unop.arg->Iex.Unop.arg);
1537          addInstr(env, ARMInstr_CMov(cc ^ 1, dst, r0));
1538          return dst;
1539       }
1540
1541       /* Mux0X(cond, expr0, exprX) (general case) */
1542       if (ty == Ity_I32) {
1543          HReg     r8;
1544          HReg     rX  = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
1545          ARMRI84* r0  = iselIntExpr_RI84(NULL, False, env, e->Iex.Mux0X.expr0);
1546          HReg     dst = newVRegI(env);
1547          addInstr(env, mk_iMOVds_RR(dst, rX));
1548          r8 = iselIntExpr_R(env, cond);
1549          addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
1550                                          ARMRI84_I84(0xFF,0)));
1551          addInstr(env, ARMInstr_CMov(ARMcc_EQ, dst, r0));
1552          return dst;
1553       }
1554       break;
1555    }
1556
1557    default: 
1558    break;
1559    } /* switch (e->tag) */
1560
1561    /* We get here if no pattern matched. */
1562   irreducible:
1563    ppIRExpr(e);
1564    vpanic("iselIntExpr_R: cannot reduce tree");
1565 }
1566
1567
1568 /* -------------------- 64-bit -------------------- */
1569
1570 /* Compute a 64-bit value into a register pair, which is returned as
1571    the first two parameters.  As with iselIntExpr_R, these may be
1572    either real or virtual regs; in any case they must not be changed
1573    by subsequent code emitted by the caller.  */
1574
1575 static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1576 {
1577    iselInt64Expr_wrk(rHi, rLo, env, e);
1578 #  if 0
1579    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1580 #  endif
1581    vassert(hregClass(*rHi) == HRcInt32);
1582    vassert(hregIsVirtual(*rHi));
1583    vassert(hregClass(*rLo) == HRcInt32);
1584    vassert(hregIsVirtual(*rLo));
1585 }
1586
1587 /* DO NOT CALL THIS DIRECTLY ! */
1588 static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
1589 {
1590    vassert(e);
1591    vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
1592
1593    /* 64-bit literal */
1594    if (e->tag == Iex_Const) {
1595       ULong   w64 = e->Iex.Const.con->Ico.U64;
1596       UInt    wHi = toUInt(w64 >> 32);
1597       UInt    wLo = toUInt(w64);
1598       HReg    tHi = newVRegI(env);
1599       HReg    tLo = newVRegI(env);
1600       vassert(e->Iex.Const.con->tag == Ico_U64);
1601       addInstr(env, ARMInstr_Imm32(tHi, wHi));
1602       addInstr(env, ARMInstr_Imm32(tLo, wLo));
1603       *rHi = tHi;
1604       *rLo = tLo;
1605       return;
1606    }
1607
1608    /* read 64-bit IRTemp */
1609    if (e->tag == Iex_RdTmp) {
1610       lookupIRTemp64( rHi, rLo, env, e->Iex.RdTmp.tmp);
1611       return;
1612    }
1613
1614    /* 64-bit load */
1615    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
1616       HReg      tLo, tHi, rA;
1617       vassert(e->Iex.Load.ty == Ity_I64);
1618       rA  = iselIntExpr_R(env, e->Iex.Load.addr);
1619       tHi = newVRegI(env);
1620       tLo = newVRegI(env);
1621       addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, ARMAMode1_RI(rA, 4)));
1622       addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, ARMAMode1_RI(rA, 0)));
1623       *rHi = tHi;
1624       *rLo = tLo;
1625       return;
1626    }
1627
1628    /* 64-bit GET */
1629    if (e->tag == Iex_Get) {
1630       ARMAMode1* am0 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 0);
1631       ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 4);
1632       HReg tHi = newVRegI(env);
1633       HReg tLo = newVRegI(env);
1634       addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, am4));
1635       addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, am0));
1636       *rHi = tHi;
1637       *rLo = tLo;
1638       return;
1639    }
1640
1641    /* --------- BINARY ops --------- */
1642    if (e->tag == Iex_Binop) {
1643       switch (e->Iex.Binop.op) {
1644
1645          /* 32 x 32 -> 64 multiply */
1646          case Iop_MullS32:
1647          case Iop_MullU32: {
1648             HReg     argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
1649             HReg     argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
1650             HReg     tHi  = newVRegI(env);
1651             HReg     tLo  = newVRegI(env);
1652             ARMMulOp mop  = e->Iex.Binop.op == Iop_MullS32
1653                                ? ARMmul_SX : ARMmul_ZX;
1654             addInstr(env, mk_iMOVds_RR(hregARM_R2(), argL));
1655             addInstr(env, mk_iMOVds_RR(hregARM_R3(), argR));
1656             addInstr(env, ARMInstr_Mul(mop));
1657             addInstr(env, mk_iMOVds_RR(tHi, hregARM_R1()));
1658             addInstr(env, mk_iMOVds_RR(tLo, hregARM_R0()));
1659             *rHi = tHi;
1660             *rLo = tLo;
1661             return;
1662          }
1663
1664          case Iop_Or64: {
1665             HReg xLo, xHi, yLo, yHi;
1666             HReg tHi = newVRegI(env);
1667             HReg tLo = newVRegI(env);
1668             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1669             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1670             addInstr(env, ARMInstr_Alu(ARMalu_OR, tHi, xHi, ARMRI84_R(yHi)));
1671             addInstr(env, ARMInstr_Alu(ARMalu_OR, tLo, xLo, ARMRI84_R(yLo)));
1672             *rHi = tHi;
1673             *rLo = tLo;
1674             return;
1675          }
1676
1677          case Iop_Add64: {
1678             HReg xLo, xHi, yLo, yHi;
1679             HReg tHi = newVRegI(env);
1680             HReg tLo = newVRegI(env);
1681             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1682             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1683             addInstr(env, ARMInstr_Alu(ARMalu_ADDS, tLo, xLo, ARMRI84_R(yLo)));
1684             addInstr(env, ARMInstr_Alu(ARMalu_ADC,  tHi, xHi, ARMRI84_R(yHi)));
1685             *rHi = tHi;
1686             *rLo = tLo;
1687             return;
1688          }
1689
1690          /* 32HLto64(e1,e2) */
1691          case Iop_32HLto64: {
1692             *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
1693             *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
1694             return;
1695          }
1696
1697          default:
1698             break;
1699       }
1700    }
1701
1702    /* --------- UNARY ops --------- */
1703    if (e->tag == Iex_Unop) {
1704       switch (e->Iex.Unop.op) {
1705
1706          /* ReinterpF64asI64 */
1707          case Iop_ReinterpF64asI64: {
1708             HReg dstHi = newVRegI(env);
1709             HReg dstLo = newVRegI(env);
1710             HReg src   = iselDblExpr(env, e->Iex.Unop.arg);
1711             addInstr(env, ARMInstr_VXferD(False/*!toD*/, src, dstHi, dstLo));
1712             *rHi = dstHi;
1713             *rLo = dstLo;
1714             return;
1715          }
1716
1717          /* Left64(e) */
1718          case Iop_Left64: {
1719             HReg yLo, yHi;
1720             HReg tHi  = newVRegI(env);
1721             HReg tLo  = newVRegI(env);
1722             HReg zero = newVRegI(env);
1723             /* yHi:yLo = arg */
1724             iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
1725             /* zero = 0 */
1726             addInstr(env, ARMInstr_Imm32(zero, 0));
1727             /* tLo = 0 - yLo, and set carry */
1728             addInstr(env, ARMInstr_Alu(ARMalu_SUBS, tLo, zero, ARMRI84_R(yLo)));
1729             /* tHi = 0 - yHi - carry */
1730             addInstr(env, ARMInstr_Alu(ARMalu_SBC,  tHi, zero, ARMRI84_R(yHi)));
1731             /* So now we have tHi:tLo = -arg.  To finish off, or 'arg'
1732                back in, so as to give the final result 
1733                tHi:tLo = arg | -arg. */
1734             addInstr(env, ARMInstr_Alu(ARMalu_OR, tHi, tHi, ARMRI84_R(yHi)));
1735             addInstr(env, ARMInstr_Alu(ARMalu_OR, tLo, tLo, ARMRI84_R(yLo)));
1736             *rHi = tHi;
1737             *rLo = tLo;
1738             return;
1739          }
1740
1741          /* CmpwNEZ64(e) */
1742          case Iop_CmpwNEZ64: {
1743             HReg srcLo, srcHi;
1744             HReg tmp1 = newVRegI(env);
1745             HReg tmp2 = newVRegI(env);
1746             /* srcHi:srcLo = arg */
1747             iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
1748             /* tmp1 = srcHi | srcLo */
1749             addInstr(env, ARMInstr_Alu(ARMalu_OR,
1750                                        tmp1, srcHi, ARMRI84_R(srcLo)));
1751             /* tmp2 = (tmp1 | -tmp1) >>s 31 */
1752             addInstr(env, ARMInstr_Unary(ARMun_NEG, tmp2, tmp1));
1753             addInstr(env, ARMInstr_Alu(ARMalu_OR,
1754                                        tmp2, tmp2, ARMRI84_R(tmp1)));
1755             addInstr(env, ARMInstr_Shift(ARMsh_SAR,
1756                                          tmp2, tmp2, ARMRI5_I5(31)));
1757             *rHi = tmp2;
1758             *rLo = tmp2;
1759             return;
1760          }
1761
1762          case Iop_1Sto64: {
1763             HReg        dst  = newVRegI(env);
1764             ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
1765             ARMRI5*     amt  = ARMRI5_I5(31);
1766             /* This is really rough.  We could do much better here;
1767                perhaps mvn{cond} dst, #0 as the second insn?
1768                (same applies to 1Sto32) */
1769             addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
1770             addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
1771             addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, dst, amt));
1772             addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
1773             *rHi = dst;
1774             *rLo = dst;
1775             return;
1776          }
1777
1778          default: 
1779             break;
1780       }
1781    } /* if (e->tag == Iex_Unop) */
1782
1783    /* --------- MULTIPLEX --------- */
1784    if (e->tag == Iex_Mux0X) {
1785       IRType ty8;
1786       HReg   r8, rXhi, rXlo, r0hi, r0lo, dstHi, dstLo;
1787       ty8 = typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond);
1788       vassert(ty8 == Ity_I8);
1789       iselInt64Expr(&rXhi, &rXlo, env, e->Iex.Mux0X.exprX);
1790       iselInt64Expr(&r0hi, &r0lo, env, e->Iex.Mux0X.expr0);
1791       dstHi = newVRegI(env);
1792       dstLo = newVRegI(env);
1793       addInstr(env, mk_iMOVds_RR(dstHi, rXhi));
1794       addInstr(env, mk_iMOVds_RR(dstLo, rXlo));
1795       r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1796       addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
1797                                       ARMRI84_I84(0xFF,0)));
1798       addInstr(env, ARMInstr_CMov(ARMcc_EQ, dstHi, ARMRI84_R(r0hi)));
1799       addInstr(env, ARMInstr_CMov(ARMcc_EQ, dstLo, ARMRI84_R(r0lo)));
1800       *rHi = dstHi;
1801       *rLo = dstLo;
1802       return;
1803    }
1804
1805    ppIRExpr(e);
1806    vpanic("iselInt64Expr");
1807 }
1808
1809
1810 /*---------------------------------------------------------*/
1811 /*--- ISEL: Floating point expressions (64 bit)         ---*/
1812 /*---------------------------------------------------------*/
1813
1814 /* Compute a 64-bit floating point value into a register, the identity
1815    of which is returned.  As with iselIntExpr_R, the reg may be either
1816    real or virtual; in any case it must not be changed by subsequent
1817    code emitted by the caller.  */
1818
1819 static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
1820 {
1821    HReg r = iselDblExpr_wrk( env, e );
1822 #  if 0
1823    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1824 #  endif
1825    vassert(hregClass(r) == HRcFlt64);
1826    vassert(hregIsVirtual(r));
1827    return r;
1828 }
1829
1830 /* DO NOT CALL THIS DIRECTLY */
1831 static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
1832 {
1833    IRType ty = typeOfIRExpr(env->type_env,e);
1834    vassert(e);
1835    vassert(ty == Ity_F64);
1836
1837    if (e->tag == Iex_RdTmp) {
1838       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
1839    }
1840
1841    if (e->tag == Iex_Const) {
1842       /* Just handle the zero case. */
1843       IRConst* con = e->Iex.Const.con;
1844       if (con->tag == Ico_F64i && con->Ico.F64i == 0ULL) {
1845          HReg z32 = newVRegI(env);
1846          HReg dst = newVRegD(env);
1847          addInstr(env, ARMInstr_Imm32(z32, 0));
1848          addInstr(env, ARMInstr_VXferD(True/*toD*/, dst, z32, z32));
1849          return dst;
1850       }
1851    }
1852
1853    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
1854       ARMAModeV* am;
1855       HReg res = newVRegD(env);
1856       vassert(e->Iex.Load.ty == Ity_F64);
1857       am = iselIntExpr_AModeV(env, e->Iex.Load.addr);
1858       addInstr(env, ARMInstr_VLdStD(True/*isLoad*/, res, am));
1859       return res;
1860    }
1861
1862    if (e->tag == Iex_Get) {
1863       // XXX This won't work if offset > 1020 or is not 0 % 4.
1864       // In which case we'll have to generate more longwinded code.
1865       ARMAModeV* am  = mkARMAModeV(hregARM_R8(), e->Iex.Get.offset);
1866       HReg       res = newVRegD(env);
1867       addInstr(env, ARMInstr_VLdStD(True/*isLoad*/, res, am));
1868       return res;
1869    }
1870
1871    if (e->tag == Iex_Unop) {
1872       switch (e->Iex.Unop.op) {
1873          case Iop_ReinterpI64asF64: {
1874             HReg srcHi, srcLo;
1875             HReg dst = newVRegD(env);
1876             iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
1877             addInstr(env, ARMInstr_VXferD(True/*toD*/, dst, srcHi, srcLo));
1878             return dst;
1879          }
1880          case Iop_NegF64: {
1881             HReg src = iselDblExpr(env, e->Iex.Unop.arg);
1882             HReg dst = newVRegD(env);
1883             addInstr(env, ARMInstr_VUnaryD(ARMvfpu_NEG, dst, src));
1884             return dst;
1885          }
1886          case Iop_AbsF64: {
1887             HReg src = iselDblExpr(env, e->Iex.Unop.arg);
1888             HReg dst = newVRegD(env);
1889             addInstr(env, ARMInstr_VUnaryD(ARMvfpu_ABS, dst, src));
1890             return dst;
1891          }
1892          case Iop_F32toF64: {
1893             HReg src = iselFltExpr(env, e->Iex.Unop.arg);
1894             HReg dst = newVRegD(env);
1895             addInstr(env, ARMInstr_VCvtSD(True/*sToD*/, dst, src));
1896             return dst;
1897          }
1898          case Iop_I32UtoF64:
1899          case Iop_I32StoF64: {
1900             HReg src   = iselIntExpr_R(env, e->Iex.Unop.arg);
1901             HReg f32   = newVRegF(env);
1902             HReg dst   = newVRegD(env);
1903             Bool syned = e->Iex.Unop.op == Iop_I32StoF64;
1904             /* VMOV f32, src */
1905             addInstr(env, ARMInstr_VXferS(True/*toS*/, f32, src));
1906             /* FSITOD dst, f32 */
1907             addInstr(env, ARMInstr_VCvtID(True/*iToD*/, syned,
1908                                           dst, f32));
1909             return dst;
1910          }
1911          default:
1912             break;
1913       }
1914    }
1915
1916    if (e->tag == Iex_Binop) {
1917       switch (e->Iex.Binop.op) {
1918          case Iop_SqrtF64: {
1919             /* first arg is rounding mode; we ignore it. */
1920             HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
1921             HReg dst = newVRegD(env);
1922             addInstr(env, ARMInstr_VUnaryD(ARMvfpu_SQRT, dst, src));
1923             return dst;
1924          }
1925          default:
1926             break;
1927       }
1928    }
1929
1930    if (e->tag == Iex_Triop) {
1931       switch (e->Iex.Triop.op) {
1932          case Iop_DivF64:
1933          case Iop_MulF64:
1934          case Iop_AddF64:
1935          case Iop_SubF64: {
1936             ARMVfpOp op = 0; /*INVALID*/
1937             HReg argL = iselDblExpr(env, e->Iex.Triop.arg2);
1938             HReg argR = iselDblExpr(env, e->Iex.Triop.arg3);
1939             HReg dst  = newVRegD(env);
1940             switch (e->Iex.Triop.op) {
1941                case Iop_DivF64: op = ARMvfp_DIV; break;
1942                case Iop_MulF64: op = ARMvfp_MUL; break;
1943                case Iop_AddF64: op = ARMvfp_ADD; break;
1944                case Iop_SubF64: op = ARMvfp_SUB; break;
1945                default: vassert(0);
1946             }
1947             addInstr(env, ARMInstr_VAluD(op, dst, argL, argR));
1948             return dst;
1949          }
1950          default:
1951             break;
1952       }
1953    }
1954
1955    if (e->tag == Iex_Mux0X) {
1956       if (ty == Ity_F64
1957           && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
1958          HReg r8;
1959          HReg rX  = iselDblExpr(env, e->Iex.Mux0X.exprX);
1960          HReg r0  = iselDblExpr(env, e->Iex.Mux0X.expr0);
1961          HReg dst = newVRegD(env);
1962          addInstr(env, ARMInstr_VUnaryD(ARMvfpu_COPY, dst, rX));
1963          r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
1964          addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
1965                                          ARMRI84_I84(0xFF,0)));
1966          addInstr(env, ARMInstr_VCMovD(ARMcc_EQ, dst, r0));
1967          return dst;
1968       }
1969    }
1970
1971    ppIRExpr(e);
1972    vpanic("iselDblExpr_wrk");
1973 }
1974
1975
1976 /*---------------------------------------------------------*/
1977 /*--- ISEL: Floating point expressions (32 bit)         ---*/
1978 /*---------------------------------------------------------*/
1979
1980 /* Compute a 64-bit floating point value into a register, the identity
1981    of which is returned.  As with iselIntExpr_R, the reg may be either
1982    real or virtual; in any case it must not be changed by subsequent
1983    code emitted by the caller.  */
1984
1985 static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
1986 {
1987    HReg r = iselFltExpr_wrk( env, e );
1988 #  if 0
1989    vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
1990 #  endif
1991    vassert(hregClass(r) == HRcFlt32);
1992    vassert(hregIsVirtual(r));
1993    return r;
1994 }
1995
1996 /* DO NOT CALL THIS DIRECTLY */
1997 static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
1998 {
1999    IRType ty = typeOfIRExpr(env->type_env,e);
2000    vassert(e);
2001    vassert(ty == Ity_F32);
2002
2003    if (e->tag == Iex_RdTmp) {
2004       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2005    }
2006
2007    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
2008       ARMAModeV* am;
2009       HReg res = newVRegF(env);
2010       vassert(e->Iex.Load.ty == Ity_F32);
2011       am = iselIntExpr_AModeV(env, e->Iex.Load.addr);
2012       addInstr(env, ARMInstr_VLdStS(True/*isLoad*/, res, am));
2013       return res;
2014    }
2015
2016    if (e->tag == Iex_Get) {
2017       // XXX This won't work if offset > 1020 or is not 0 % 4.
2018       // In which case we'll have to generate more longwinded code.
2019       ARMAModeV* am  = mkARMAModeV(hregARM_R8(), e->Iex.Get.offset);
2020       HReg       res = newVRegF(env);
2021       addInstr(env, ARMInstr_VLdStS(True/*isLoad*/, res, am));
2022       return res;
2023    }
2024
2025    if (e->tag == Iex_Unop) {
2026       switch (e->Iex.Unop.op) {
2027          case Iop_ReinterpI32asF32: {
2028             HReg dst = newVRegF(env);
2029             HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
2030             addInstr(env, ARMInstr_VXferS(True/*toS*/, dst, src));
2031             return dst;
2032          }
2033          case Iop_NegF32: {
2034             HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2035             HReg dst = newVRegF(env);
2036             addInstr(env, ARMInstr_VUnaryS(ARMvfpu_NEG, dst, src));
2037             return dst;
2038          }
2039          case Iop_AbsF32: {
2040             HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2041             HReg dst = newVRegF(env);
2042             addInstr(env, ARMInstr_VUnaryS(ARMvfpu_ABS, dst, src));
2043             return dst;
2044          }
2045          default:
2046             break;
2047       }
2048    }
2049
2050    if (e->tag == Iex_Binop) {
2051       switch (e->Iex.Binop.op) {
2052          case Iop_SqrtF32: {
2053             /* first arg is rounding mode; we ignore it. */
2054             HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
2055             HReg dst = newVRegF(env);
2056             addInstr(env, ARMInstr_VUnaryS(ARMvfpu_SQRT, dst, src));
2057             return dst;
2058          }
2059          case Iop_F64toF32: {
2060             HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
2061             set_VFP_rounding_mode(env, e->Iex.Binop.arg1);
2062             HReg valS = newVRegF(env);
2063             /* FCVTSD valS, valD */
2064             addInstr(env, ARMInstr_VCvtSD(False/*!sToD*/, valS, valD));
2065             set_VFP_rounding_default(env);
2066             return valS;
2067          }
2068          default:
2069             break;
2070       }
2071    }
2072
2073    if (e->tag == Iex_Triop) {
2074       switch (e->Iex.Triop.op) {
2075          case Iop_DivF32:
2076          case Iop_MulF32:
2077          case Iop_AddF32:
2078          case Iop_SubF32: {
2079             ARMVfpOp op = 0; /*INVALID*/
2080             HReg argL = iselFltExpr(env, e->Iex.Triop.arg2);
2081             HReg argR = iselFltExpr(env, e->Iex.Triop.arg3);
2082             HReg dst  = newVRegF(env);
2083             switch (e->Iex.Triop.op) {
2084                case Iop_DivF32: op = ARMvfp_DIV; break;
2085                case Iop_MulF32: op = ARMvfp_MUL; break;
2086                case Iop_AddF32: op = ARMvfp_ADD; break;
2087                case Iop_SubF32: op = ARMvfp_SUB; break;
2088                default: vassert(0);
2089             }
2090             addInstr(env, ARMInstr_VAluS(op, dst, argL, argR));
2091             return dst;
2092          }
2093          default:
2094             break;
2095       }
2096    }
2097
2098    if (e->tag == Iex_Mux0X) {
2099       if (ty == Ity_F32
2100           && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
2101          HReg r8;
2102          HReg rX  = iselFltExpr(env, e->Iex.Mux0X.exprX);
2103          HReg r0  = iselFltExpr(env, e->Iex.Mux0X.expr0);
2104          HReg dst = newVRegF(env);
2105          addInstr(env, ARMInstr_VUnaryS(ARMvfpu_COPY, dst, rX));
2106          r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
2107          addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
2108                                          ARMRI84_I84(0xFF,0)));
2109          addInstr(env, ARMInstr_VCMovS(ARMcc_EQ, dst, r0));
2110          return dst;
2111       }
2112    }
2113
2114    ppIRExpr(e);
2115    vpanic("iselFltExpr_wrk");
2116 }
2117
2118
2119 /*---------------------------------------------------------*/
2120 /*--- ISEL: Statements                                  ---*/
2121 /*---------------------------------------------------------*/
2122
2123 static void iselStmt ( ISelEnv* env, IRStmt* stmt )
2124 {
2125    if (vex_traceflags & VEX_TRACE_VCODE) {
2126       vex_printf("\n-- ");
2127       ppIRStmt(stmt);
2128       vex_printf("\n");
2129    }
2130    switch (stmt->tag) {
2131
2132    /* --------- STORE --------- */
2133    /* little-endian write to memory */
2134    case Ist_Store: {
2135       IRType    tya  = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
2136       IRType    tyd  = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2137       IREndness end  = stmt->Ist.Store.end;
2138
2139       if (tya != Ity_I32 || end != Iend_LE) 
2140          goto stmt_fail;
2141
2142       if (tyd == Ity_I32) {
2143          HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
2144          ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
2145          addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
2146          return;
2147       }
2148       if (tyd == Ity_I16) {
2149          HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
2150          ARMAMode2* am = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
2151          addInstr(env, ARMInstr_LdSt16(False/*!isLoad*/,
2152                                        False/*!isSignedLoad*/, rD, am));
2153          return;
2154       }
2155       if (tyd == Ity_I8) {
2156          HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
2157          ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
2158          addInstr(env, ARMInstr_LdSt8U(False/*!isLoad*/, rD, am));
2159          return;
2160       }
2161       if (tyd == Ity_I64) {
2162          HReg rDhi, rDlo, rA;
2163          iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Store.data);
2164          rA = iselIntExpr_R(env, stmt->Ist.Store.addr);
2165          addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDhi,
2166                                        ARMAMode1_RI(rA,4)));
2167          addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDlo,
2168                                        ARMAMode1_RI(rA,0)));
2169          return;
2170       }
2171       if (tyd == Ity_F64) {
2172          HReg       dD = iselDblExpr(env, stmt->Ist.Store.data);
2173          ARMAModeV* am = iselIntExpr_AModeV(env, stmt->Ist.Store.addr);
2174          addInstr(env, ARMInstr_VLdStD(False/*!isLoad*/, dD, am));
2175          return;
2176       }
2177       if (tyd == Ity_F32) {
2178          HReg       fD = iselFltExpr(env, stmt->Ist.Store.data);
2179          ARMAModeV* am = iselIntExpr_AModeV(env, stmt->Ist.Store.addr);
2180          addInstr(env, ARMInstr_VLdStS(False/*!isLoad*/, fD, am));
2181          return;
2182       }
2183
2184       break;
2185    }
2186
2187    /* --------- PUT --------- */
2188    /* write guest state, fixed offset */
2189    case Ist_Put: {
2190        IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2191
2192        if (tyd == Ity_I32) {
2193            HReg       rD = iselIntExpr_R(env, stmt->Ist.Put.data);
2194            ARMAMode1* am = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset);
2195            addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
2196            return;
2197        }
2198        if (tyd == Ity_I64) {
2199           HReg rDhi, rDlo;
2200           ARMAMode1* am0 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 0);
2201           ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 4);
2202           iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Put.data);
2203           addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDhi, am4));
2204           addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDlo, am0));
2205           return;
2206        }
2207        if (tyd == Ity_F64) {
2208           // XXX This won't work if offset > 1020 or is not 0 % 4.
2209           // In which case we'll have to generate more longwinded code.
2210           ARMAModeV* am = mkARMAModeV(hregARM_R8(), stmt->Ist.Put.offset);
2211           HReg       rD = iselDblExpr(env, stmt->Ist.Put.data);
2212           addInstr(env, ARMInstr_VLdStD(False/*!isLoad*/, rD, am));
2213           return;
2214        }
2215        if (tyd == Ity_F32) {
2216           // XXX This won't work if offset > 1020 or is not 0 % 4.
2217           // In which case we'll have to generate more longwinded code.
2218           ARMAModeV* am = mkARMAModeV(hregARM_R8(), stmt->Ist.Put.offset);
2219           HReg       rD = iselFltExpr(env, stmt->Ist.Put.data);
2220           addInstr(env, ARMInstr_VLdStS(False/*!isLoad*/, rD, am));
2221           return;
2222        }
2223        break;
2224    }
2225
2226 //zz   /* --------- Indexed PUT --------- */
2227 //zz   /* write guest state, run-time offset */
2228 //zz   case Ist_PutI: {
2229 //zz      ARMAMode2* am2
2230 //zz           = genGuestArrayOffset(
2231 //zz               env, stmt->Ist.PutI.descr, 
2232 //zz               stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
2233 //zz       
2234 //zz       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
2235 //zz       
2236 //zz       if (tyd == Ity_I8) {
2237 //zz           HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
2238 //zz           addInstr(env, ARMInstr_StoreB(reg, am2));
2239 //zz           return;
2240 //zz       }
2241 //zz// CAB: Ity_I32, Ity_I16 ?
2242 //zz       break;
2243 //zz   }
2244
2245    /* --------- TMP --------- */
2246    /* assign value to temporary */
2247    case Ist_WrTmp: {
2248       IRTemp tmp = stmt->Ist.WrTmp.tmp;
2249       IRType ty = typeOfIRTemp(env->type_env, tmp);
2250
2251       if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
2252          ARMRI84* ri84 = iselIntExpr_RI84(NULL, False,
2253                                           env, stmt->Ist.WrTmp.data);
2254          HReg     dst  = lookupIRTemp(env, tmp);
2255          addInstr(env, ARMInstr_Mov(dst,ri84));
2256          return;
2257       }
2258       if (ty == Ity_I1) {
2259          HReg        dst  = lookupIRTemp(env, tmp);
2260          ARMCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
2261          addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
2262          addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
2263          return;
2264       }
2265       if (ty == Ity_I64) {
2266          HReg rHi, rLo, dstHi, dstLo;
2267          iselInt64Expr(&rHi,&rLo, env, stmt->Ist.WrTmp.data);
2268          lookupIRTemp64( &dstHi, &dstLo, env, tmp);
2269          addInstr(env, mk_iMOVds_RR(dstHi, rHi) );
2270          addInstr(env, mk_iMOVds_RR(dstLo, rLo) );
2271          return;
2272       }
2273       if (ty == Ity_F64) {
2274          HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
2275          HReg dst = lookupIRTemp(env, tmp);
2276          addInstr(env, ARMInstr_VUnaryD(ARMvfpu_COPY, dst, src));
2277          return;
2278       }
2279       if (ty == Ity_F32) {
2280          HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
2281          HReg dst = lookupIRTemp(env, tmp);
2282          addInstr(env, ARMInstr_VUnaryS(ARMvfpu_COPY, dst, src));
2283          return;
2284       }
2285       break;
2286    }
2287
2288    /* --------- Call to DIRTY helper --------- */
2289    /* call complex ("dirty") helper function */
2290    case Ist_Dirty: {
2291       IRType   retty;
2292       IRDirty* d = stmt->Ist.Dirty.details;
2293       Bool     passBBP = False;
2294
2295       if (d->nFxState == 0)
2296          vassert(!d->needsBBP);
2297
2298       passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2299
2300       /* Marshal args, do the call, clear stack. */
2301       Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args );
2302       if (!ok)
2303          break; /* will go to stmt_fail: */
2304
2305       /* Now figure out what to do with the returned value, if any. */
2306       if (d->tmp == IRTemp_INVALID)
2307          /* No return value.  Nothing to do. */
2308          return;
2309
2310       retty = typeOfIRTemp(env->type_env, d->tmp);
2311
2312       if (retty == Ity_I64) {
2313          HReg dstHi, dstLo;
2314          /* The returned value is in r1:r0.  Park it in the
2315             register-pair associated with tmp. */
2316          lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
2317          addInstr(env, mk_iMOVds_RR(dstHi, hregARM_R1()) );
2318          addInstr(env, mk_iMOVds_RR(dstLo, hregARM_R0()) );
2319          return;
2320       }
2321       if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
2322          /* The returned value is in r0.  Park it in the register
2323             associated with tmp. */
2324          HReg dst = lookupIRTemp(env, d->tmp);
2325          addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()) );
2326          return;
2327       }
2328
2329       break;
2330    }
2331
2332    /* --------- Load Linked and Store Conditional --------- */
2333    case Ist_LLSC: {
2334       if (stmt->Ist.LLSC.storedata == NULL) {
2335          /* LL */
2336          IRTemp res = stmt->Ist.LLSC.result;
2337          IRType ty  = typeOfIRTemp(env->type_env, res);
2338          if (ty == Ity_I32 || ty == Ity_I8) {
2339             Int  szB   = 0;
2340             HReg r_dst = lookupIRTemp(env, res);
2341             HReg raddr = iselIntExpr_R(env, stmt->Ist.LLSC.addr);
2342             switch (ty) {
2343                case Ity_I8:  szB = 1; break;
2344                case Ity_I32: szB = 4; break;
2345                default:      vassert(0);
2346             }
2347             addInstr(env, mk_iMOVds_RR(hregARM_R1(), raddr));
2348             addInstr(env, ARMInstr_LdrEX(szB));
2349             addInstr(env, mk_iMOVds_RR(r_dst, hregARM_R0()));
2350             return;
2351          }
2352          /* else fall thru; is unhandled */
2353       } else {
2354          /* SC */
2355          IRTemp res = stmt->Ist.LLSC.result;
2356          IRType ty  = typeOfIRTemp(env->type_env, res);
2357          IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.storedata);
2358          vassert(ty == Ity_I1);
2359          if (tyd == Ity_I32 || tyd == Ity_I8) {
2360             Int  szB     = 0;
2361             HReg r_res   = lookupIRTemp(env, res);
2362             HReg rD      = iselIntExpr_R(env, stmt->Ist.LLSC.storedata);
2363             HReg rA      = iselIntExpr_R(env, stmt->Ist.LLSC.addr);
2364             ARMRI84* one = ARMRI84_I84(1,0);
2365             switch (tyd) {
2366                case Ity_I8:  szB = 1; break;
2367                case Ity_I32: szB = 4; break;
2368                default:      vassert(0);
2369             }
2370             addInstr(env, mk_iMOVds_RR(hregARM_R1(), rD));
2371             addInstr(env, mk_iMOVds_RR(hregARM_R2(), rA));
2372             addInstr(env, ARMInstr_StrEX(szB));
2373             /* now r0 is 1 if failed, 0 if success.  Change to IR
2374                conventions (0 is fail, 1 is success).  Also transfer
2375                result to r_res. */
2376             addInstr(env, ARMInstr_Alu(ARMalu_XOR, r_res, hregARM_R0(), one));
2377             /* And be conservative -- mask off all but the lowest bit */
2378             addInstr(env, ARMInstr_Alu(ARMalu_AND, r_res, r_res, one));
2379             return;
2380          }
2381          /* else fall thru; is unhandled */
2382       }
2383       break;
2384    }
2385
2386    /* --------- MEM FENCE --------- */
2387    case Ist_MBE:
2388       switch (stmt->Ist.MBE.event) {
2389          case Imbe_Fence:
2390             addInstr(env,ARMInstr_MFence());
2391             return;
2392          default:
2393             break;
2394       }
2395       break;
2396
2397    /* --------- INSTR MARK --------- */
2398    /* Doesn't generate any executable code ... */
2399    case Ist_IMark:
2400        return;
2401
2402    /* --------- NO-OP --------- */
2403    case Ist_NoOp:
2404        return;
2405
2406    /* --------- EXIT --------- */
2407    case Ist_Exit: {
2408       HReg        gnext;
2409       ARMCondCode cc;
2410       if (stmt->Ist.Exit.dst->tag != Ico_U32)
2411          vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");
2412       gnext = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
2413       cc    = iselCondCode(env, stmt->Ist.Exit.guard);
2414       addInstr(env, mk_iMOVds_RR(hregARM_R14(), env->savedLR));
2415       addInstr(env, ARMInstr_Goto(stmt->Ist.Exit.jk, cc, gnext));
2416       return;
2417    }
2418
2419    default: break;
2420    }
2421   stmt_fail:
2422    ppIRStmt(stmt);
2423    vpanic("iselStmt");
2424 }
2425
2426
2427 /*---------------------------------------------------------*/
2428 /*--- ISEL: Basic block terminators (Nexts)             ---*/
2429 /*---------------------------------------------------------*/
2430
2431 static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
2432 {
2433    HReg rDst;
2434    if (vex_traceflags & VEX_TRACE_VCODE) {
2435       vex_printf("\n-- goto {");
2436       ppIRJumpKind(jk);
2437       vex_printf("} ");
2438       ppIRExpr(next);
2439       vex_printf("\n");
2440    }
2441    rDst = iselIntExpr_R(env, next);
2442    addInstr(env, mk_iMOVds_RR(hregARM_R14(), env->savedLR));
2443    addInstr(env, ARMInstr_Goto(jk, ARMcc_AL, rDst));
2444 }
2445
2446
2447 /*---------------------------------------------------------*/
2448 /*--- Insn selector top-level                           ---*/
2449 /*---------------------------------------------------------*/
2450
2451 /* Translate an entire SB to arm code. */
2452
2453 HInstrArray* iselSB_ARM ( IRSB* bb, VexArch      arch_host,
2454                                     VexArchInfo* archinfo_host,
2455                                     VexAbiInfo*  vbi/*UNUSED*/ )
2456 {
2457    Int      i, j;
2458    HReg     hreg, hregHI;
2459    ISelEnv* env;
2460    UInt     hwcaps_host = archinfo_host->hwcaps;
2461
2462    /* sanity ... */
2463    vassert(arch_host == VexArchARM);
2464    vassert(0 == hwcaps_host);
2465
2466    /* Make up an initial environment to use. */
2467    env = LibVEX_Alloc(sizeof(ISelEnv));
2468    env->vreg_ctr = 0;
2469
2470    /* Set up output code array. */
2471    env->code = newHInstrArray();
2472     
2473    /* Copy BB's type env. */
2474    env->type_env = bb->tyenv;
2475
2476    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
2477       change as we go along. */
2478    env->n_vregmap = bb->tyenv->types_used;
2479    env->vregmap   = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2480    env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
2481
2482    /* For each IR temporary, allocate a suitably-kinded virtual
2483       register. */
2484    j = 0;
2485    for (i = 0; i < env->n_vregmap; i++) {
2486       hregHI = hreg = INVALID_HREG;
2487       switch (bb->tyenv->types[i]) {
2488          case Ity_I1:
2489          case Ity_I8:
2490          case Ity_I16:
2491          case Ity_I32:  hreg   = mkHReg(j++, HRcInt32, True); break;
2492          case Ity_I64:  hregHI = mkHReg(j++, HRcInt32, True);
2493                         hreg   = mkHReg(j++, HRcInt32, True); break;
2494          case Ity_F32:  hreg   = mkHReg(j++, HRcFlt32, True); break;
2495          case Ity_F64:  hreg   = mkHReg(j++, HRcFlt64, True); break;
2496          //case Ity_V128: hreg   = mkHReg(j++, HRcVec128, True); break;
2497          default: ppIRType(bb->tyenv->types[i]);
2498                   vpanic("iselBB: IRTemp type");
2499       }
2500       env->vregmap[i]   = hreg;
2501       env->vregmapHI[i] = hregHI;
2502    }
2503    env->vreg_ctr = j;
2504
2505    /* Keep a copy of the link reg, since any call to a helper function
2506       will trash it, and we can't get back to the dispatcher once that
2507       happens. */
2508    env->savedLR = newVRegI(env);
2509    addInstr(env, mk_iMOVds_RR(env->savedLR, hregARM_R14()));
2510
2511    /* Ok, finally we can iterate over the statements. */
2512    for (i = 0; i < bb->stmts_used; i++)
2513       iselStmt(env,bb->stmts[i]);
2514
2515    iselNext(env,bb->next,bb->jumpkind);
2516
2517    /* record the number of vregs we used. */
2518    env->code->n_vregs = env->vreg_ctr;
2519    return env->code;
2520 }
2521
2522
2523 /*---------------------------------------------------------------*/
2524 /*--- end                                     host_arm_isel.c ---*/
2525 /*---------------------------------------------------------------*/