1
2/*---------------------------------------------------------------*/
3/*--- begin                                  host_mips_isel.c ---*/
4/*---------------------------------------------------------------*/
5
6/*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
9
10   Copyright (C) 2010-2013 RT-RK
11      mips-valgrind@rt-rk.com
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_generic_simd64.h"  /* for 64-bit SIMD helpers */
39#include "host_mips_defs.h"
40
41/*---------------------------------------------------------*/
42/*--- Register Usage Conventions                        ---*/
43/*---------------------------------------------------------*/
44
45/* Integer Regs
46   ------------
47   ZERO0       Reserved
48   GPR12:22    Allocateable
49   23          GuestStatePointer
50   SP          StackFramePointer
51   RA          LinkRegister */
52
53static Bool mode64 = False;
54
55/* Host CPU has FPU and 32 dbl. prec. FP registers. */
56static Bool fp_mode64 = False;
57
58/* GPR register class for mips32/64 */
59#define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
60
61/* FPR register class for mips32/64 */
62#define HRcFPR(_mode64) ((_mode64) ? HRcFlt64 : HRcFlt32)
63
64/* guest_COND offset */
65#define COND_OFFSET(_mode64) ((_mode64) ? 612 : 448)
66
67/*---------------------------------------------------------*/
68/*--- ISelEnv                                           ---*/
69/*---------------------------------------------------------*/
70
71/* This carries around:
72
73   - A mapping from IRTemp to IRType, giving the type of any IRTemp we
74     might encounter.  This is computed before insn selection starts,
75     and does not change.
76
77   - A mapping from IRTemp to HReg.  This tells the insn selector
78     which virtual register(s) are associated with each IRTemp
79     temporary.  This is computed before insn selection starts, and
80     does not change.  We expect this mapping to map precisely the
81     same set of IRTemps as the type mapping does.
82
83        - vregmap   holds the primary register for the IRTemp.
84        - vregmapHI is only used for 64-bit integer-typed
85             IRTemps.  It holds the identity of a second
86             32-bit virtual HReg, which holds the high half
87             of the value.
88
89   - The code array, that is, the insns selected so far.
90
91   - A counter, for generating new virtual registers.
92
93   - The host subarchitecture we are selecting insns for.
94     This is set at the start and does not change.
95
96   - A Bool for indicating whether we may generate chain-me
97     instructions for control flow transfers, or whether we must use
98     XAssisted.
99
100   - The maximum guest address of any guest insn in this block.
101     Actually, the address of the highest-addressed byte from any insn
102     in this block.  Is set at the start and does not change.  This is
103     used for detecting jumps which are definitely forward-edges from
104     this block, and therefore can be made (chained) to the fast entry
105     point of the destination, thereby avoiding the destination's
106     event check.
107
108   Note, this is all (well, mostly) host-independent.
109*/
110
111typedef
112   struct {
113      /* Constant -- are set at the start and do not change. */
114      IRTypeEnv*   type_env;
115
116      HReg*        vregmap;
117      HReg*        vregmapHI;
118      Int          n_vregmap;
119
120      UInt         hwcaps;
121      Bool         mode64;
122      Bool         fp_mode64;
123
124      Bool         chainingAllowed;
125      Addr64       max_ga;
126
127      /* These are modified as we go along. */
128      HInstrArray* code;
129      Int          vreg_ctr;
130   }
131   ISelEnv;
132
133static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp)
134{
135   vassert(tmp >= 0);
136   vassert(tmp < env->n_vregmap);
137   return env->vregmap[tmp];
138}
139
140static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
141{
142   vassert(tmp >= 0);
143   vassert(tmp < env->n_vregmap);
144   vassert(! hregIsInvalid(env->vregmapHI[tmp]));
145   *vrLO = env->vregmap[tmp];
146   *vrHI = env->vregmapHI[tmp];
147}
148
149static void
150lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
151{
152   vassert(env->mode64);
153   vassert(tmp >= 0);
154   vassert(tmp < env->n_vregmap);
155   vassert(! hregIsInvalid(env->vregmapHI[tmp]));
156   *vrLO = env->vregmap[tmp];
157   *vrHI = env->vregmapHI[tmp];
158}
159
160static void addInstr(ISelEnv * env, MIPSInstr * instr)
161{
162   addHInstr(env->code, instr);
163   if (vex_traceflags & VEX_TRACE_VCODE) {
164      ppMIPSInstr(instr, mode64);
165      vex_printf("\n");
166   }
167}
168
169static HReg newVRegI(ISelEnv * env)
170{
171   HReg reg = mkHReg(True/*virtual reg*/,
172                     HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
173   env->vreg_ctr++;
174   return reg;
175}
176
177static HReg newVRegD(ISelEnv * env)
178{
179   HReg reg = mkHReg(True/*virtual reg*/,
180                     HRcFlt64, 0/*enc*/, env->vreg_ctr);
181   env->vreg_ctr++;
182   return reg;
183}
184
185static HReg newVRegF(ISelEnv * env)
186{
187   HReg reg = mkHReg(True/*virtual reg*/,
188                     HRcFPR(env->mode64), 0/*enc*/, env->vreg_ctr);
189   env->vreg_ctr++;
190   return reg;
191}
192
193static void add_to_sp(ISelEnv * env, UInt n)
194{
195   HReg sp = StackPointer(mode64);
196   vassert(n < 256 && (n % 8) == 0);
197   if (mode64)
198      addInstr(env, MIPSInstr_Alu(Malu_DADD, sp, sp, MIPSRH_Imm(True,
199                                                                toUShort(n))));
200   else
201      addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True,
202                                                               toUShort(n))));
203}
204
205static void sub_from_sp(ISelEnv * env, UInt n)
206{
207   HReg sp = StackPointer(mode64);
208   vassert(n < 256 && (n % 8) == 0);
209   if (mode64)
210      addInstr(env, MIPSInstr_Alu(Malu_DSUB, sp, sp,
211                                  MIPSRH_Imm(True, toUShort(n))));
212   else
213      addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp,
214                                  MIPSRH_Imm(True, toUShort(n))));
215}
216
217/*---------------------------------------------------------*/
218/*--- ISEL: Forward declarations                        ---*/
219/*---------------------------------------------------------*/
220
221/* These are organised as iselXXX and iselXXX_wrk pairs.  The
222   iselXXX_wrk do the real work, but are not to be called directly.
223   For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
224   checks that all returned registers are virtual.  You should not
225   call the _wrk version directly.
226*/
227/* 32-bit mode: Compute an I8/I16/I32 into a RH
228                (reg-or-halfword-immediate).
229   It's important to specify whether the immediate is to be regarded
230   as signed or not.  If yes, this will never return -32768 as an
231   immediate; this guaranteed that all signed immediates that are
232   return can have their sign inverted if need be.
233*/
234static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
235static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
236
237/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an
238   immediate in the range 1 .. 31 inclusive.  Used for doing shift amounts. */
239static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
240static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
241
242/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an
243   immediate in the range 1 .. 63 inclusive.  Used for doing shift amounts. */
244static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e);
245static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e);
246
247/* compute an I8/I16/I32 into a GPR*/
248static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
249static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
250
251/* compute an I32 into an AMode. */
252static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
253                                         IRType xferTy);
254static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy);
255
256static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
257                              IRExpr * e);
258static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
259
260/* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
261static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo,
262                               ISelEnv * env, IRExpr * e);
263static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
264
265static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
266static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e);
267
268static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e);
269static HReg iselDblExpr(ISelEnv * env, IRExpr * e);
270
271static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e);
272static HReg iselFltExpr(ISelEnv * env, IRExpr * e);
273
274static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode)
275{
276   /*
277      rounding mode | MIPS | IR
278      ------------------------
279      to nearest    | 00  | 00
280      to zero       | 01  | 11
281      to +infinity  | 10  | 10
282      to -infinity  | 11  | 01
283    */
284   /* rm_MIPS32  = XOR(rm_IR , (rm_IR << 1)) & 2 */
285   HReg irrm = iselWordExpr_R(env, mode);
286   HReg tmp = newVRegI(env);
287   HReg fcsr_old = newVRegI(env);
288   MIPSAMode *am_addr;
289
290   addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
291                                MIPSRH_Imm(False, 1)));
292   addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
293   addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, MIPSRH_Imm(False, 3)));
294   /* save old value of FCSR */
295   addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
296   sub_from_sp(env, 8); /*  Move SP down 8 bytes */
297   am_addr = MIPSAMode_IR(0, StackPointer(mode64));
298
299   /* store old FCSR to stack */
300   addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
301
302   /* set new value of FCSR */
303   addInstr(env, MIPSInstr_MtFCSR(irrm));
304}
305
306static void set_MIPS_rounding_default(ISelEnv * env)
307{
308   HReg fcsr = newVRegI(env);
309   /* load as float */
310   MIPSAMode *am_addr;
311   am_addr = MIPSAMode_IR(0, StackPointer(mode64));
312
313   addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64));
314
315   add_to_sp(env, 8);  /* Reset SP */
316
317   /* set new value of FCSR*/
318   addInstr(env, MIPSInstr_MtFCSR(fcsr));
319}
320
321/*---------------------------------------------------------*/
322/*--- ISEL: Misc helpers                                ---*/
323/*---------------------------------------------------------*/
324
325/* Make an int reg-reg move. */
326static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src)
327{
328   vassert(hregClass(r_dst) == hregClass(r_src));
329   vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64);
330   return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src));
331}
332
333/*---------------------------------------------------------*/
334/*--- ISEL: Function call helpers                       ---*/
335/*---------------------------------------------------------*/
336
337/* Used only in doHelperCall.  See big comment in doHelperCall re
338   handling of register-parameter args.  This function figures out
339   whether evaluation of an expression might require use of a fixed
340   register.  If in doubt return True (safe but suboptimal).
341*/
342static Bool mightRequireFixedRegs(IRExpr * e)
343{
344   switch (e->tag) {
345      case Iex_RdTmp:
346      case Iex_Const:
347      case Iex_Get:
348         return False;
349      default:
350         return True;
351   }
352}
353
354/* Load 2*I32 regs to fp reg */
355static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
356{
357   HReg fr_dst = newVRegD(env);
358   MIPSAMode *am_addr0, *am_addr1;
359
360   vassert(hregClass(r_srcHi) == HRcInt32);
361   vassert(hregClass(r_srcLo) == HRcInt32);
362
363   sub_from_sp(env, 16);  /* Move SP down 16 bytes */
364   am_addr0 = MIPSAMode_IR(0, StackPointer(mode64));
365   am_addr1 = MIPSAMode_IR(4, StackPointer(mode64));
366
367   /* store hi,lo as Ity_I32's */
368#if defined (_MIPSEL)
369   addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64));
370   addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64));
371#elif defined (_MIPSEB)
372   addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcHi, mode64));
373   addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcLo, mode64));
374#else
375   /* Stop gcc on other platforms complaining about am_addr1 being set
376      but not used. */
377   (void)am_addr1;
378#endif
379
380   /* load as float */
381   addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0));
382
383   add_to_sp(env, 16);  /* Reset SP */
384   return fr_dst;
385}
386
387/* Do a complete function call.  |guard| is a Ity_Bit expression
388   indicating whether or not the call happens.  If guard==NULL, the
389   call is unconditional.  |retloc| is set to indicate where the
390   return value is after the call.  The caller (of this fn) must
391   generate code to add |stackAdjustAfterCall| to the stack pointer
392   after the call is done. */
393
394static void doHelperCall(/*OUT*/UInt*   stackAdjustAfterCall,
395                         /*OUT*/RetLoc* retloc,
396                         ISelEnv* env,
397                         IRExpr* guard,
398                         IRCallee* cee, IRType retTy, IRExpr** args )
399{
400   MIPSCondCode cc;
401   HReg argregs[MIPS_N_REGPARMS];
402   HReg tmpregs[MIPS_N_REGPARMS];
403   Bool go_fast;
404   Int n_args, i, argreg;
405   UInt argiregs;
406   HReg src = INVALID_HREG;
407
408   /* Set default returns.  We'll update them later if needed. */
409   *stackAdjustAfterCall = 0;
410   *retloc               = mk_RetLoc_INVALID();
411
412   /* These are used for cross-checking that IR-level constraints on
413      the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
414   UInt nVECRETs = 0;
415   UInt nBBPTRs  = 0;
416
417   /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
418      are allowed to be used for passing integer arguments. They correspond
419      to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
420      on MIPS host (since we only implement one calling convention) and so we
421      always ignore it. */
422
423   /* MIPS 64 calling convention: up to four registers ($a0 ... $a7)
424      are allowed to be used for passing integer arguments. They correspond
425      to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
426      on MIPS host (since we only implement one calling convention) and so we
427      always ignore it. */
428
429   /* The return type can be I{64,32,16,8} or V{128,256}.  In the
430      latter two cases, it is expected that |args| will contain the
431      special node IRExpr_VECRET(), in which case this routine
432      generates code to allocate space on the stack for the vector
433      return value.  Since we are not passing any scalars on the
434      stack, it is enough to preallocate the return space before
435      marshalling any arguments, in this case.
436
437      |args| may also contain IRExpr_BBPTR(), in which case the value
438      in the guest state pointer register is passed as the
439      corresponding argument. */
440
441   n_args = 0;
442   for (i = 0; args[i]; i++) {
443      IRExpr* arg = args[i];
444      if (UNLIKELY(arg->tag == Iex_VECRET)) {
445         nVECRETs++;
446      } else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
447         nBBPTRs++;
448      }
449      n_args++;
450   }
451
452   if (n_args > MIPS_N_REGPARMS) {
453      vpanic("doHelperCall(MIPS): cannot currently handle > 4 or 8 args");
454   }
455   if (mode64) {
456      argregs[0] = hregMIPS_GPR4(mode64);
457      argregs[1] = hregMIPS_GPR5(mode64);
458      argregs[2] = hregMIPS_GPR6(mode64);
459      argregs[3] = hregMIPS_GPR7(mode64);
460      argregs[4] = hregMIPS_GPR8(mode64);
461      argregs[5] = hregMIPS_GPR9(mode64);
462      argregs[6] = hregMIPS_GPR10(mode64);
463      argregs[7] = hregMIPS_GPR11(mode64);
464      argiregs = 0;
465      tmpregs[0] = tmpregs[1] = tmpregs[2] =
466      tmpregs[3] = tmpregs[4] = tmpregs[5] =
467      tmpregs[6] = tmpregs[7] = INVALID_HREG;
468   } else {
469      argregs[0] = hregMIPS_GPR4(mode64);
470      argregs[1] = hregMIPS_GPR5(mode64);
471      argregs[2] = hregMIPS_GPR6(mode64);
472      argregs[3] = hregMIPS_GPR7(mode64);
473      argiregs = 0;
474      tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
475   }
476
477   /* First decide which scheme (slow or fast) is to be used. First assume the
478      fast scheme, and select slow if any contraindications (wow) appear. */
479
480   go_fast = True;
481
482   /* We'll need space on the stack for the return value.  Avoid
483      possible complications with nested calls by using the slow
484      scheme. */
485   if (retTy == Ity_V128 || retTy == Ity_V256)
486      go_fast = False;
487
488   if (go_fast && guard) {
489      if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
490          && guard->Iex.Const.con->Ico.U1 == True) {
491         /* unconditional */
492      } else {
493         /* Not manifestly unconditional -- be conservative. */
494         go_fast = False;
495      }
496   }
497
498   if (go_fast) {
499      for (i = 0; i < n_args; i++) {
500         if (mightRequireFixedRegs(args[i])) {
501            go_fast = False;
502            break;
503         }
504      }
505   }
506
507   /* At this point the scheme to use has been established.  Generate
508      code to get the arg values into the argument rregs. */
509   if (go_fast) {
510      /* FAST SCHEME */
511      argreg = 0;
512
513      for (i = 0; i < n_args; i++) {
514         IRExpr* arg = args[i];
515         vassert(argreg < MIPS_N_REGPARMS);
516
517         IRType  aTy = Ity_INVALID;
518         if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
519            aTy = typeOfIRExpr(env->type_env, arg);
520
521         if (aTy == Ity_I32 || mode64) {
522            argiregs |= (1 << (argreg + 4));
523            addInstr(env, mk_iMOVds_RR(argregs[argreg],
524                                       iselWordExpr_R(env, arg)));
525            argreg++;
526         } else if (aTy == Ity_I64) {  /* Ity_I64 */
527            if (argreg & 1) {
528               argreg++;
529               argiregs |= (1 << (argreg + 4));
530            }
531            HReg rHi, rLo;
532            iselInt64Expr(&rHi, &rLo, env, arg);
533            argiregs |= (1 << (argreg + 4));
534            addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
535            argiregs |= (1 << (argreg + 4));
536            addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
537            argreg++;
538         } else if (arg->tag == Iex_BBPTR) {
539            vassert(0);  // ATC
540            addInstr(env, mk_iMOVds_RR(argregs[argreg],
541                                       GuestStatePointer(mode64)));
542            argreg++;
543         } else if (arg->tag == Iex_VECRET) {
544            // If this happens, it denotes ill-formed IR.
545            vassert(0);
546         }
547      }
548      /* Fast scheme only applies for unconditional calls.  Hence: */
549      cc = MIPScc_AL;
550   } else {
551      /* SLOW SCHEME; move via temporaries */
552      argreg = 0;
553
554      for (i = 0; i < n_args; i++) {
555         vassert(argreg < MIPS_N_REGPARMS);
556         IRExpr* arg = args[i];
557
558         IRType  aTy = Ity_INVALID;
559         if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
560            aTy  = typeOfIRExpr(env->type_env, arg);
561
562         if (aTy == Ity_I32 || (mode64 && arg->tag != Iex_BBPTR)) {
563            tmpregs[argreg] = iselWordExpr_R(env, arg);
564            argreg++;
565         } else if (aTy == Ity_I64) {  /* Ity_I64 */
566            if (argreg & 1)
567               argreg++;
568            if (argreg + 1 >= MIPS_N_REGPARMS)
569               vassert(0);  /* out of argregs */
570            HReg raHi, raLo;
571            iselInt64Expr(&raHi, &raLo, env, arg);
572            tmpregs[argreg] = raLo;
573            argreg++;
574            tmpregs[argreg] = raHi;
575            argreg++;
576         } else if (arg->tag == Iex_BBPTR) {
577            tmpregs[argreg] = GuestStatePointer(mode64);
578            argreg++;
579         }
580         else if (arg->tag == Iex_VECRET) {
581            // If this happens, it denotes ill-formed IR
582            vassert(0);
583         }
584      }
585
586      /* Now we can compute the condition.  We can't do it earlier
587         because the argument computations could trash the condition
588         codes.  Be a bit clever to handle the common case where the
589         guard is 1:Bit. */
590      cc = MIPScc_AL;
591      if (guard) {
592         if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
593             && guard->Iex.Const.con->Ico.U1 == True) {
594            /* unconditional -- do nothing */
595         } else {
596            cc = iselCondCode(env, guard);
597            src = iselWordExpr_R(env, guard);
598         }
599      }
600      /* Move the args to their final destinations. */
601      for (i = 0; i < argreg; i++) {
602         if (hregIsInvalid(tmpregs[i]))  /* Skip invalid regs */
603            continue;
604         /* None of these insns, including any spill code that might
605            be generated, may alter the condition codes. */
606         argiregs |= (1 << (i + 4));
607         addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
608      }
609   }
610
611   /* Do final checks, set the return values, and generate the call
612      instruction proper. */
613   vassert(nBBPTRs == 0 || nBBPTRs == 1);
614   vassert(nVECRETs == (retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0);
615   vassert(*stackAdjustAfterCall == 0);
616   vassert(is_RetLoc_INVALID(*retloc));
617   switch (retTy) {
618      case Ity_INVALID:
619         /* Function doesn't return a value. */
620         *retloc = mk_RetLoc_simple(RLPri_None);
621         break;
622      case Ity_I64:
623         *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
624         break;
625      case Ity_I32: case Ity_I16: case Ity_I8:
626         *retloc = mk_RetLoc_simple(RLPri_Int);
627         break;
628      case Ity_V128:
629         vassert(0); // ATC
630         *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
631         *stackAdjustAfterCall = 16;
632         break;
633      case Ity_V256:
634         vassert(0); // ATC
635         *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
636         *stackAdjustAfterCall = 32;
637         break;
638      default:
639         /* IR can denote other possible return types, but we don't
640            handle those here. */
641        vassert(0);
642   }
643
644   Addr64 target = mode64 ? (Addr)cee->addr :
645                            toUInt((Addr)cee->addr);
646
647   /* Finally, generate the call itself.  This needs the *retloc value
648      set in the switch above, which is why it's at the end. */
649   if (cc == MIPScc_AL)
650      addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs,
651                                         *retloc));
652   else
653      addInstr(env, MIPSInstr_Call(cc, target, argiregs, src, *retloc));
654}
655
656/*---------------------------------------------------------*/
657/*--- ISEL: Integer expression auxiliaries              ---*/
658/*---------------------------------------------------------*/
659
660/* --------------------- AMODEs --------------------- */
661
662/* Return an AMode which computes the value of the specified
663   expression, possibly also adding insns to the code list as a
664   result.  The expression may only be a word-size one.
665*/
666
667static Bool uInt_fits_in_16_bits(UInt u)
668{
669   Int i = u & 0xFFFF;
670   i <<= 16;
671   i >>= 16;
672   return toBool(u == (UInt) i);
673}
674
675static Bool uLong_fits_in_16_bits ( ULong u )
676{
677   Long i = u & 0xFFFFULL;
678   i <<= 48;
679   i >>= 48;
680   return toBool(u == (ULong) i);
681}
682
683static Bool uLong_is_4_aligned ( ULong u )
684{
685   return toBool((u & 3ULL) == 0);
686}
687
688static Bool sane_AMode(ISelEnv * env, MIPSAMode * am)
689{
690   switch (am->tag) {
691      case Mam_IR:
692         return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) &&
693                  hregIsVirtual(am->Mam.IR.base) &&
694                  uInt_fits_in_16_bits(am->Mam.IR.index));
695      case Mam_RR:
696         return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) &&
697                  hregIsVirtual(am->Mam.RR.base) &&
698                  hregClass(am->Mam.RR.index) == HRcGPR(mode64) &&
699                  hregIsVirtual(am->Mam.RR.index));
700      default:
701         vpanic("sane_AMode: unknown mips amode tag");
702   }
703}
704
705static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy)
706{
707   MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
708   vassert(sane_AMode(env, am));
709   return am;
710}
711
712/* DO NOT CALL THIS DIRECTLY ! */
713static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
714                                         IRType xferTy)
715{
716   IRType ty = typeOfIRExpr(env->type_env, e);
717   if (env->mode64) {
718      Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
719      vassert(ty == Ity_I64);
720
721      /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
722      if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64
723          && e->Iex.Binop.arg2->tag == Iex_Const
724          && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
725          && (aligned4imm ?
726          uLong_is_4_aligned(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64) : True)
727          && uLong_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) {
728         return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
729                                   iselWordExpr_R(env, e->Iex.Binop.arg1));
730      }
731
732      /* Add64(expr,expr) */
733      if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64) {
734         HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
735         HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
736         return MIPSAMode_RR(r_idx, r_base);
737      }
738   } else {
739      vassert(ty == Ity_I32);
740
741      /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
742      if (e->tag == Iex_Binop
743          && e->Iex.Binop.op == Iop_Add32
744          && e->Iex.Binop.arg2->tag == Iex_Const
745          && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
746          && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) {
747         return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
748                              iselWordExpr_R(env, e->Iex.Binop.arg1));
749      }
750
751      /* Add32(expr,expr) */
752      if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) {
753         HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
754         HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
755
756         return MIPSAMode_RR(r_idx, r_base);
757      }
758   }
759
760   /* Doesn't match anything in particular.  Generate it into
761      a register and use that. */
762   return MIPSAMode_IR(0, iselWordExpr_R(env, e));
763}
764
765/*---------------------------------------------------------*/
766/*--- ISEL: Integer expressions (64/32/16/8 bit)        ---*/
767/*---------------------------------------------------------*/
768
769/* Select insns for an integer-typed expression, and add them to the
770   code list.  Return a reg holding the result.  This reg will be a
771   virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
772   want to modify it, ask for a new vreg, copy it in there, and modify
773   the copy.  The register allocator will do its best to map both
774   vregs to the same real register, so the copies will often disappear
775   later in the game.
776
777   This should handle expressions of 64, 32, 16 and 8-bit type.
778   All results are returned in a (mode64 ? 64bit : 32bit) register.
779   For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
780   are arbitrary, so you should mask or sign extend partial values
781   if necessary.
782*/
783static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e)
784{
785   HReg r = iselWordExpr_R_wrk(env, e);
786   /* sanity checks ... */
787
788   vassert(hregClass(r) == HRcGPR(env->mode64));
789   vassert(hregIsVirtual(r));
790   return r;
791}
792
793/* DO NOT CALL THIS DIRECTLY ! */
794static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
795{
796   UInt argiregs = 0;
797   IRType ty = typeOfIRExpr(env->type_env, e);
798   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1
799           || ty == Ity_F32 || (ty == Ity_I64 && mode64)
800           || (ty == Ity_I128 && mode64));
801
802   switch (e->tag) {
803      /* --------- TEMP --------- */
804      case Iex_RdTmp:
805         return lookupIRTemp(env, e->Iex.RdTmp.tmp);
806
807      /* --------- LOAD --------- */
808      case Iex_Load: {
809         HReg r_dst = newVRegI(env);
810         MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
811
812         if (e->Iex.Load.end != Iend_LE
813             && e->Iex.Load.end != Iend_BE)
814            goto irreducible;
815
816         addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)),
817                                      r_dst, am_addr, mode64));
818         return r_dst;
819      }
820
821      /* --------- BINARY OP --------- */
822      case Iex_Binop: {
823         MIPSAluOp aluOp;
824         MIPSShftOp shftOp;
825
826         /* Is it an addition or logical style op? */
827         switch (e->Iex.Binop.op) {
828            case Iop_Add8:
829            case Iop_Add16:
830            case Iop_Add32:
831               aluOp = Malu_ADD;
832               break;
833
834            case Iop_Sub8:
835            case Iop_Sub16:
836            case Iop_Sub32:
837               aluOp = Malu_SUB;
838               break;
839
840            case Iop_Sub64:
841               aluOp = Malu_DSUB;
842               break;
843
844            case Iop_And8:
845            case Iop_And16:
846            case Iop_And32:
847            case Iop_And64:
848               aluOp = Malu_AND;
849               break;
850
851            case Iop_Or8:
852            case Iop_Or16:
853            case Iop_Or32:
854            case Iop_Or64:
855               aluOp = Malu_OR;
856               break;
857
858            case Iop_Xor8:
859            case Iop_Xor16:
860            case Iop_Xor32:
861            case Iop_Xor64:
862               aluOp = Malu_XOR;
863               break;
864
865            case Iop_Add64:
866               aluOp = Malu_DADD;
867               break;
868
869            default:
870               aluOp = Malu_INVALID;
871               break;
872         }
873
874         /* For commutative ops we assume any literal
875            values are on the second operand. */
876         if (aluOp != Malu_INVALID) {
877            HReg r_dst = newVRegI(env);
878            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
879            MIPSRH *ri_srcR = NULL;
880            /* get right arg into an RH, in the appropriate way */
881            switch (aluOp) {
882               case Malu_ADD:
883               case Malu_SUB:
884               case Malu_DADD:
885               case Malu_DSUB:
886                  ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
887                                            e->Iex.Binop.arg2);
888                  break;
889               case Malu_AND:
890               case Malu_OR:
891               case Malu_XOR:
892                  ri_srcR = iselWordExpr_RH(env, False /*unsigned */,
893                                            e->Iex.Binop.arg2);
894                  break;
895               default:
896                  vpanic("iselWordExpr_R_wrk-aluOp-arg2");
897            }
898            addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
899            return r_dst;
900         }
901
902         /* a shift? */
903         switch (e->Iex.Binop.op) {
904            case Iop_Shl32:
905            case Iop_Shl64:
906               shftOp = Mshft_SLL;
907               break;
908            case Iop_Shr32:
909            case Iop_Shr64:
910               shftOp = Mshft_SRL;
911               break;
912            case Iop_Sar32:
913            case Iop_Sar64:
914               shftOp = Mshft_SRA;
915               break;
916            default:
917               shftOp = Mshft_INVALID;
918               break;
919         }
920
921         /* we assume any literal values are on the second operand. */
922         if (shftOp != Mshft_INVALID) {
923            HReg r_dst = newVRegI(env);
924            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
925            MIPSRH *ri_srcR;
926            if (mode64)
927               ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
928            else
929               ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2);
930
931            if (ty == Ity_I8) {
932               vassert(0);
933            } else if (ty == Ity_I32) {
934               if (mode64 && (shftOp == Mshft_SRA || shftOp == Mshft_SRL)) {
935                  HReg tmp = newVRegI(env);
936                  HReg r_srcL_se = newVRegI(env);
937                  /* SRA, SRAV, SRL, SRLV: On 64-bit processors, if GPR rt does
938                     not contain a sign-extended 32-bit value (bits 63..31
939                     equal), then the result of the operation is UNPREDICTABLE.
940                     So we need to sign-extend r_srcL:
941                     DSLLV tmp, r_srcL, 32
942                     DSRAV r_srcL_se, tmp, 32
943                  */
944                  addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tmp,
945                                               r_srcL, MIPSRH_Imm(False, 32)));
946                  addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, r_srcL_se,
947                                               tmp, MIPSRH_Imm(False, 32)));
948                  /* And finally do the shift. */
949                  addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
950                                               r_dst, r_srcL_se, ri_srcR));
951               } else
952                  addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
953                                               r_dst, r_srcL, ri_srcR));
954            } else if (ty == Ity_I64) {
955               vassert(mode64);
956               addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */,
957                                            r_dst, r_srcL, ri_srcR));
958            } else
959               goto irreducible;
960            return r_dst;
961         }
962
963         /* Cmp*32*(x,y) ? */
964         if (e->Iex.Binop.op == Iop_CmpEQ32
965             || e->Iex.Binop.op == Iop_CmpEQ16
966             || e->Iex.Binop.op == Iop_CmpNE32
967             || e->Iex.Binop.op == Iop_CmpNE64
968             || e->Iex.Binop.op == Iop_CmpLT32S
969             || e->Iex.Binop.op == Iop_CmpLT32U
970             || e->Iex.Binop.op == Iop_CmpLT64U
971             || e->Iex.Binop.op == Iop_CmpLE32U
972             || e->Iex.Binop.op == Iop_CmpLE32S
973             || e->Iex.Binop.op == Iop_CmpLE64S
974             || e->Iex.Binop.op == Iop_CmpLT64S
975             || e->Iex.Binop.op == Iop_CmpEQ64
976             || e->Iex.Binop.op == Iop_CasCmpEQ32
977             || e->Iex.Binop.op == Iop_CasCmpEQ64) {
978
979            Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
980                         || e->Iex.Binop.op == Iop_CmpLE32S
981                         || e->Iex.Binop.op == Iop_CmpLT64S
982                         || e->Iex.Binop.op == Iop_CmpLE64S);
983            Bool size32;
984            HReg dst = newVRegI(env);
985            HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
986            HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
987
988            MIPSCondCode cc;
989
990            switch (e->Iex.Binop.op) {
991               case Iop_CmpEQ32:
992               case Iop_CasCmpEQ32:
993                  cc = MIPScc_EQ;
994                  size32 = True;
995                  break;
996               case Iop_CmpEQ16:
997                  cc = MIPScc_EQ;
998                  size32 = True;
999                  break;
1000               case Iop_CmpNE32:
1001                  cc = MIPScc_NE;
1002                  size32 = True;
1003                  break;
1004               case Iop_CmpNE64:
1005                  cc = MIPScc_NE;
1006                  size32 = True;
1007                  break;
1008               case Iop_CmpLT32S:
1009                  cc = MIPScc_LT;
1010                  size32 = True;
1011                  break;
1012               case Iop_CmpLT32U:
1013                  cc = MIPScc_LO;
1014                  size32 = True;
1015                  break;
1016               case Iop_CmpLT64U:
1017                  cc = MIPScc_LO;
1018                  size32 = False;
1019                  break;
1020               case Iop_CmpLE32U:
1021                  cc = MIPScc_LE;
1022                  size32 = True;
1023                  break;
1024               case Iop_CmpLE32S:
1025                  cc = MIPScc_LE;
1026                  size32 = True;
1027                  break;
1028               case Iop_CmpLE64S:
1029                  cc = MIPScc_LE;
1030                  size32 = False;
1031                  break;
1032               case Iop_CmpLT64S:
1033                  cc = MIPScc_LT;
1034                  size32 = False;
1035                  break;
1036               case Iop_CmpEQ64:
1037               case Iop_CasCmpEQ64:
1038                  cc = MIPScc_EQ;
1039                  size32 = False;
1040                  break;
1041               default:
1042                  vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
1043            }
1044
1045            addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
1046            return dst;
1047         }
1048
1049         if (e->Iex.Binop.op == Iop_Max32U) {
1050            HReg tmp = newVRegI(env);
1051            HReg r_dst = newVRegI(env);
1052            HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1053            HReg argR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1054            MIPSRH *argRH = iselWordExpr_RH(env, False /*signed */ ,
1055                                           e->Iex.Binop.arg2);
1056            /* max (v0, s0)
1057               ------------
1058               slt v1, v0, s0
1059               movn v0, s0, v1 */
1060
1061            addInstr(env, MIPSInstr_Alu(Malu_SLT, tmp, argL, argRH));
1062            addInstr(env, mk_iMOVds_RR(r_dst, argL));
1063            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, argR, tmp));
1064            return r_dst;
1065         }
1066
1067         if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) {
1068            Bool sz32 = (e->Iex.Binop.op == Iop_Mul32);
1069            HReg r_dst = newVRegI(env);
1070            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1071            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1072            addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ ,
1073                                       False /*widen */ ,
1074                                       sz32 /*32bit or 64bit */,
1075                                       r_dst, r_srcL, r_srcR));
1076            return r_dst;
1077         }
1078
1079         if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) {
1080            HReg r_dst = newVRegI(env);
1081            HReg tHi = newVRegI(env);
1082            HReg tLo = newVRegI(env);
1083            HReg tLo_1 = newVRegI(env);
1084            HReg tHi_1 = newVRegI(env);
1085            HReg mask = newVRegI(env);
1086
1087            Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
1088            Bool size = toBool(e->Iex.Binop.op == Iop_MullS32)
1089                        || toBool(e->Iex.Binop.op == Iop_MullU32);
1090            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1091            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1092            addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ ,
1093                                        True /*widen */ ,
1094                                        size /*32bit or 64bit mul */ ,
1095                                        r_dst, r_srcL, r_srcR));
1096
1097            addInstr(env, MIPSInstr_Mfhi(tHi));
1098            addInstr(env, MIPSInstr_Mflo(tLo));
1099
1100            addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1,
1101                          tHi, MIPSRH_Imm(False, 32)));
1102
1103            addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1104            addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1105                          MIPSRH_Reg(mask)));
1106
1107            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1108                          MIPSRH_Reg(tLo_1)));
1109
1110            return r_dst;
1111         }
1112
1113         if (e->Iex.Binop.op == Iop_CmpF64) {
1114            HReg r_srcL, r_srcR;
1115            if (mode64) {
1116               r_srcL = iselFltExpr(env, e->Iex.Binop.arg1);
1117               r_srcR = iselFltExpr(env, e->Iex.Binop.arg2);
1118            } else {
1119               r_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
1120               r_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
1121            }
1122            HReg tmp = newVRegI(env);
1123            HReg r_ccMIPS = newVRegI(env);
1124            HReg r_ccIR = newVRegI(env);
1125            HReg r_ccIR_b0 = newVRegI(env);
1126            HReg r_ccIR_b2 = newVRegI(env);
1127            HReg r_ccIR_b6 = newVRegI(env);
1128
1129            /* Create in dst, the IRCmpF64Result encoded result. */
1130            /* chech for EQ */
1131            addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmp, r_srcL, r_srcR));
1132            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccMIPS, tmp,
1133                                         MIPSRH_Imm(False, 1)));
1134            /* chech for UN */
1135            addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmp, r_srcL, r_srcR));
1136            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1137                                        MIPSRH_Reg(tmp)));
1138            /* chech for LT */
1139            addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmp, r_srcL, r_srcR));
1140            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp,
1141                                         tmp, MIPSRH_Imm(False, 2)));
1142            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1143                                        MIPSRH_Reg(tmp)));
1144            /* chech for GT */
1145            addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_NGT,
1146                                              tmp, r_srcL, r_srcR));
1147            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, tmp,
1148                                         MIPSRH_Imm(False, 3)));
1149
1150            addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp)));
1151            addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1152                                        MIPSRH_Imm(False, 8)));
1153            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1154                                        MIPSRH_Reg(tmp)));
1155            /* Map compare result from MIPS to IR,
1156               conforming to CmpF64 definition.
1157               FP cmp result | MIPS | IR
1158               --------------------------
1159               UN            | 0x1 | 0x45
1160               EQ            | 0x2 | 0x40
1161               GT            | 0x4 | 0x00
1162               LT            | 0x8 | 0x01
1163             */
1164
1165            /* r_ccIR_b0 = r_ccMIPS[0] | r_ccMIPS[3] */
1166            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS,
1167                          MIPSRH_Imm(False, 0x3)));
1168            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS,
1169                          MIPSRH_Reg(r_ccIR_b0)));
1170            addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0,
1171                          MIPSRH_Imm(False, 0x1)));
1172
1173            /* r_ccIR_b2 = r_ccMIPS[0] */
1174            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS,
1175                          MIPSRH_Imm(False, 0x2)));
1176            addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2,
1177                          MIPSRH_Imm(False, 0x4)));
1178
1179            /* r_ccIR_b6 = r_ccMIPS[0] | r_ccMIPS[1] */
1180            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6,
1181                          r_ccMIPS, MIPSRH_Imm(False, 0x1)));
1182            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS,
1183                          MIPSRH_Reg(r_ccIR_b6)));
1184            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6,
1185                          MIPSRH_Imm(False, 0x6)));
1186            addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6,
1187                          MIPSRH_Imm(False, 0x40)));
1188
1189            /* r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 */
1190            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0,
1191                          MIPSRH_Reg(r_ccIR_b2)));
1192            addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR,
1193                          MIPSRH_Reg(r_ccIR_b6)));
1194            return r_ccIR;
1195         }
1196
1197         if (e->Iex.Binop.op == Iop_DivModU64to32 ||
1198             e->Iex.Binop.op == Iop_DivModS64to32) {
1199            HReg tLo = newVRegI(env);
1200            HReg tHi = newVRegI(env);
1201            HReg mask = newVRegI(env);
1202            HReg tLo_1 = newVRegI(env);
1203            HReg tHi_1 = newVRegI(env);
1204            HReg r_dst = newVRegI(env);
1205            Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32);
1206
1207            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1208            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1209
1210            addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
1211            addInstr(env, MIPSInstr_Mfhi(tHi));
1212            addInstr(env, MIPSInstr_Mflo(tLo));
1213
1214            addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1215                                         MIPSRH_Imm(False, 32)));
1216
1217            addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1218            addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1219                          MIPSRH_Reg(mask)));
1220
1221            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1222                          MIPSRH_Reg(tLo_1)));
1223
1224            return r_dst;
1225         }
1226
1227         if (e->Iex.Binop.op == Iop_8HLto16
1228             || e->Iex.Binop.op == Iop_16HLto32) {
1229            HReg tHi   = iselWordExpr_R(env, e->Iex.Binop.arg1);
1230            HReg tLo   = iselWordExpr_R(env, e->Iex.Binop.arg2);
1231            HReg tLo_1 = newVRegI(env);
1232            HReg tHi_1 = newVRegI(env);
1233            HReg r_dst = newVRegI(env);
1234            UInt shift = 0;
1235            UInt mask  = 0;
1236            switch (e->Iex.Binop.op) {
1237               case Iop_8HLto16:
1238                  shift = 8;
1239                  mask  = 0xff;
1240                  break;
1241               case Iop_16HLto32:
1242                  shift = 16;
1243                  mask  = 0xffff;
1244                  break;
1245               default:
1246                  break;
1247            }
1248
1249            /* sll tHi_1, tHi,   shift
1250               and tLo_1, tLo,   mask
1251               or  r_dst, tHi_1, tLo_1 */
1252            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi,
1253                                         MIPSRH_Imm(False, shift)));
1254            addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1255                          MIPSRH_Imm(False, mask)));
1256            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1257                          MIPSRH_Reg(tLo_1)));
1258            return r_dst;
1259         }
1260
1261         if (e->Iex.Binop.op == Iop_32HLto64) {
1262            vassert(mode64);
1263            HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1264            HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1265            HReg tLo_1 = newVRegI(env);
1266            HReg tHi_1 = newVRegI(env);
1267            HReg r_dst = newVRegI(env);
1268            HReg mask = newVRegI(env);
1269
1270            addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1271                                         MIPSRH_Imm(False, 32)));
1272
1273            addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1274            addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1275                          MIPSRH_Reg(mask)));
1276            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1277                          MIPSRH_Reg(tLo_1)));
1278
1279            return r_dst;
1280         }
1281
1282         if (e->Iex.Binop.op == Iop_F32toI64S) {
1283            vassert(mode64);
1284            HReg valS = newVRegI(env);
1285            HReg tmpF = newVRegF(env);
1286            HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1287
1288            /* CVTLS tmpF, valF */
1289            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1290            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpF, valF));
1291            set_MIPS_rounding_default(env);
1292
1293            /* Doubleword Move from Floating Point
1294               dmfc1 valS, tmpF */
1295            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF));
1296
1297            return valS;
1298         }
1299
1300         if (e->Iex.Binop.op == Iop_F64toI32S) {
1301            HReg valD;
1302            if (mode64)
1303               valD = iselFltExpr(env, e->Iex.Binop.arg2);
1304            else
1305               valD = iselDblExpr(env, e->Iex.Binop.arg2);
1306            HReg valS = newVRegF(env);
1307            HReg r_dst = newVRegI(env);
1308
1309            /* CVTWD valS, valD */
1310            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1311            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1312            set_MIPS_rounding_default(env);
1313
1314            /* Move Word From Floating Point
1315               mfc1 r_dst, valS */
1316            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1317
1318            return r_dst;
1319         }
1320
1321         /* -------- DSP ASE -------- */
1322         /* All used cases involving host-side helper calls. */
1323         void* fn = NULL;
1324         switch (e->Iex.Binop.op) {
1325            case Iop_HAdd8Ux4:
1326               fn = &h_generic_calc_HAdd8Ux4; break;
1327            case Iop_HSub8Ux4:
1328               fn = &h_generic_calc_HSub8Ux4; break;
1329            case Iop_HSub16Sx2:
1330               fn = &h_generic_calc_HSub16Sx2; break;
1331            case Iop_QSub8Ux4:
1332               fn = &h_generic_calc_QSub8Ux4; break;
1333            default:
1334                  break;
1335         }
1336
1337         /* What's the retloc? */
1338         RetLoc rloc = mk_RetLoc_INVALID();
1339         if (ty == Ity_I32) {
1340            rloc = mk_RetLoc_simple(RLPri_Int);
1341         }
1342         else if (ty == Ity_I64) {
1343            rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1344                            mk_RetLoc_simple(RLPri_2Int);
1345         }
1346         else {
1347            goto irreducible;
1348         }
1349
1350         if (fn) {
1351            HReg regL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1352            HReg regR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1353            HReg res  = newVRegI(env);
1354            addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1355            addInstr(env, mk_iMOVds_RR(hregMIPS_GPR5(env->mode64), regR));
1356            argiregs |= (1 << 4);
1357            argiregs |= (1 << 5);
1358            addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
1359                                                (Addr)fn,
1360                                                argiregs, rloc));
1361            addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1362            return res;
1363         }
1364      break;
1365   }
1366
1367   /* --------- UNARY OP --------- */
1368   case Iex_Unop: {
1369      IROp op_unop = e->Iex.Unop.op;
1370
1371      switch (op_unop) {
1372         case Iop_1Sto8:
1373         case Iop_1Sto16:
1374         case Iop_1Sto32:
1375         case Iop_8Sto16:
1376         case Iop_8Sto32:
1377         case Iop_16Sto32:
1378         case Iop_16Sto64:
1379         case Iop_8Sto64:
1380         case Iop_1Sto64: {
1381            HReg r_dst = newVRegI(env);
1382            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1383            Bool sz32;
1384            UShort amt;
1385            switch (op_unop) {
1386               case Iop_1Sto8:
1387                  amt = 31;
1388                  sz32 = True;
1389                  break;
1390               case Iop_1Sto16:
1391                  amt = 31;
1392                  sz32 = True;
1393                  break;
1394               case Iop_1Sto32:
1395                  amt = 31;
1396                  sz32 = True;
1397                  break;
1398               case Iop_16Sto32:
1399                  amt = 16;
1400                  sz32 = True;
1401                  break;
1402               case Iop_16Sto64:
1403                  amt = 48;
1404                  sz32 = False;
1405                  break;
1406               case Iop_8Sto16:
1407                  amt = 24;
1408                  sz32 = True;
1409                  break;
1410               case Iop_8Sto32:
1411                  amt = 24;
1412                  sz32 = True;
1413                  break;
1414               case Iop_8Sto64:
1415                  amt = 56;
1416                  sz32 = False;
1417                  break;
1418               case Iop_1Sto64:
1419                  amt = 63;
1420                  sz32 = False;
1421                  break;
1422               default:
1423                  vassert(0);
1424            }
1425
1426            addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src,
1427                                         MIPSRH_Imm(False, amt)));
1428            addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst,
1429                                         MIPSRH_Imm(False, amt)));
1430            return r_dst;
1431         }
1432
1433         /* not(x) = nor(x,x) */
1434         case Iop_Not1: {
1435            HReg r_dst = newVRegI(env);
1436            HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1437            MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1438
1439            addInstr(env, MIPSInstr_LI(r_dst, 0x1));
1440            addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
1441            return r_dst;
1442         }
1443
1444         case Iop_Not8:
1445         case Iop_Not16:
1446         case Iop_Not32:
1447         case Iop_Not64: {
1448            HReg r_dst = newVRegI(env);
1449            HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1450            MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1451
1452            addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR));
1453            return r_dst;
1454         }
1455
1456         case Iop_ReinterpF32asI32: {
1457            HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1458            HReg r_dst = newVRegI(env);
1459
1460            /* Move Word From Floating Point
1461               mfc1 r_dst, fr_src */
1462            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, fr_src));
1463
1464            return r_dst;
1465         }
1466
1467         case Iop_ReinterpF64asI64: {
1468            vassert(mode64);
1469            HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1470            HReg r_dst = newVRegI(env);
1471
1472            /* Doubleword Move from Floating Point
1473               mfc1 r_dst, fr_src */
1474            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, r_dst, fr_src));
1475
1476            return r_dst;
1477         }
1478
1479         case Iop_F64toI32S: {
1480            HReg valD;
1481            if (mode64)
1482               valD = iselFltExpr(env, e->Iex.Binop.arg2);
1483            else
1484               valD = iselDblExpr(env, e->Iex.Binop.arg2);
1485            HReg valS = newVRegF(env);
1486            HReg r_dst = newVRegI(env);
1487
1488            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1489            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1490            set_MIPS_rounding_default(env);
1491
1492            /* Move Word From Floating Point
1493               mfc1 r_dst, valS */
1494            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1495
1496            return r_dst;
1497         }
1498
1499         case Iop_16to8:
1500         case Iop_32to1:
1501         case Iop_32to8:
1502         case Iop_32to16:
1503            return iselWordExpr_R(env, e->Iex.Unop.arg);
1504
1505         case Iop_32HIto16: {
1506            HReg r_dst = newVRegI(env);
1507            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1508            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1509                                         r_dst, r_src, MIPSRH_Imm(False, 16)));
1510            return r_dst;
1511         }
1512
1513         case Iop_64to1:
1514         case Iop_64to8: {
1515            vassert(mode64);
1516            HReg r_src, r_dst;
1517            UShort mask = (op_unop == Iop_64to1) ? 0x1 : 0xFF;
1518            r_dst = newVRegI(env);
1519            r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1520            addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1521                          MIPSRH_Imm(False, mask)));
1522            return r_dst;
1523         }
1524
1525         case Iop_16HIto8: {
1526            HReg r_dst = newVRegI(env);
1527            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1528            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1529                                         r_dst, r_src, MIPSRH_Imm(False, 8)));
1530            return r_dst;
1531         }
1532
1533         case Iop_1Uto8:
1534         case Iop_1Uto32:
1535         case Iop_1Uto64:
1536         case Iop_8Uto16:
1537         case Iop_8Uto32:
1538         case Iop_8Uto64:
1539         case Iop_16Uto32:
1540         case Iop_16Uto64: {
1541            HReg r_dst = newVRegI(env);
1542            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1543            UShort mask = 0;
1544            switch (op_unop) {
1545               case Iop_1Uto64:
1546                  vassert(mode64);
1547               case Iop_1Uto8:
1548               case Iop_1Uto32:
1549                  mask = toUShort(0x1);
1550                  break;
1551               case Iop_8Uto64:
1552                  vassert(mode64);
1553               case Iop_8Uto16:
1554               case Iop_8Uto32:
1555                  mask = toUShort(0xFF);
1556                  break;
1557               case Iop_16Uto64:
1558                  vassert(mode64);
1559               case Iop_16Uto32:
1560                  mask = toUShort(0xFFFF);
1561                  break;
1562               default:
1563                  vassert(0);
1564                  break;
1565            }
1566            addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1567                          MIPSRH_Imm(False, mask)));
1568            return r_dst;
1569         }
1570
1571         case Iop_32Uto64: {
1572            HReg r_dst = newVRegI(env);
1573            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1574            vassert(mode64);
1575            addInstr(env, MIPSInstr_Shft(Mshft_SLL, False /*!32bit shift */,
1576                                         r_dst, r_src, MIPSRH_Imm(False, 32)));
1577            addInstr(env, MIPSInstr_Shft(Mshft_SRL, False /*!32bit shift */,
1578                                         r_dst, r_dst, MIPSRH_Imm(False, 32)));
1579            return r_dst;
1580         }
1581
1582         case Iop_64HIto32: {
1583            if (env->mode64) {
1584               HReg r_dst = newVRegI(env);
1585               HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1586               addInstr(env, MIPSInstr_Shft(Mshft_SRA, False /*64bit shift */,
1587                       r_dst, r_src, MIPSRH_Imm(True, 32)));
1588               return r_dst;
1589            } else {
1590               HReg rHi, rLo;
1591               iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1592               return rHi;
1593            }
1594         }
1595
1596         case Iop_64to32: {
1597            if (env->mode64) {
1598               HReg r_dst = newVRegI(env);
1599               r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1600               return r_dst;
1601            } else {
1602               HReg rHi, rLo;
1603               iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1604               return rLo;
1605            }
1606         }
1607
1608         case Iop_64to16: {
1609            vassert(env->mode64);
1610            HReg r_dst = newVRegI(env);
1611            r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1612            return r_dst;
1613         }
1614
1615         case Iop_32Sto64: {
1616            HReg r_dst = newVRegI(env);
1617            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1618            vassert(mode64);
1619            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*!32bit shift */,
1620                                         r_dst, r_src, MIPSRH_Imm(True, 0)));
1621            return r_dst;
1622         }
1623
1624         case Iop_CmpNEZ8:
1625         case Iop_CmpNEZ16: {
1626            HReg r_dst = newVRegI(env);
1627            HReg tmp = newVRegI(env);
1628            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1629            UShort mask = (op_unop == Iop_CmpNEZ8) ? 0xFF : 0xFFFF;
1630
1631            addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src,
1632                                        MIPSRH_Imm(False, mask)));
1633            addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp,
1634                                        hregMIPS_GPR0(mode64), MIPScc_NE));
1635            return r_dst;
1636         }
1637
1638         case Iop_CmpNEZ32: {
1639            HReg r_dst = newVRegI(env);
1640            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1641
1642            addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src,
1643                                        hregMIPS_GPR0(mode64), MIPScc_NE));
1644            return r_dst;
1645         }
1646
1647         case Iop_CmpwNEZ32: {
1648            HReg r_dst = newVRegI(env);
1649            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1650
1651            addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
1652                          MIPSRH_Reg(r_src)));
1653
1654            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1655                                        MIPSRH_Reg(r_src)));
1656            addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst,
1657                                         MIPSRH_Imm(False, 31)));
1658            return r_dst;
1659         }
1660
1661         case Iop_Left8:
1662         case Iop_Left16:
1663         case Iop_Left32:
1664         case Iop_Left64: {
1665            if (op_unop == Iop_Left64 && !mode64)
1666               goto irreducible;
1667            HReg r_dst = newVRegI(env);
1668            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1669            MIPSAluOp op = (op_unop == Iop_Left64) ? Malu_DSUB : Malu_SUB;
1670            addInstr(env, MIPSInstr_Alu(op, r_dst,
1671                                        hregMIPS_GPR0(mode64),
1672                                        MIPSRH_Reg(r_src)));
1673            addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1674                          MIPSRH_Reg(r_src)));
1675            return r_dst;
1676         }
1677
1678         case Iop_Clz64:
1679            vassert(mode64);
1680         case Iop_Clz32: {
1681            HReg r_dst = newVRegI(env);
1682            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1683            MIPSUnaryOp op = (op_unop == Iop_Clz64) ? Mun_DCLZ : Mun_CLZ;
1684            addInstr(env, MIPSInstr_Unary(op, r_dst, r_src));
1685            return r_dst;
1686         }
1687
1688         case Iop_CmpNEZ64: {
1689            HReg hi, lo;
1690            HReg r_dst = newVRegI(env);
1691            HReg r_src;
1692            if (env->mode64) {
1693               r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1694            } else {
1695               r_src = newVRegI(env);
1696               iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg);
1697               addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi)));
1698            }
1699            addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src,
1700                                        hregMIPS_GPR0(mode64), MIPScc_NE));
1701            return r_dst;
1702         }
1703
1704         case Iop_CmpwNEZ64: {
1705            HReg tmp1;
1706            HReg tmp2 = newVRegI(env);
1707            vassert(env->mode64);
1708            tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
1709
1710            addInstr(env, MIPSInstr_Alu(Malu_DSUB, tmp2, hregMIPS_GPR0(mode64),
1711                          MIPSRH_Reg(tmp1)));
1712
1713            addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
1714            addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2,
1715                                         MIPSRH_Imm (False, 63)));
1716            return tmp2;
1717         }
1718
1719         case Iop_128HIto64: {
1720            vassert(mode64);
1721            HReg rHi, rLo;
1722            iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1723            return rHi;  /* and abandon rLo .. poor wee thing :-) */
1724         }
1725
1726         case Iop_128to64: {
1727            vassert(mode64);
1728            HReg rHi, rLo;
1729            iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1730            return rLo;  /* and abandon rLo .. poor wee thing :-) */
1731         }
1732
1733         default:
1734            break;
1735      }
1736
1737      /* -------- DSP ASE -------- */
1738      /* All Unop cases involving host-side helper calls. */
1739      void* fn = NULL;
1740      switch (e->Iex.Unop.op) {
1741         case Iop_CmpNEZ16x2:
1742            fn = &h_generic_calc_CmpNEZ16x2; break;
1743         case Iop_CmpNEZ8x4:
1744            fn = &h_generic_calc_CmpNEZ8x4; break;
1745         default:
1746            break;
1747      }
1748
1749      RetLoc rloc = mk_RetLoc_INVALID();
1750      if (ty == Ity_I32) {
1751         rloc = mk_RetLoc_simple(RLPri_Int);
1752      }
1753      else if (ty == Ity_I64) {
1754         rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1755                         mk_RetLoc_simple(RLPri_2Int);
1756      }
1757      else {
1758         goto irreducible;
1759      }
1760
1761      if (fn) {
1762         HReg regL = iselWordExpr_R(env, e->Iex.Unop.arg);
1763         HReg res  = newVRegI(env);
1764         addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1765         argiregs |= (1 << 4);
1766         addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
1767                                             (Addr)fn,
1768                                             argiregs, rloc));
1769         addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1770         return res;
1771      }
1772
1773      break;
1774   }
1775
1776   /* --------- GET --------- */
1777   case Iex_Get: {
1778      if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
1779          || ((ty == Ity_I64) && mode64)) {
1780         HReg r_dst = newVRegI(env);
1781
1782         MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
1783                                           GuestStatePointer(mode64));
1784         addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr,
1785                                      mode64));
1786         return r_dst;
1787      }
1788      break;
1789   }
1790
1791   /* --------- ITE --------- */
1792   case Iex_ITE: {
1793      if ((ty == Ity_I8 || ty == Ity_I16 ||
1794           ty == Ity_I32 || ((ty == Ity_I64))) &&
1795           typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
1796         HReg r_dst  = iselWordExpr_R(env, e->Iex.ITE.iffalse);
1797         HReg r1     = iselWordExpr_R(env, e->Iex.ITE.iftrue);
1798         HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
1799         /*
1800          * r_dst = r0
1801          * movn r_dst, r1, r_cond
1802          */
1803         addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, r1, r_cond));
1804         return r_dst;
1805      }
1806      break;
1807   }
1808
1809   /* --------- LITERAL --------- */
1810   /* 32/16/8-bit literals */
1811   case Iex_Const: {
1812      Long l;
1813      HReg r_dst = newVRegI(env);
1814      IRConst *con = e->Iex.Const.con;
1815      switch (con->tag) {
1816         case Ico_U64:
1817            if (!mode64)
1818               goto irreducible;
1819            l = (Long) con->Ico.U64;
1820            break;
1821         case Ico_U32:
1822            l = (Long) (Int) con->Ico.U32;
1823            break;
1824         case Ico_U16:
1825            l = (Long) (Int) (Short) con->Ico.U16;
1826            break;
1827         case Ico_U8:
1828            l = (Long) (Int) (Char) con->Ico.U8;
1829            break;
1830         default:
1831            vpanic("iselIntExpr_R.const(mips)");
1832      }
1833      addInstr(env, MIPSInstr_LI(r_dst, (ULong) l));
1834      return r_dst;
1835   }
1836
1837   /* --------- CCALL --------- */
1838   case Iex_CCall: {
1839      HReg r_dst = newVRegI(env);
1840      vassert(ty == e->Iex.CCall.retty);
1841
1842      /* be very restrictive for now.  Only 32/64-bit ints allowed for
1843         args, and 64 and 32 bits for return type.  Don't forget to change
1844         the RetLoc if more return types are allowed in future. */
1845      if (e->Iex.CCall.retty != Ity_I64 && e->Iex.CCall.retty != Ity_I32)
1846         goto irreducible;
1847
1848      /* Marshal args, do the call, clear stack. */
1849      UInt   addToSp = 0;
1850      RetLoc rloc    = mk_RetLoc_INVALID();
1851      doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
1852                   e->Iex.CCall.retty, e->Iex.CCall.args );
1853
1854      vassert(is_sane_RetLoc(rloc));
1855      vassert(rloc.pri == RLPri_Int);
1856      vassert(addToSp == 0);
1857      addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
1858      return r_dst;
1859   }
1860
1861   default:
1862      break;
1863   }  /* end switch(e->tag) */
1864
1865   /* We get here if no pattern matched. */
1866   irreducible:
1867      vex_printf("--------------->\n");
1868      if (e->tag == Iex_RdTmp)
1869         vex_printf("Iex_RdTmp \n");
1870      ppIRExpr(e);
1871
1872      vpanic("iselWordExpr_R(mips): cannot reduce tree");
1873}
1874
1875/* --------------------- RH --------------------- */
1876
1877/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
1878   (reg-or-halfword-immediate).  It's important to specify whether the
1879   immediate is to be regarded as signed or not.  If yes, this will
1880   never return -32768 as an immediate; this guaranteed that all
1881   signed immediates that are return can have their sign inverted if
1882   need be. */
1883
1884static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e)
1885{
1886   MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e);
1887   /* sanity checks ... */
1888   switch (ri->tag) {
1889      case Mrh_Imm:
1890         vassert(ri->Mrh.Imm.syned == syned);
1891         if (syned)
1892            vassert(ri->Mrh.Imm.imm16 != 0x8000);
1893         return ri;
1894      case Mrh_Reg:
1895         vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
1896         vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1897         return ri;
1898      default:
1899         vpanic("iselIntExpr_RH: unknown mips RH tag");
1900   }
1901}
1902
1903/* DO NOT CALL THIS DIRECTLY ! */
1904static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e)
1905{
1906   ULong u;
1907   Long l;
1908   IRType ty = typeOfIRExpr(env->type_env, e);
1909   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1910          ((ty == Ity_I64) && env->mode64));
1911
1912   /* special case: immediate */
1913   if (e->tag == Iex_Const) {
1914      IRConst *con = e->Iex.Const.con;
1915      /* What value are we aiming to generate? */
1916      switch (con->tag) {
1917         /* Note: Not sign-extending - we carry 'syned' around */
1918         case Ico_U64:
1919            vassert(env->mode64);
1920            u = con->Ico.U64;
1921            break;
1922         case Ico_U32:
1923            u = 0xFFFFFFFF & con->Ico.U32;
1924            break;
1925         case Ico_U16:
1926            u = 0x0000FFFF & con->Ico.U16;
1927            break;
1928         case Ico_U8:
1929            u = 0x000000FF & con->Ico.U8;
1930            break;
1931         default:
1932            vpanic("iselIntExpr_RH.Iex_Const(mips)");
1933      }
1934      l = (Long) u;
1935      /* Now figure out if it's representable. */
1936      if (!syned && u <= 65535) {
1937         return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
1938      }
1939      if (syned && l >= -32767 && l <= 32767) {
1940         return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
1941      }
1942      /* no luck; use the Slow Way. */
1943   }
1944   /* default case: calculate into a register and return that */
1945   return MIPSRH_Reg(iselWordExpr_R(env, e));
1946}
1947
1948/* --------------------- RH5u --------------------- */
1949
1950/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
1951   being an immediate in the range 1 .. 31 inclusive.  Used for doing
1952   shift amounts. */
1953
1954static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e)
1955{
1956   MIPSRH *ri;
1957   ri = iselWordExpr_RH5u_wrk(env, e);
1958   /* sanity checks ... */
1959   switch (ri->tag) {
1960      case Mrh_Imm:
1961         vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31);
1962         vassert(!ri->Mrh.Imm.syned);
1963         return ri;
1964      case Mrh_Reg:
1965         vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32);
1966         vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1967         return ri;
1968      default:
1969         vpanic("iselIntExpr_RH5u: unknown mips RH tag");
1970   }
1971}
1972
1973/* DO NOT CALL THIS DIRECTLY ! */
1974static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e)
1975{
1976   IRType ty = typeOfIRExpr(env->type_env, e);
1977   vassert(ty == Ity_I8);
1978
1979   /* special case: immediate */
1980   if (e->tag == Iex_Const
1981       && e->Iex.Const.con->tag == Ico_U8
1982       && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) {
1983      return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
1984   }
1985
1986   /* default case: calculate into a register and return that */
1987   return MIPSRH_Reg(iselWordExpr_R(env, e));
1988}
1989
1990/* --------------------- RH6u --------------------- */
1991
1992/* Only used in 64-bit mode. */
1993static MIPSRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e )
1994{
1995   MIPSRH *ri;
1996   ri = iselWordExpr_RH6u_wrk(env, e);
1997   /* sanity checks ... */
1998   switch (ri->tag) {
1999   case Mrh_Imm:
2000      vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 63);
2001      vassert(!ri->Mrh.Imm.syned);
2002      return ri;
2003   case Mrh_Reg:
2004      vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
2005      vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2006      return ri;
2007   default:
2008      vpanic("iselIntExpr_RH6u: unknown mips64 RI tag");
2009   }
2010}
2011
2012/* DO NOT CALL THIS DIRECTLY ! */
2013static MIPSRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e )
2014{
2015   IRType ty = typeOfIRExpr(env->type_env, e);
2016   vassert(ty == Ity_I8);
2017
2018   /* special case: immediate */
2019   if (e->tag == Iex_Const
2020       && e->Iex.Const.con->tag == Ico_U8
2021       && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 63)
2022   {
2023      return MIPSRH_Imm(False /*unsigned */ ,
2024              e->Iex.Const.con->Ico.U8);
2025   }
2026
2027   /* default case: calculate into a register and return that */
2028   return MIPSRH_Reg(iselWordExpr_R(env, e));
2029}
2030
2031/* --------------------- CONDCODE --------------------- */
2032
2033/* Generate code to evaluated a bit-typed expression, returning the
2034   condition code which would correspond when the expression would
2035   notionally have returned 1. */
2036
2037static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e)
2038{
2039   MIPSCondCode cc = iselCondCode_wrk(env,e);
2040   vassert(cc != MIPScc_NV);
2041   return cc;
2042}
2043
2044/* DO NOT CALL THIS DIRECTLY ! */
2045static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
2046{
2047   vassert(e);
2048   vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
2049   /* Cmp*32*(x,y) ? */
2050   if (e->Iex.Binop.op == Iop_CmpEQ32
2051       || e->Iex.Binop.op == Iop_CmpNE32
2052       || e->Iex.Binop.op == Iop_CmpNE64
2053       || e->Iex.Binop.op == Iop_CmpLT32S
2054       || e->Iex.Binop.op == Iop_CmpLT32U
2055       || e->Iex.Binop.op == Iop_CmpLT64U
2056       || e->Iex.Binop.op == Iop_CmpLE32S
2057       || e->Iex.Binop.op == Iop_CmpLE64S
2058       || e->Iex.Binop.op == Iop_CmpLT64S
2059       || e->Iex.Binop.op == Iop_CmpEQ64
2060       || e->Iex.Binop.op == Iop_CasCmpEQ32
2061       || e->Iex.Binop.op == Iop_CasCmpEQ64) {
2062
2063      Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
2064                   || e->Iex.Binop.op == Iop_CmpLE32S
2065                   || e->Iex.Binop.op == Iop_CmpLT64S
2066                   || e->Iex.Binop.op == Iop_CmpLE64S);
2067      Bool size32;
2068      HReg dst = newVRegI(env);
2069      HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2070      HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
2071
2072      MIPSCondCode cc;
2073
2074      switch (e->Iex.Binop.op) {
2075         case Iop_CmpEQ32:
2076         case Iop_CasCmpEQ32:
2077            cc = MIPScc_EQ;
2078            size32 = True;
2079            break;
2080         case Iop_CmpNE32:
2081            cc = MIPScc_NE;
2082            size32 = True;
2083            break;
2084         case Iop_CmpNE64:
2085            cc = MIPScc_NE;
2086            size32 = True;
2087            break;
2088         case Iop_CmpLT32S:
2089            cc = MIPScc_LT;
2090            size32 = True;
2091            break;
2092         case Iop_CmpLT32U:
2093            cc = MIPScc_LO;
2094            size32 = True;
2095            break;
2096         case Iop_CmpLT64U:
2097            cc = MIPScc_LO;
2098            size32 = False;
2099            break;
2100         case Iop_CmpLE32S:
2101            cc = MIPScc_LE;
2102            size32 = True;
2103            break;
2104         case Iop_CmpLE64S:
2105            cc = MIPScc_LE;
2106            size32 = False;
2107            break;
2108         case Iop_CmpLT64S:
2109            cc = MIPScc_LT;
2110            size32 = False;
2111            break;
2112         case Iop_CmpEQ64:
2113         case Iop_CasCmpEQ64:
2114            cc = MIPScc_EQ;
2115            size32 = False;
2116            break;
2117         default:
2118            vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
2119            break;
2120      }
2121
2122      addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
2123      /* Store result to guest_COND */
2124      MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2125
2126      addInstr(env, MIPSInstr_Store(4,
2127               MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2128                            am_addr->Mam.IR.base),
2129               dst, mode64));
2130      return cc;
2131   }
2132   if (e->Iex.Binop.op == Iop_Not1) {
2133      HReg r_dst = newVRegI(env);
2134      HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
2135      MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
2136
2137      addInstr(env, MIPSInstr_LI(r_dst, 0x1));
2138      addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
2139      /* Store result to guest_COND */
2140      MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2141
2142      addInstr(env, MIPSInstr_Store(4,
2143               MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2144                            am_addr->Mam.IR.base),
2145               r_dst, mode64));
2146      return MIPScc_NE;
2147   }
2148   if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) {
2149      HReg r_dst = iselWordExpr_R_wrk(env, e);
2150      /* Store result to guest_COND */
2151      MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2152
2153      addInstr(env, MIPSInstr_Store(4,
2154               MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2155                            am_addr->Mam.IR.base),
2156               r_dst, mode64));
2157      return MIPScc_EQ;
2158   }
2159
2160   vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag);
2161   ppIRExpr(e);
2162   vpanic("iselCondCode(mips)");
2163}
2164
2165/*---------------------------------------------------------*/
2166/*--- ISEL: Integer expressions (128 bit)               ---*/
2167/*---------------------------------------------------------*/
2168
2169/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
2170   which is returned as the first two parameters.  As with
2171   iselWordExpr_R, these may be either real or virtual regs; in any
2172   case they must not be changed by subsequent code emitted by the
2173   caller.  */
2174
2175static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2176{
2177   vassert(env->mode64);
2178   iselInt128Expr_wrk(rHi, rLo, env, e);
2179   vassert(hregClass(*rHi) == HRcGPR(env->mode64));
2180   vassert(hregIsVirtual(*rHi));
2181   vassert(hregClass(*rLo) == HRcGPR(env->mode64));
2182   vassert(hregIsVirtual(*rLo));
2183}
2184
2185/* DO NOT CALL THIS DIRECTLY ! */
2186static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
2187                               IRExpr * e)
2188{
2189   vassert(e);
2190   vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
2191
2192   /* read 128-bit IRTemp */
2193   if (e->tag == Iex_RdTmp) {
2194      lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
2195      return;
2196   }
2197
2198   /* --------- BINARY ops --------- */
2199   if (e->tag == Iex_Binop) {
2200      switch (e->Iex.Binop.op) {
2201         /* 64 x 64 -> 128 multiply */
2202         case Iop_MullU64:
2203         case Iop_MullS64: {
2204            HReg tLo = newVRegI(env);
2205            HReg tHi = newVRegI(env);
2206            Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
2207            HReg r_dst = newVRegI(env);
2208            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2209            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2210            addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ ,
2211                                        r_dst, r_srcL, r_srcR));
2212            addInstr(env, MIPSInstr_Mfhi(tHi));
2213            addInstr(env, MIPSInstr_Mflo(tLo));
2214            *rHi = tHi;
2215            *rLo = tLo;
2216            return;
2217         }
2218
2219         /* 64HLto128(e1,e2) */
2220         case Iop_64HLto128:
2221            *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2222            *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2223            return;
2224
2225         case Iop_DivModS64to64: {
2226            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2227            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2228            HReg tLo = newVRegI(env);
2229            HReg tHi = newVRegI(env);
2230            Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
2231
2232            addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
2233            addInstr(env, MIPSInstr_Mfhi(tHi));
2234            addInstr(env, MIPSInstr_Mflo(tLo));
2235            *rHi = tHi;
2236            *rLo = tLo;
2237            return;
2238         }
2239
2240         case Iop_DivModU128to64:
2241         case Iop_DivModS128to64: {
2242            vassert(mode64);
2243            HReg rHi1, rLo1;
2244            iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1);
2245
2246            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2247            HReg tLo = newVRegI(env);
2248            HReg tHi = newVRegI(env);
2249            Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64);
2250
2251            addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR));
2252            addInstr(env, MIPSInstr_Mfhi(tHi));
2253            addInstr(env, MIPSInstr_Mflo(tLo));
2254            *rHi = tHi;
2255            *rLo = tLo;
2256            return;
2257         }
2258
2259         default:
2260            break;
2261      }
2262   }
2263   vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag);
2264   ppIRExpr(e);
2265   vpanic("iselInt128Expr(mips64)");
2266}
2267
2268/*---------------------------------------------------------*/
2269/*--- ISEL: Integer expressions (64 bit)                ---*/
2270/*---------------------------------------------------------*/
2271
2272/* 32-bit mode ONLY. Compute a 64-bit value into the register
2273 * pair HI, LO. HI and LO must not be changed by subsequent
2274 *  code emitted by the caller. */
2275
2276static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2277{
2278   vassert(!env->mode64);
2279   iselInt64Expr_wrk(rHi, rLo, env, e);
2280   vassert(hregClass(*rHi) == HRcInt32);
2281   vassert(hregIsVirtual(*rHi));
2282   vassert(hregClass(*rLo) == HRcInt32);
2283   vassert(hregIsVirtual(*rLo));
2284}
2285
2286/* DO NOT CALL THIS DIRECTLY ! */
2287static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2288{
2289   vassert(e);
2290   vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
2291
2292   /* read 64-bit IRTemp */
2293   if (e->tag == Iex_RdTmp) {
2294      lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp);
2295      return;
2296   }
2297   /* 64-bit load */
2298   if (e->tag == Iex_Load) {
2299      HReg tLo = newVRegI(env);
2300      HReg tHi = newVRegI(env);
2301      HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
2302      addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64));
2303      addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64));
2304      *rHi = tHi;
2305      *rLo = tLo;
2306      return;
2307   }
2308
2309   /* 64-bit literal */
2310   if (e->tag == Iex_Const) {
2311      ULong w64 = e->Iex.Const.con->Ico.U64;
2312      UInt wHi = toUInt(w64 >> 32);
2313      UInt wLo = toUInt(w64);
2314      HReg tLo = newVRegI(env);
2315      HReg tHi = newVRegI(env);
2316      vassert(e->Iex.Const.con->tag == Ico_U64);
2317
2318      if (wLo == wHi) {
2319         /* Save a precious Int register in this special case. */
2320         addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
2321         *rHi = tLo;
2322         *rLo = tLo;
2323      } else {
2324         addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi));
2325         addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
2326         *rHi = tHi;
2327         *rLo = tLo;
2328      }
2329
2330      return;
2331   }
2332
2333   /* 64-bit GET */
2334   if (e->tag == Iex_Get) {
2335      HReg tLo = newVRegI(env);
2336      HReg tHi = newVRegI(env);
2337
2338      MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
2339                                        GuestStatePointer(mode64));
2340      addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2341      addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64));
2342      *rHi = tHi;
2343      *rLo = tLo;
2344      return;
2345   }
2346
2347   /* 64-bit ITE */
2348   if (e->tag == Iex_ITE) {
2349      vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1);
2350      HReg expr0Lo, expr0Hi;
2351      HReg expr1Lo, expr1Hi;
2352      HReg desLo  = newVRegI(env);
2353      HReg desHi  = newVRegI(env);
2354      HReg cond = iselWordExpr_R(env, e->Iex.ITE.cond);
2355
2356      /* expr0Hi:expr0Lo = iffalse */
2357      /* expr1Hi:expr1Lo = iftrue */
2358      iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.ITE.iffalse);
2359      iselInt64Expr(&expr1Hi, &expr1Lo, env, e->Iex.ITE.iftrue);
2360
2361      /* move desLo, expr0Lo
2362       * move desHi, expr0Hi
2363       * movn desLo, expr1Lo, cond
2364       * movn desHi, expr1Hi, cond */
2365      addInstr(env, mk_iMOVds_RR(desLo, expr0Lo));
2366      addInstr(env, mk_iMOVds_RR(desHi, expr0Hi));
2367      addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desLo, expr1Lo, cond));
2368      addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desHi, expr1Hi, cond));
2369
2370      *rHi = desHi;
2371      *rLo = desLo;
2372      return;
2373   }
2374
2375   /* --------- BINARY ops --------- */
2376   if (e->tag == Iex_Binop) {
2377      IROp op_binop = e->Iex.Binop.op;
2378      switch (op_binop) {
2379         /* 32 x 32 -> 64 multiply */
2380         /* Add64 */
2381         case Iop_Add64: {
2382            HReg xLo, xHi, yLo, yHi, carryBit;
2383
2384            HReg tHi = newVRegI(env);
2385            HReg tHi1 = newVRegI(env);
2386            HReg tLo = newVRegI(env);
2387
2388            carryBit = newVRegI(env);
2389
2390            Bool size32 = True;
2391            MIPSCondCode cc = MIPScc_LO;
2392
2393            iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2394            iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2395            addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo)));
2396
2397            /* Check carry. */
2398            addInstr(env, MIPSInstr_Cmp(False, size32, carryBit, tLo, xLo, cc));
2399
2400            addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi1, xHi, MIPSRH_Reg(yHi)));
2401            addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, tHi1,
2402                                        MIPSRH_Reg(carryBit)));
2403
2404            *rHi = tHi;
2405            *rLo = tLo;
2406            return;
2407         }
2408         case Iop_Sub64: {
2409            HReg xLo, xHi, yLo, yHi, borrow;
2410            Bool size32 = True;
2411            MIPSCondCode cc = MIPScc_LO;
2412
2413            HReg tHi = newVRegI(env);
2414            HReg tLo = newVRegI(env);
2415
2416            borrow = newVRegI(env);
2417
2418            iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2419            iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2420
2421            addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, xLo, MIPSRH_Reg(yLo)));
2422
2423            /* Check if borrow is nedded. */
2424            addInstr(env, MIPSInstr_Cmp(False, size32, borrow, xLo, yLo, cc));
2425
2426            addInstr(env, MIPSInstr_Alu(Malu_ADD, yHi, yHi,
2427                                        MIPSRH_Reg(borrow)));
2428            addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, xHi, MIPSRH_Reg(yHi)));
2429
2430            *rHi = tHi;
2431            *rLo = tLo;
2432            return;
2433         }
2434         case Iop_MullU32:
2435         case Iop_MullS32: {
2436            HReg tLo = newVRegI(env);
2437            HReg tHi = newVRegI(env);
2438            HReg r_dst = newVRegI(env);
2439            Bool syned = toBool(op_binop == Iop_MullS32);
2440            HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2441            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2442
2443            addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */,
2444                                        True /*widen */ , True,
2445                                        r_dst, r_srcL, r_srcR));
2446            addInstr(env, MIPSInstr_Mfhi(tHi));
2447            addInstr(env, MIPSInstr_Mflo(tLo));
2448            *rHi = tHi;
2449            *rLo = tLo;
2450
2451            return;
2452         }
2453         case Iop_DivModS64to32:
2454         case Iop_DivModU64to32: {
2455            HReg r_sHi, r_sLo;
2456            HReg tLo = newVRegI(env);
2457            HReg tHi = newVRegI(env);
2458            Bool syned = toBool(op_binop == Iop_DivModS64to32);
2459            HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2460
2461            iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1);
2462            addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR));
2463            addInstr(env, MIPSInstr_Mfhi(tHi));
2464            addInstr(env, MIPSInstr_Mflo(tLo));
2465            *rHi = tHi;
2466            *rLo = tLo;
2467
2468            return;
2469         }
2470
2471         /* 32HLto64(e1,e2) */
2472         case Iop_32HLto64:
2473            *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2474            *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2475
2476            return;
2477         /* Or64/And64/Xor64 */
2478         case Iop_Or64:
2479         case Iop_And64:
2480         case Iop_Xor64: {
2481            HReg xLo, xHi, yLo, yHi;
2482            HReg tLo = newVRegI(env);
2483            HReg tHi = newVRegI(env);
2484            MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR :
2485                           (op_binop == Iop_And64) ? Malu_AND : Malu_XOR;
2486            iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2487            iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2488            addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi)));
2489            addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo)));
2490            *rHi = tHi;
2491            *rLo = tLo;
2492            return;
2493         }
2494
2495         case Iop_Shr64: {
2496#if defined (_MIPSEL)
2497            /* 64-bit logical shift right based on what gcc generates:
2498               <shift>:
2499               nor  v0, zero, a2
2500               sll  a3, a1, 0x1
2501               sllv a3, a3, v0
2502               srlv v0, a0, a2
2503               srlv v1, a1, a2
2504               andi a0, a2, 0x20
2505               or   v0, a3, v0
2506               movn v0, v1, a0
2507               jr   ra
2508               movn v1, zero, a0
2509            */
2510            HReg a0, a1;
2511            HReg a0tmp = newVRegI(env);
2512            HReg a2 = newVRegI(env);
2513            HReg a3 = newVRegI(env);
2514            HReg v0 = newVRegI(env);
2515            HReg v1 = newVRegI(env);
2516            HReg zero = newVRegI(env);
2517            MIPSRH *sa = NULL;
2518
2519            iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2520            sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
2521
2522            if (sa->tag == Mrh_Imm) {
2523               addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2524            }
2525            else {
2526               addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2527                                           MIPSRH_Imm(False, 0x3f)));
2528            }
2529
2530            addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2531            /* nor  v0, zero, a2 */
2532            addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2533            /* sll  a3, a1, 0x1 */
2534            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2535                                         a3, a1, MIPSRH_Imm(False, 0x1)));
2536            /* sllv a3, a3, v0 */
2537            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2538                                         a3, a3, MIPSRH_Reg(v0)));
2539            /* srlv v0, a0, a2 */
2540            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2541                                         v0, a0, MIPSRH_Reg(a2)));
2542            /* srlv v1, a1, a2 */
2543            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2544                                         v1, a1, MIPSRH_Reg(a2)));
2545            /* andi a0, a2, 0x20 */
2546            addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2,
2547                                        MIPSRH_Imm(False, 0x20)));
2548            /* or   v0, a3, v0 */
2549            addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0)));
2550
2551            /* movn    v0, v1, a0 */
2552            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp));
2553            /* movn    v1, zero, a0 */
2554            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, zero, a0tmp));
2555
2556            *rHi = v1;
2557            *rLo = v0;
2558            return;
2559#elif defined (_MIPSEB)
2560            /* 64-bit logical shift right based on what gcc generates:
2561               <shift>:
2562               nor  v0, zero, a2
2563               sll  a3, a0, 0x1
2564               sllv a3, a3, v0
2565               srlv v1, a1, a2
2566               andi v0, a2, 0x20
2567               or   v1, a3, v1
2568               srlv a2, a0, a2
2569               movn v1, a2, v0
2570               movn a2, zero, v0
2571               jr   ra
2572               move v0, a2
2573            */
2574            HReg a0, a1;
2575            HReg a2 = newVRegI(env);
2576            HReg a2tmp = newVRegI(env);
2577            HReg a3 = newVRegI(env);
2578            HReg v0 = newVRegI(env);
2579            HReg v1 = newVRegI(env);
2580            HReg zero = newVRegI(env);
2581            MIPSRH *sa = NULL;
2582
2583            iselInt64Expr(&a0, &a1, env, e->Iex.Binop.arg1);
2584            sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
2585
2586            if (sa->tag == Mrh_Imm) {
2587               addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2588            }
2589            else {
2590               addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2591                                           MIPSRH_Imm(False, 0x3f)));
2592            }
2593
2594            addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2595            /* nor v0, zero, a2 */
2596            addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2597            /* sll a3, a0, 0x1 */
2598            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2599                                         a3, a0, MIPSRH_Imm(False, 0x1)));
2600            /* sllv a3, a3, v0 */
2601            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2602                                         a3, a3, MIPSRH_Reg(v0)));
2603            /* srlv v1, a1, a2 */
2604            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2605                                         v1, a1, MIPSRH_Reg(a2)));
2606            /* andi v0, a2, 0x20 */
2607            addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2,
2608                                        MIPSRH_Imm(False, 0x20)));
2609            /* or v1, a3, v1 */
2610            addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1)));
2611            /* srlv a2, a0, a2 */
2612            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2613                             a2tmp, a0, MIPSRH_Reg(a2)));
2614
2615            /* movn v1, a2, v0 */
2616            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2tmp, v0));
2617            /* movn  a2, zero, v0 */
2618            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2tmp, zero, v0));
2619            /* move v0, a2 */
2620            addInstr(env, mk_iMOVds_RR(v0, a2tmp));
2621
2622            *rHi = v0;
2623            *rLo = v1;
2624            return;
2625#endif
2626         }
2627
2628         case Iop_Shl64: {
2629            /* 64-bit shift left based on what gcc generates:
2630               <shift>:
2631               nor  v0,zero,a2
2632               srl  a3,a0,0x1
2633               srlv a3,a3,v0
2634               sllv v1,a1,a2
2635               andi v0,a2,0x20
2636               or   v1,a3,v1
2637               sllv a2,a0,a2
2638               movn v1,a2,v0
2639               movn a2,zero,v0
2640               jr   ra
2641               move v0,a2
2642            */
2643            HReg a0, a1;
2644            HReg a2 = newVRegI(env);
2645            HReg a3 = newVRegI(env);
2646            HReg v0 = newVRegI(env);
2647            HReg v1 = newVRegI(env);
2648            HReg zero = newVRegI(env);
2649            MIPSRH *sa = NULL;
2650
2651            iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2652            sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
2653
2654            if (sa->tag == Mrh_Imm) {
2655               addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2656            }
2657            else {
2658               addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2659                                           MIPSRH_Imm(False, 0x3f)));
2660            }
2661
2662            addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2663            /* nor v0, zero, a2 */
2664            addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2665            /* srl a3, a0, 0x1 */
2666            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2667                                         a3, a0, MIPSRH_Imm(False, 0x1)));
2668            /* srlv a3, a3, v0 */
2669            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2670                                         a3, a3, MIPSRH_Reg(v0)));
2671            /* sllv v1, a1, a2 */
2672            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2673                                         v1, a1, MIPSRH_Reg(a2)));
2674            /* andi v0, a2, 0x20 */
2675            addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2,
2676                                        MIPSRH_Imm(False, 0x20)));
2677            /* or v1, a3, v1 */
2678            addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1)));
2679            /* sllv a2, a0, a2 */
2680            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2681                                         a2, a0, MIPSRH_Reg(a2)));
2682
2683            /* movn v1, a2, v0 */
2684            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2, v0));
2685            /* movn a2, zero, v0 */
2686            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2, zero, v0));
2687            addInstr(env, mk_iMOVds_RR(v0, a2));
2688
2689            *rHi = v1;
2690            *rLo = v0;
2691            return;
2692         }
2693
2694         case Iop_Sar64: {
2695            /* 64-bit arithmetic shift right based on what gcc generates:
2696               <shift>:
2697               nor  v0, zero, a2
2698               sll  a3, a1, 0x1
2699               sllv a3, a3, v0
2700               srlv v0, a0, a2
2701               srav v1, a1, a2
2702               andi a0, a2, 0x20
2703               sra  a1, a1, 0x1f
2704               or   v0, a3, v0
2705               movn v0, v1, a0
2706               jr   ra
2707               movn v1, a1, a0
2708            */
2709            HReg a0, a1;
2710            HReg a0tmp = newVRegI(env);
2711            HReg a1tmp = newVRegI(env);
2712            HReg a2 = newVRegI(env);
2713            HReg a3 = newVRegI(env);
2714            HReg v0 = newVRegI(env);
2715            HReg v1 = newVRegI(env);
2716            HReg zero = newVRegI(env);
2717            MIPSRH *sa = NULL;
2718
2719            iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2720            sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
2721
2722            if (sa->tag == Mrh_Imm) {
2723               addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2724            }
2725            else {
2726               addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2727                                           MIPSRH_Imm(False, 0x3f)));
2728            }
2729
2730            addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2731            /* nor  v0, zero, a2 */
2732            addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2733            /* sll  a3, a1, 0x1 */
2734            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2735                                         a3, a1, MIPSRH_Imm(False, 0x1)));
2736            /* sllv a3, a3, v0 */
2737            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2738                                         a3, a3, MIPSRH_Reg(v0)));
2739            /* srlv v0, a0, a2 */
2740            addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2741                                         v0, a0, MIPSRH_Reg(a2)));
2742            /* srav v1, a1, a2 */
2743            addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
2744                                         v1, a1, MIPSRH_Reg(a2)));
2745            /* andi a0, a2, 0x20 */
2746            addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2,
2747                                        MIPSRH_Imm(False, 0x20)));
2748            /* sra a1, a1, 0x1f */
2749            addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
2750                                         a1tmp, a1, MIPSRH_Imm(False, 0x1f)));
2751            /* or   v0, a3, v0 */
2752            addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0)));
2753
2754            /* movn    v0, v1, a0 */
2755            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp));
2756            /* movn    v1, a1, a0 */
2757            addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a1tmp, a0tmp));
2758
2759            *rHi = v1;
2760            *rLo = v0;
2761            return;
2762         }
2763
2764         case Iop_F32toI64S: {
2765            HReg tmpD = newVRegD(env);
2766            HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
2767            HReg tLo  = newVRegI(env);
2768            HReg tHi  = newVRegI(env);
2769            MIPSAMode *am_addr;
2770
2771            /* CVTLS tmpD, valF */
2772            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2773            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
2774            set_MIPS_rounding_default(env);
2775
2776            sub_from_sp(env, 16);  /* Move SP down 16 bytes */
2777            am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2778
2779            /* store as F64 */
2780            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
2781                                           am_addr));
2782            /* load as 2xI32 */
2783#if defined (_MIPSEL)
2784            addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2785            addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2786                                         mode64));
2787#elif defined (_MIPSEB)
2788            addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
2789            addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
2790                                         mode64));
2791#endif
2792
2793            /* Reset SP */
2794            add_to_sp(env, 16);
2795
2796            *rHi = tHi;
2797            *rLo = tLo;
2798
2799            return;
2800         }
2801
2802         default:
2803            break;
2804      }
2805   }
2806
2807   /* --------- UNARY ops --------- */
2808   if (e->tag == Iex_Unop) {
2809      switch (e->Iex.Unop.op) {
2810         case Iop_1Sto64: {
2811            HReg tLo = newVRegI(env);
2812            HReg tHi = newVRegI(env);
2813            HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2814            HReg tmp = newVRegI(env);
2815
2816            addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src,
2817                          MIPSRH_Imm(False, 31)));
2818            addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
2819                          MIPSRH_Imm(False, 31)));
2820
2821            addInstr(env, mk_iMOVds_RR(tHi, tmp));
2822            addInstr(env, mk_iMOVds_RR(tLo, tmp));
2823
2824            *rHi = tHi;
2825            *rLo = tLo;
2826            return;
2827         }
2828
2829         /* 32Sto64(e) */
2830         case Iop_32Sto64: {
2831            HReg tLo = newVRegI(env);
2832            HReg tHi = newVRegI(env);
2833            HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2834            addInstr(env, mk_iMOVds_RR(tHi, src));
2835            addInstr(env, mk_iMOVds_RR(tLo, src));
2836            addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi,
2837                          MIPSRH_Imm(False, 31)));
2838            *rHi = tHi;
2839            *rLo = tLo;
2840            return;
2841         }
2842
2843         /* 8Uto64(e) */
2844         case Iop_8Uto64: {
2845            HReg tLo = newVRegI(env);
2846            HReg tHi = newVRegI(env);
2847            HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2848            addInstr(env, MIPSInstr_Alu(Malu_AND, tLo, src,
2849                                        MIPSRH_Imm(False, 0xFF)));
2850            addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2851                                        MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2852            *rHi = tHi;
2853            *rLo = tLo;
2854            return;
2855         }
2856
2857         /* 32Uto64(e) */
2858         case Iop_32Uto64: {
2859            HReg tLo = newVRegI(env);
2860            HReg tHi = newVRegI(env);
2861            HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2862            addInstr(env, mk_iMOVds_RR(tLo, src));
2863            addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2864                          MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2865            *rHi = tHi;
2866            *rLo = tLo;
2867            return;
2868         }
2869
2870         case Iop_Left64: {
2871            HReg yHi, yLo;
2872            HReg tHi  = newVRegI(env);
2873            HReg tLo  = newVRegI(env);
2874            HReg tmp  = newVRegI(env);
2875            HReg tmp1  = newVRegI(env);
2876            HReg tmp2  = newVRegI(env);
2877            HReg zero = newVRegI(env);
2878            MIPSCondCode cc = MIPScc_LO;
2879
2880            /* yHi:yLo = arg */
2881            iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
2882            /* zero = 0 */
2883            addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2884
2885            /* tmp2:tmp1 = 0 - (yHi:yLo)*/
2886            addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, zero, MIPSRH_Reg(yLo)));
2887            addInstr(env, MIPSInstr_Cmp(False, True, tmp1, zero, tmp2, cc));
2888            addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, zero, MIPSRH_Reg(yHi)));
2889            addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp1, tmp, MIPSRH_Reg(tmp1)));
2890
2891            /* So now we have tmp2:tmp1 = -arg.  To finish off, or 'arg'
2892               back in, so as to give the final result
2893               tHi:tLo = arg | -arg. */
2894            addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, yHi, MIPSRH_Reg(tmp1)));
2895            addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, yLo, MIPSRH_Reg(tmp2)));
2896            *rHi = tHi;
2897            *rLo = tLo;
2898            return;
2899         }
2900
2901         case Iop_CmpwNEZ64: {
2902            HReg srcLo, srcHi;
2903            HReg tmp1 = newVRegI(env);
2904            HReg tmp2 = newVRegI(env);
2905            /* srcHi:srcLo = arg */
2906            iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
2907            /* tmp1 = srcHi | srcLo */
2908            addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo,
2909                                        MIPSRH_Reg(srcHi)));
2910            /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2911
2912            addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
2913                                        MIPSRH_Reg(tmp1)));
2914
2915            addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
2916            addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2,
2917                          MIPSRH_Imm(False, 31)));
2918            *rHi = tmp2;
2919            *rLo = tmp2;
2920            return;
2921
2922         }
2923         case Iop_ReinterpF64asI64: {
2924            HReg tLo = newVRegI(env);
2925            HReg tHi = newVRegI(env);
2926            MIPSAMode *am_addr;
2927            HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
2928
2929            sub_from_sp(env, 16);  /* Move SP down 16 bytes */
2930            am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2931
2932            /* store as F64 */
2933            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
2934                                           am_addr));
2935            /* load as 2xI32 */
2936#if defined (_MIPSEL)
2937            addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2938            addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2939                                         mode64));
2940#elif defined (_MIPSEB)
2941            addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
2942            addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
2943                                         mode64));
2944#endif
2945
2946            /* Reset SP */
2947            add_to_sp(env, 16);
2948
2949            *rHi = tHi;
2950            *rLo = tLo;
2951            return;
2952         }
2953
2954         default:
2955            vex_printf("UNARY: No such op: ");
2956            ppIROp(e->Iex.Unop.op);
2957            vex_printf("\n");
2958            break;
2959      }
2960   }
2961
2962   vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag);
2963   ppIRExpr(e);
2964   vpanic("iselInt64Expr(mips)");
2965}
2966
2967/*---------------------------------------------------------*/
2968/*--- ISEL: Floating point expressions (32 bit)         ---*/
2969/*---------------------------------------------------------*/
2970
2971/* Nothing interesting here; really just wrappers for
2972   64-bit stuff. */
2973static HReg iselFltExpr(ISelEnv * env, IRExpr * e)
2974{
2975   HReg r = iselFltExpr_wrk(env, e);
2976   vassert(hregIsVirtual(r));
2977   return r;
2978}
2979
2980/* DO NOT CALL THIS DIRECTLY */
2981static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
2982{
2983   IRType ty = typeOfIRExpr(env->type_env, e);
2984   vassert(ty == Ity_F32 || (ty == Ity_F64 && fp_mode64));
2985
2986   if (e->tag == Iex_RdTmp) {
2987      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2988   }
2989
2990   if (e->tag == Iex_Load) {
2991      vassert(e->Iex.Load.ty == Ity_F32
2992              || (e->Iex.Load.ty == Ity_F64 && fp_mode64));
2993      HReg r_dst;
2994      MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
2995      if (e->Iex.Load.ty == Ity_F64) {
2996         r_dst = newVRegD(env);
2997         addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
2998      } else {
2999         r_dst = newVRegF(env);
3000         addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
3001      }
3002      return r_dst;
3003   }
3004
3005   if (e->tag == Iex_Get) {
3006      MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
3007                                        GuestStatePointer(mode64));
3008      HReg r_dst;
3009      if (e->Iex.Load.ty == Ity_F64) {
3010         r_dst = newVRegD(env);
3011         addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
3012      } else {
3013         r_dst = newVRegF(env);
3014         addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
3015      }
3016      return r_dst;
3017   }
3018
3019   if (e->tag == Iex_Unop) {
3020      switch (e->Iex.Unop.op) {
3021      case Iop_ReinterpI32asF32: {
3022         HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3023         HReg r_dst = newVRegF(env);
3024
3025         /* Move Word to Floating Point
3026            mtc1 r_dst, valS */
3027         addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, fr_src));
3028
3029         return r_dst;
3030      }
3031      case Iop_F32toF64: {
3032         vassert(fp_mode64);
3033         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3034         HReg dst = newVRegD(env);
3035
3036         addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
3037         return dst;
3038      }
3039      case Iop_ReinterpI64asF64: {
3040         HReg r_dst;
3041         if (mode64) {
3042            HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3043            r_dst = newVRegF(env);
3044            /* Move Doubleword to Floating Point
3045               dmtc1 r_dst, fr_src */
3046            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src));
3047         } else {
3048             HReg Hi, Lo;
3049             r_dst = newVRegD(env);
3050             iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
3051             r_dst = mk_LoadRR32toFPR(env, Hi, Lo);  /* 2*I32 -> F64 */
3052         }
3053         return r_dst;
3054      }
3055      case Iop_I32StoF64: {
3056         vassert(fp_mode64);
3057         HReg dst = newVRegF(env);
3058         HReg tmp = newVRegF(env);
3059         HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3060
3061         /* Move Word to Floating Point
3062            mtc1 tmp, r_src */
3063         addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
3064
3065         /* and do convert */
3066         addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
3067
3068         return dst;
3069      }
3070      case Iop_AbsF32:
3071      case Iop_AbsF64: {
3072         Bool sz32 = e->Iex.Unop.op == Iop_AbsF32;
3073         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3074         HReg dst = newVRegF(env);
3075         addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src));
3076         return dst;
3077      }
3078      case Iop_NegF32:
3079      case Iop_NegF64: {
3080         Bool sz32 = e->Iex.Unop.op == Iop_NegF32;
3081         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3082         HReg dst = newVRegF(env);
3083         addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src));
3084         return dst;
3085      }
3086      case Iop_RoundF64toF64_ZERO: {
3087         vassert(mode64);
3088         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3089         HReg dst = newVRegF(env);
3090         addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, dst, src));
3091         return dst;
3092      }
3093      case Iop_RoundF64toF64_NEAREST: {
3094         vassert(mode64);
3095         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3096         HReg dst = newVRegF(env);
3097         addInstr(env, MIPSInstr_FpConvert(Mfp_ROUNDLD, dst, src));
3098         return dst;
3099      }
3100      case Iop_RoundF64toF64_NegINF: {
3101         vassert(mode64);
3102         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3103         HReg dst = newVRegF(env);
3104         addInstr(env, MIPSInstr_FpConvert(Mfp_FLOORLD, dst, src));
3105         return dst;
3106      }
3107      case Iop_RoundF64toF64_PosINF: {
3108         vassert(mode64);
3109         HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3110         HReg dst = newVRegF(env);
3111         addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, dst, src));
3112         return dst;
3113      }
3114
3115      default:
3116         break;
3117      }
3118   }
3119
3120   if (e->tag == Iex_Triop) {
3121      switch (e->Iex.Triop.details->op) {
3122         case Iop_DivF32:
3123         case Iop_DivF64:
3124         case Iop_MulF32:
3125         case Iop_MulF64:
3126         case Iop_AddF32:
3127         case Iop_AddF64:
3128         case Iop_SubF32:
3129         case Iop_SubF64: {
3130            MIPSFpOp op = 0;
3131            HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2);
3132            HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3);
3133            HReg dst = newVRegF(env);
3134            switch (e->Iex.Triop.details->op) {
3135               case Iop_DivF32:
3136                  op = Mfp_DIVS;
3137                  break;
3138               case Iop_DivF64:
3139                  vassert(fp_mode64);
3140                  op = Mfp_DIVD;
3141                  break;
3142               case Iop_MulF32:
3143                  op = Mfp_MULS;
3144                  break;
3145               case Iop_MulF64:
3146                  vassert(fp_mode64);
3147                  op = Mfp_MULD;
3148                  break;
3149               case Iop_AddF32:
3150                  op = Mfp_ADDS;
3151                  break;
3152               case Iop_AddF64:
3153                  vassert(fp_mode64);
3154                  op = Mfp_ADDD;
3155                  break;
3156               case Iop_SubF32:
3157                  op = Mfp_SUBS;
3158                  break;
3159               case Iop_SubF64:
3160                  vassert(fp_mode64);
3161                  op = Mfp_SUBD;
3162                  break;
3163               default:
3164                  vassert(0);
3165            }
3166            set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
3167            addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
3168            set_MIPS_rounding_default(env);
3169            return dst;
3170         }
3171         default:
3172            break;
3173      }
3174   }
3175
3176   if (e->tag == Iex_Binop) {
3177      switch (e->Iex.Binop.op) {
3178         case Iop_F64toF32: {
3179            HReg valD;
3180            if (mode64)
3181               valD = iselFltExpr(env, e->Iex.Binop.arg2);
3182            else
3183               valD = iselDblExpr(env, e->Iex.Binop.arg2);
3184            HReg valS = newVRegF(env);
3185
3186            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3187            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD));
3188            set_MIPS_rounding_default(env);
3189            return valS;
3190         }
3191
3192         case Iop_RoundF32toInt: {
3193               HReg valS = newVRegF(env);
3194               HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
3195
3196               set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3197               addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
3198               set_MIPS_rounding_default(env);
3199               return valS;
3200            }
3201
3202         case Iop_RoundF64toInt: {
3203            HReg valS = newVRegF(env);
3204            HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
3205
3206            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3207            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, valS, valF));
3208            set_MIPS_rounding_default(env);
3209            return valS;
3210         }
3211
3212         case Iop_I32StoF32: {
3213            HReg r_dst = newVRegF(env);
3214            HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3215            HReg tmp = newVRegF(env);
3216
3217            /* Move Word to Floating Point
3218               mtc1 tmp, fr_src */
3219            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, fr_src));
3220
3221            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3222            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp));
3223            set_MIPS_rounding_default(env);
3224
3225            return r_dst;
3226         }
3227
3228         case Iop_I64StoF64: {
3229            HReg r_dst = newVRegF(env);
3230            MIPSAMode *am_addr;
3231            HReg tmp, fr_src;
3232            if (mode64) {
3233               tmp = newVRegF(env);
3234               fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3235               /* Move SP down 8 bytes */
3236               sub_from_sp(env, 8);
3237               am_addr = MIPSAMode_IR(0, StackPointer(mode64));
3238
3239               /* store as I64 */
3240               addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
3241
3242               /* load as Ity_F64 */
3243               addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
3244
3245               /* Reset SP */
3246               add_to_sp(env, 8);
3247            } else {
3248               HReg Hi, Lo;
3249               tmp = newVRegD(env);
3250               iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
3251               tmp = mk_LoadRR32toFPR(env, Hi, Lo);  /* 2*I32 -> F64 */
3252            }
3253
3254            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3255            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
3256            set_MIPS_rounding_default(env);
3257
3258            return r_dst;
3259         }
3260
3261         case Iop_I64StoF32: {
3262            HReg r_dst = newVRegF(env);
3263            MIPSAMode *am_addr;
3264            HReg fr_src, tmp;
3265            if (mode64) {
3266               tmp = newVRegF(env);
3267               fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3268               /* Move SP down 8 bytes */
3269               sub_from_sp(env, 8);
3270               am_addr = MIPSAMode_IR(0, StackPointer(mode64));
3271
3272               /* store as I64 */
3273               addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
3274
3275               /* load as Ity_F64 */
3276               addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
3277
3278               /* Reset SP */
3279               add_to_sp(env, 8);
3280            } else {
3281               HReg Hi, Lo;
3282               tmp = newVRegD(env);
3283               iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
3284               tmp = mk_LoadRR32toFPR(env, Hi, Lo);  /* 2*I32 -> F64 */
3285            }
3286
3287            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3288            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSL, r_dst, tmp));
3289            set_MIPS_rounding_default(env);
3290
3291            return r_dst;
3292         }
3293
3294         case Iop_SqrtF32:
3295         case Iop_SqrtF64: {
3296            Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32;
3297            HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
3298            HReg dst = newVRegF(env);
3299            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3300            addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst,
3301                                            src));
3302            set_MIPS_rounding_default(env);
3303            return dst;
3304         }
3305
3306         default:
3307            break;
3308      }
3309   }
3310
3311   if (e->tag == Iex_Qop) {
3312      switch (e->Iex.Qop.details->op) {
3313         case Iop_MAddF32:
3314         case Iop_MAddF64:
3315         case Iop_MSubF32:
3316         case Iop_MSubF64: {
3317            MIPSFpOp op = 0;
3318            switch (e->Iex.Qop.details->op) {
3319               case Iop_MAddF32:
3320                  op = Mfp_MADDS;
3321                  break;
3322               case Iop_MAddF64:
3323                  op = Mfp_MADDD;
3324                  break;
3325               case Iop_MSubF32:
3326                  op = Mfp_MSUBS;
3327                  break;
3328               case Iop_MSubF64:
3329                  op = Mfp_MSUBD;
3330                  break;
3331               default:
3332                  vassert(0);
3333            }
3334            HReg dst = newVRegF(env);
3335            HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2);
3336            HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3);
3337            HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4);
3338            set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
3339            addInstr(env, MIPSInstr_FpTernary(op, dst,
3340                                              src1, src2, src3));
3341            set_MIPS_rounding_default(env);
3342            return dst;
3343         }
3344
3345         default:
3346         break;
3347      }
3348   }
3349
3350   if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3351      /* This is quite subtle.  The only way to do the relevant
3352         truncation is to do a single-precision store and then a
3353         double precision load to get it back into a register.  The
3354         problem is, if the data is then written to memory a second
3355         time, as in
3356
3357         STbe(...) = TruncF64asF32(...)
3358
3359         then will the second truncation further alter the value?  The
3360         answer is no: flds (as generated here) followed by fsts
3361         (generated for the STbe) is the identity function on 32-bit
3362         floats, so we are safe.
3363
3364         Another upshot of this is that if iselStmt can see the
3365         entirety of
3366
3367         STbe(...) = TruncF64asF32(arg)
3368
3369         then it can short circuit having to deal with TruncF64asF32
3370         individually; instead just compute arg into a 64-bit FP
3371         register and do 'fsts' (since that itself does the
3372         truncation).
3373
3374         We generate pretty poor code here (should be ok both for
3375         32-bit and 64-bit mode); but it is expected that for the most
3376         part the latter optimisation will apply and hence this code
3377         will not often be used.
3378       */
3379      HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
3380      HReg fdst = newVRegF(env);
3381      MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64));
3382
3383      sub_from_sp(env, 16);
3384      /* store as F32, hence truncating */
3385      addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1));
3386      /* and reload.  Good huh?! (sigh) */
3387      addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1));
3388      add_to_sp(env, 16);
3389      return fdst;
3390   }
3391
3392   /* --------- ITE --------- */
3393   if (e->tag == Iex_ITE) {
3394      if (ty == Ity_F64
3395          && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
3396         vassert(mode64);
3397         HReg r0 = iselFltExpr(env, e->Iex.ITE.iffalse);
3398         HReg r1 = iselFltExpr(env, e->Iex.ITE.iftrue);
3399         HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
3400         HReg r_dst = newVRegF(env);
3401         addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0));
3402         addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1,
3403                                            r_cond));
3404         return r_dst;
3405      }
3406   }
3407
3408   vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag);
3409   ppIRExpr(e);
3410   vpanic("iselFltExpr_wrk(mips)");
3411}
3412
3413static HReg iselDblExpr(ISelEnv * env, IRExpr * e)
3414{
3415   HReg r = iselDblExpr_wrk(env, e);
3416   vassert(hregClass(r) == HRcFlt64);
3417   vassert(hregIsVirtual(r));
3418   return r;
3419}
3420
3421/* DO NOT CALL THIS DIRECTLY */
3422static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e)
3423{
3424   IRType ty = typeOfIRExpr(env->type_env, e);
3425   vassert(e);
3426   vassert(ty == Ity_F64);
3427
3428   if (e->tag == Iex_RdTmp) {
3429      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3430   }
3431
3432   /* --------- LOAD --------- */
3433   if (e->tag == Iex_Load) {
3434      HReg r_dst = newVRegD(env);
3435      MIPSAMode *am_addr;
3436      vassert(e->Iex.Load.ty == Ity_F64);
3437      am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
3438      addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
3439      return r_dst;
3440   }
3441
3442   /* --------- GET --------- */
3443   if (e->tag == Iex_Get) {
3444
3445      HReg r_dst = newVRegD(env);
3446      MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
3447                                        GuestStatePointer(mode64));
3448      addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
3449      return r_dst;
3450   }
3451
3452   if (e->tag == Iex_Unop) {
3453      MIPSFpOp fpop = Mfp_INVALID;
3454      switch (e->Iex.Unop.op) {
3455         case Iop_NegF64:
3456            fpop = Mfp_NEGD;
3457            break;
3458         case Iop_AbsF64:
3459            fpop = Mfp_ABSD;
3460            break;
3461         case Iop_F32toF64: {
3462            vassert(!mode64);
3463            HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3464            HReg dst = newVRegD(env);
3465
3466            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
3467            return dst;
3468         }
3469         case Iop_ReinterpI64asF64: {
3470            HReg Hi, Lo;
3471            HReg dst = newVRegD(env);
3472
3473            iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
3474
3475            dst = mk_LoadRR32toFPR(env, Hi, Lo);  /* 2*I32 -> F64 */
3476            return dst;
3477         }
3478         case Iop_I32StoF64: {
3479            vassert(!mode64);
3480            HReg dst = newVRegD(env);
3481            HReg tmp = newVRegF(env);
3482            HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3483
3484            /* Move Word to Floating Point
3485               mtc1 tmp, r_src */
3486            addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
3487
3488            /* and do convert */
3489            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
3490
3491            return dst;
3492         }
3493         default:
3494            break;
3495      }
3496
3497      if (fpop != Mfp_INVALID) {
3498         HReg src = iselDblExpr(env, e->Iex.Unop.arg);
3499         HReg dst = newVRegD(env);
3500         addInstr(env, MIPSInstr_FpUnary(fpop, dst, src));
3501         return dst;
3502      }
3503   }
3504
3505   if (e->tag == Iex_Binop) {
3506      switch (e->Iex.Binop.op) {
3507         case Iop_RoundF64toInt: {
3508            HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3509            HReg dst = newVRegD(env);
3510
3511            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3512            addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src));
3513            set_MIPS_rounding_default(env);
3514
3515            return dst;
3516         }
3517
3518         case Iop_SqrtF64: {
3519            HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3520            HReg dst = newVRegD(env);
3521            set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3522            addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src));
3523            set_MIPS_rounding_default(env);
3524            return dst;
3525         }
3526
3527         default:
3528            break;
3529
3530      }
3531   }
3532
3533   if (e->tag == Iex_Triop) {
3534      switch (e->Iex.Triop.details->op) {
3535         case Iop_DivF64:
3536         case Iop_DivF32:
3537         case Iop_MulF64:
3538         case Iop_AddF64:
3539         case Iop_SubF64: {
3540            MIPSFpOp op = 0;
3541            HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2);
3542            HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3);
3543            HReg dst = newVRegD(env);
3544            switch (e->Iex.Triop.details->op) {
3545               case Iop_DivF64:
3546                  op = Mfp_DIVD;
3547                  break;
3548               case Iop_DivF32:
3549                  op = Mfp_DIVS;
3550                  break;
3551               case Iop_MulF64:
3552                  op = Mfp_MULD;
3553                  break;
3554               case Iop_AddF64:
3555                  op = Mfp_ADDD;
3556                  break;
3557               case Iop_SubF64:
3558                  op = Mfp_SUBD;
3559                  break;
3560               default:
3561                  vassert(0);
3562            }
3563            set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
3564            addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
3565            set_MIPS_rounding_default(env);
3566            return dst;
3567         }
3568         default:
3569            break;
3570      }
3571   }
3572
3573   if (e->tag == Iex_Qop) {
3574      switch (e->Iex.Qop.details->op) {
3575         case Iop_MAddF32:
3576         case Iop_MAddF64:
3577         case Iop_MSubF32:
3578         case Iop_MSubF64: {
3579            MIPSFpOp op = 0;
3580            switch (e->Iex.Qop.details->op) {
3581               case Iop_MAddF32:
3582                  op = Mfp_MADDS;
3583                  break;
3584               case Iop_MAddF64:
3585                  op = Mfp_MADDD;
3586                  break;
3587               case Iop_MSubF32:
3588                  op = Mfp_MSUBS;
3589                  break;
3590               case Iop_MSubF64:
3591                  op = Mfp_MSUBD;
3592                  break;
3593               default:
3594                  vassert(0);
3595            }
3596            HReg dst = newVRegD(env);
3597            HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2);
3598            HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3);
3599            HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4);
3600            set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
3601            addInstr(env, MIPSInstr_FpTernary(op, dst,
3602                                              src1, src2, src3));
3603            set_MIPS_rounding_default(env);
3604            return dst;
3605         }
3606
3607         default:
3608         break;
3609      }
3610   }
3611
3612   /* --------- ITE --------- */
3613   if (e->tag == Iex_ITE) {
3614      if (ty == Ity_F64
3615          && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
3616         HReg r0 = iselDblExpr(env, e->Iex.ITE.iffalse);
3617         HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue);
3618         HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
3619         HReg r_dst = newVRegD(env);
3620
3621         addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0));
3622         addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1,
3623                                            r_cond));
3624         return r_dst;
3625      }
3626   }
3627
3628   vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag);
3629   ppIRExpr(e);
3630   vpanic("iselDblExpr_wrk(mips)");
3631}
3632
3633/*---------------------------------------------------------*/
3634/*--- ISEL: Statements                                  ---*/
3635/*---------------------------------------------------------*/
3636
3637static void iselStmt(ISelEnv * env, IRStmt * stmt)
3638{
3639   if (vex_traceflags & VEX_TRACE_VCODE) {
3640      vex_printf("\n-- ");
3641
3642      ppIRStmt(stmt);
3643      vex_printf("\n");
3644   }
3645
3646   switch (stmt->tag) {
3647      /* --------- STORE --------- */
3648      case Ist_Store: {
3649         MIPSAMode *am_addr;
3650         IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3651
3652         /*constructs addressing mode from address provided */
3653         am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
3654
3655         if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
3656             (mode64 && (tyd == Ity_I64))) {
3657            HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
3658            addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)),
3659                     am_addr, r_src, mode64));
3660            return;
3661         }
3662         if (!mode64 && (tyd == Ity_I64)) {
3663            HReg vHi, vLo;
3664            HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
3665
3666            iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
3667
3668            addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3669                          MIPSAMode_IR(0, r_addr), vHi, mode64));
3670            addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3671                          MIPSAMode_IR(4, r_addr), vLo, mode64));
3672            return;
3673         }
3674         if (tyd == Ity_F32) {
3675            HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3676            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
3677                                           am_addr));
3678            return;
3679         }
3680         if (tyd == Ity_F64 && mode64) {
3681            HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3682            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3683                                           am_addr));
3684            return;
3685         }
3686         if (!mode64 && (tyd == Ity_F64)) {
3687            HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
3688            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3689                                           am_addr));
3690            return;
3691         }
3692
3693         break;
3694      }
3695
3696      /* --------- PUT --------- */
3697      case Ist_Put: {
3698         IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
3699
3700         if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
3701             (ty == Ity_I64 && mode64)) {
3702            HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
3703            MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3704                                              GuestStatePointer(mode64));
3705            addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)),
3706                                          am_addr, r_src, mode64));
3707            return;
3708         }
3709
3710         if (ty == Ity_I64 && !mode64) {
3711            HReg vHi, vLo;
3712            MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3713                                              GuestStatePointer(mode64));
3714            MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4,
3715                                               GuestStatePointer(mode64));
3716            iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
3717            addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3718                                          am_addr, vLo, mode64));
3719            addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3720                                          am_addr4, vHi, mode64));
3721            return;
3722
3723         }
3724
3725         if (ty == Ity_F32) {
3726            HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
3727            MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3728                                              GuestStatePointer(mode64));
3729            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
3730                                           am_addr));
3731            return;
3732         }
3733
3734         if (ty == Ity_F64) {
3735            HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
3736            MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3737                                              GuestStatePointer(mode64));
3738            addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3739                                           am_addr));
3740            return;
3741         }
3742         break;
3743      }
3744
3745      /* --------- TMP --------- */
3746      case Ist_WrTmp: {
3747         IRTemp tmp = stmt->Ist.WrTmp.tmp;
3748         IRType ty = typeOfIRTemp(env->type_env, tmp);
3749
3750         if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) {
3751            HReg r_dst = lookupIRTemp(env, tmp);
3752            HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3753            addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3754            return;
3755         }
3756
3757         if (ty == Ity_I64) {
3758            if (mode64) {
3759               HReg r_dst = lookupIRTemp(env, tmp);
3760               HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3761               addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3762               return;
3763            } else {
3764               HReg rHi, rLo, dstHi, dstLo;
3765               iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
3766               lookupIRTemp64(&dstHi, &dstLo, env, tmp);
3767               addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3768               addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3769               return;
3770            }
3771         }
3772
3773         if (mode64 && ty == Ity_I128) {
3774            HReg rHi, rLo, dstHi, dstLo;
3775            iselInt128Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
3776            lookupIRTempPair(&dstHi, &dstLo, env, tmp);
3777            addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3778            addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3779            return;
3780         }
3781
3782         if (ty == Ity_F32) {
3783            HReg fr_dst = lookupIRTemp(env, tmp);
3784            HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
3785            addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src));
3786            return;
3787         }
3788
3789         if (ty == Ity_F64) {
3790            if (mode64) {
3791               HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
3792               HReg dst = lookupIRTemp(env, tmp);
3793               addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
3794               return;
3795            } else {
3796               HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
3797               HReg dst = lookupIRTemp(env, tmp);
3798               addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
3799               return;
3800            }
3801         }
3802         break;
3803      }
3804
3805      /* --------- Call to DIRTY helper --------- */
3806      case Ist_Dirty: {
3807         IRDirty *d = stmt->Ist.Dirty.details;
3808
3809         /* Figure out the return type, if any. */
3810         IRType retty = Ity_INVALID;
3811         if (d->tmp != IRTemp_INVALID)
3812            retty = typeOfIRTemp(env->type_env, d->tmp);
3813
3814         /* Throw out any return types we don't know about. */
3815         Bool retty_ok = False;
3816         switch (retty) {
3817            case Ity_INVALID: /* Function doesn't return anything. */
3818            case Ity_V128:
3819            case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
3820               retty_ok = True; break;
3821            default:
3822               break;
3823         }
3824
3825         if (!retty_ok)
3826            break; /* will go to stmt_fail: */
3827
3828         /* Marshal args, do the call, clear stack, set the return value
3829            to 0x555..555 if this is a conditional call that returns a
3830            value and the call is skipped. */
3831         UInt   addToSp = 0;
3832         RetLoc rloc    = mk_RetLoc_INVALID();
3833         doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
3834         vassert(is_sane_RetLoc(rloc));
3835
3836         /* Now figure out what to do with the returned value, if any. */
3837         switch (retty) {
3838            case Ity_INVALID: {
3839               /* No return value.  Nothing to do. */
3840               vassert(d->tmp == IRTemp_INVALID);
3841               vassert(rloc.pri == RLPri_None);
3842               vassert(addToSp == 0);
3843               return;
3844            }
3845            case Ity_I32: case Ity_I16: case Ity_I8: {
3846               /* The returned value is in $v0.  Park it in the register
3847                  associated with tmp. */
3848               HReg r_dst = lookupIRTemp(env, d->tmp);
3849               addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
3850               vassert(rloc.pri == RLPri_Int);
3851               vassert(addToSp == 0);
3852               return;
3853            }
3854            case Ity_I64: {
3855               if (mode64) {
3856                  /* The returned value is in $v0.  Park it in the register
3857                     associated with tmp. */
3858                  HReg r_dst = lookupIRTemp(env, d->tmp);
3859                  addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
3860                  vassert(rloc.pri == RLPri_Int);
3861                  vassert(addToSp == 0);
3862                  return;
3863               } else {
3864                  HReg rHi = newVRegI(env);
3865                  HReg rLo = newVRegI(env);
3866                  HReg dstHi, dstLo;
3867                  addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64)));
3868                  addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64)));
3869                  lookupIRTemp64(&dstHi, &dstLo, env, d->tmp);
3870                  addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3871                  addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3872                  return;
3873               }
3874            }
3875            case Ity_V128: {
3876               /* ATC. The code that this produces really
3877                  needs to be looked at, to verify correctness.
3878                  I don't think this can ever happen though, since the
3879                  MIPS front end never produces 128-bit loads/stores. */
3880               vassert(0);
3881               vassert(rloc.pri == RLPri_V128SpRel);
3882               vassert(addToSp >= 16);
3883               HReg       dst = lookupIRTemp(env, d->tmp);
3884               MIPSAMode* am  = MIPSAMode_IR(rloc.spOff, StackPointer(mode64));
3885               addInstr(env, MIPSInstr_Load(mode64 ? 8 : 4, dst, am, mode64));
3886               add_to_sp(env, addToSp);
3887               return;
3888
3889            }
3890            default:
3891               /*NOTREACHED*/
3892               vassert(0);
3893         }
3894      }
3895
3896      /* --------- Load Linked or Store Conditional --------- */
3897      case Ist_LLSC: {
3898         /* Temporary solution; this need to be rewritten again for MIPS.
3899            On MIPS you can not read from address that is locked with LL
3900            before SC. If you read from address that is locked than SC will
3901            fall. */
3902         IRTemp res = stmt->Ist.LLSC.result;
3903         IRType tyRes = typeOfIRTemp(env->type_env, res);
3904         IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
3905
3906         if (!mode64 && (tyAddr != Ity_I32))
3907            goto stmt_fail;
3908
3909         if (stmt->Ist.LLSC.storedata == NULL) {
3910            /* LL */
3911            MIPSAMode *r_addr;
3912            /* constructs addressing mode from address provided */
3913            r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
3914
3915            HReg r_dst = lookupIRTemp(env, res);
3916            if (tyRes == Ity_I32) {
3917               addInstr(env, MIPSInstr_LoadL(4, r_dst, r_addr, mode64));
3918               return;
3919            } else if (tyRes == Ity_I64 && mode64) {
3920               addInstr(env, MIPSInstr_LoadL(8, r_dst, r_addr, mode64));
3921               return;
3922            }
3923         } else {
3924            /* SC */
3925            MIPSAMode *r_addr;
3926            r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
3927            HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
3928            HReg r_dst = lookupIRTemp(env, res);
3929            IRType tyData = typeOfIRExpr(env->type_env,
3930                                         stmt->Ist.LLSC.storedata);
3931
3932            if (tyData == Ity_I32) {
3933               addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3934               addInstr(env, MIPSInstr_StoreC(4, r_addr, r_dst, mode64));
3935               return;
3936            } else if (tyData == Ity_I64 && mode64) {
3937               addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3938               addInstr(env, MIPSInstr_StoreC(8, r_addr, r_dst, mode64));
3939               return;
3940            }
3941         }
3942         goto stmt_fail;
3943       /* NOTREACHED */}
3944
3945   case Ist_CAS:
3946      if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3947         IRCAS *cas = stmt->Ist.CAS.details;
3948         HReg old   = lookupIRTemp(env, cas->oldLo);
3949         HReg addr  = iselWordExpr_R(env, cas->addr);
3950         HReg expd  = iselWordExpr_R(env, cas->expdLo);
3951         HReg data  = iselWordExpr_R(env, cas->dataLo);
3952         if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) {
3953            addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64));
3954         } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3955            addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64));
3956         }
3957      }
3958      return;
3959
3960   /* --------- INSTR MARK --------- */
3961   /* Doesn't generate any executable code ... */
3962   case Ist_IMark:
3963      return;
3964
3965   /* --------- ABI HINT --------- */
3966   /* These have no meaning (denotation in the IR) and so we ignore
3967      them ... if any actually made it this far. */
3968   case Ist_AbiHint:
3969      return;
3970
3971   /* --------- NO-OP --------- */
3972   /* Fairly self-explanatory, wouldn't you say? */
3973   case Ist_NoOp:
3974      return;
3975
3976   /* --------- EXIT --------- */
3977   case Ist_Exit: {
3978      IRConst* dst = stmt->Ist.Exit.dst;
3979      if (!mode64 && dst->tag != Ico_U32)
3980         vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value");
3981      if (mode64 && dst->tag != Ico_U64)
3982         vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value");
3983
3984      MIPSCondCode cc   = iselCondCode(env, stmt->Ist.Exit.guard);
3985      MIPSAMode*   amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP,
3986                                      GuestStatePointer(mode64));
3987
3988      /* Case: boring transfer to known address */
3989      if (stmt->Ist.Exit.jk == Ijk_Boring
3990          || stmt->Ist.Exit.jk == Ijk_Call
3991          /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
3992         if (env->chainingAllowed) {
3993            /* .. almost always true .. */
3994            /* Skip the event check at the dst if this is a forwards
3995               edge. */
3996            Bool toFastEP
3997               = mode64
3998               ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
3999               : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
4000            if (0) vex_printf("%s", toFastEP ? "Y" : ",");
4001            addInstr(env, MIPSInstr_XDirect(
4002                             mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
4003                                    : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
4004                             amPC, cc, toFastEP));
4005         } else {
4006            /* .. very occasionally .. */
4007            /* We can't use chaining, so ask for an assisted transfer,
4008               as that's the only alternative that is allowable. */
4009            HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4010            addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring));
4011         }
4012         return;
4013      }
4014
4015      /* Case: assisted transfer to arbitrary address */
4016      switch (stmt->Ist.Exit.jk) {
4017         /* Keep this list in sync with that in iselNext below */
4018         case Ijk_ClientReq:
4019         case Ijk_EmFail:
4020         case Ijk_EmWarn:
4021         case Ijk_NoDecode:
4022         case Ijk_NoRedir:
4023         case Ijk_SigBUS:
4024         case Ijk_Yield:
4025         case Ijk_SigTRAP:
4026         case Ijk_SigFPE_IntDiv:
4027         case Ijk_SigFPE_IntOvf:
4028         case Ijk_Sys_syscall:
4029         case Ijk_InvalICache:
4030         {
4031            HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4032            addInstr(env, MIPSInstr_XAssisted(r, amPC, cc,
4033                                             stmt->Ist.Exit.jk));
4034            return;
4035         }
4036         default:
4037            break;
4038      }
4039
4040      /* Do we ever expect to see any other kind? */
4041      goto stmt_fail;
4042   }
4043
4044   default:
4045      break;
4046   }
4047
4048   stmt_fail:
4049      vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
4050      ppIRStmt(stmt);
4051      vpanic("iselStmt:\n");
4052}
4053
4054/*---------------------------------------------------------*/
4055/*--- ISEL: Basic block terminators (Nexts)             ---*/
4056/*---------------------------------------------------------*/
4057
4058static void iselNext ( ISelEnv* env,
4059                       IRExpr* next, IRJumpKind jk, Int offsIP )
4060{
4061   if (vex_traceflags & VEX_TRACE_VCODE) {
4062      vex_printf( "\n-- PUT(%d) = ", offsIP);
4063      ppIRExpr( next );
4064      vex_printf( "; exit-");
4065      ppIRJumpKind(jk);
4066      vex_printf( "\n");
4067   }
4068
4069   /* Case: boring transfer to known address */
4070   if (next->tag == Iex_Const) {
4071      IRConst* cdst = next->Iex.Const.con;
4072      vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
4073      if (jk == Ijk_Boring || jk == Ijk_Call) {
4074         /* Boring transfer to known address */
4075         MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
4076         if (env->chainingAllowed) {
4077            /* .. almost always true .. */
4078            /* Skip the event check at the dst if this is a forwards
4079               edge. */
4080            Bool toFastEP
4081               = env->mode64
4082               ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
4083               : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
4084            if (0) vex_printf("%s", toFastEP ? "X" : ".");
4085            addInstr(env, MIPSInstr_XDirect(
4086                             env->mode64 ? (Addr64)cdst->Ico.U64
4087                                         : (Addr64)cdst->Ico.U32,
4088                             amPC, MIPScc_AL, toFastEP));
4089         } else {
4090            /* .. very occasionally .. */
4091            /* We can't use chaining, so ask for an assisted transfer,
4092               as that's the only alternative that is allowable. */
4093            HReg r = iselWordExpr_R(env, next);
4094            addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
4095                                              Ijk_Boring));
4096         }
4097         return;
4098      }
4099   }
4100
4101   /* Case: call/return (==boring) transfer to any address */
4102   switch (jk) {
4103      case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
4104         HReg       r     = iselWordExpr_R(env, next);
4105         MIPSAMode*  amPC = MIPSAMode_IR(offsIP,
4106                                         GuestStatePointer(env->mode64));
4107         if (env->chainingAllowed) {
4108            addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL));
4109         } else {
4110            addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
4111                                              Ijk_Boring));
4112         }
4113         return;
4114      }
4115      default:
4116         break;
4117   }
4118
4119   /* Case: assisted transfer to arbitrary address */
4120   switch (jk) {
4121      /* Keep this list in sync with that for Ist_Exit above */
4122      case Ijk_ClientReq:
4123      case Ijk_EmFail:
4124      case Ijk_EmWarn:
4125      case Ijk_NoDecode:
4126      case Ijk_NoRedir:
4127      case Ijk_SigBUS:
4128      case Ijk_SigILL:
4129      case Ijk_SigTRAP:
4130      case Ijk_SigFPE_IntDiv:
4131      case Ijk_SigFPE_IntOvf:
4132      case Ijk_Sys_syscall:
4133      case Ijk_InvalICache: {
4134         HReg      r     = iselWordExpr_R(env, next);
4135         MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
4136         addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk));
4137         return;
4138      }
4139      default:
4140         break;
4141   }
4142
4143   vex_printf("\n-- PUT(%d) = ", offsIP);
4144   ppIRExpr(next );
4145   vex_printf("; exit-");
4146   ppIRJumpKind(jk);
4147   vex_printf("\n");
4148   vassert(0);  /* are we expecting any other kind? */
4149}
4150
4151/*---------------------------------------------------------*/
4152/*--- Insn selector top-level                           ---*/
4153/*---------------------------------------------------------*/
4154
4155/* Translate an entire BB to mips code. */
4156HInstrArray *iselSB_MIPS ( const IRSB* bb,
4157                           VexArch arch_host,
4158                           const VexArchInfo* archinfo_host,
4159                           const VexAbiInfo* vbi,
4160                           Int offs_Host_EvC_Counter,
4161                           Int offs_Host_EvC_FailAddr,
4162                           Bool chainingAllowed,
4163                           Bool addProfInc,
4164                           Addr max_ga )
4165{
4166   Int      i, j;
4167   HReg     hreg, hregHI;
4168   ISelEnv* env;
4169   UInt     hwcaps_host = archinfo_host->hwcaps;
4170   MIPSAMode *amCounter, *amFailAddr;
4171
4172   /* sanity ... */
4173   vassert(arch_host == VexArchMIPS32 || arch_host == VexArchMIPS64);
4174   vassert(VEX_PRID_COMP_MIPS == hwcaps_host
4175           || VEX_PRID_COMP_BROADCOM == hwcaps_host
4176           || VEX_PRID_COMP_NETLOGIC);
4177
4178   /* Check that the host's endianness is as expected. */
4179   vassert(archinfo_host->endness == VexEndnessLE
4180           || archinfo_host->endness == VexEndnessBE);
4181
4182   mode64 = arch_host != VexArchMIPS32;
4183#if (__mips_fpr==64)
4184   fp_mode64 = ((VEX_MIPS_REV(hwcaps_host) == VEX_PRID_CPU_32FPR)
4185                || arch_host == VexArchMIPS64);
4186#endif
4187
4188   /* Make up an initial environment to use. */
4189   env = LibVEX_Alloc_inline(sizeof(ISelEnv));
4190   env->vreg_ctr = 0;
4191   env->mode64 = mode64;
4192   env->fp_mode64 = fp_mode64;
4193
4194   /* Set up output code array. */
4195   env->code = newHInstrArray();
4196
4197   /* Copy BB's type env. */
4198   env->type_env = bb->tyenv;
4199
4200   /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
4201      change as we go along. */
4202   env->n_vregmap = bb->tyenv->types_used;
4203   env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
4204   env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
4205
4206   /* and finally ... */
4207   env->hwcaps          = hwcaps_host;
4208   env->chainingAllowed = chainingAllowed;
4209   env->hwcaps          = hwcaps_host;
4210   env->max_ga          = max_ga;
4211
4212   /* For each IR temporary, allocate a suitably-kinded virtual
4213      register. */
4214   j = 0;
4215   for (i = 0; i < env->n_vregmap; i++) {
4216      hregHI = hreg = INVALID_HREG;
4217      switch (bb->tyenv->types[i]) {
4218         case Ity_I1:
4219         case Ity_I8:
4220         case Ity_I16:
4221         case Ity_I32:
4222            if (mode64) {
4223               hreg = mkHReg(True, HRcInt64, 0, j++);
4224               break;
4225            } else {
4226               hreg = mkHReg(True, HRcInt32, 0, j++);
4227               break;
4228            }
4229         case Ity_I64:
4230            if (mode64) {
4231               hreg = mkHReg(True, HRcInt64, 0, j++);
4232               break;
4233            } else {
4234               hreg   = mkHReg(True, HRcInt32, 0, j++);
4235               hregHI = mkHReg(True, HRcInt32, 0, j++);
4236               break;
4237            }
4238         case Ity_I128:
4239            vassert(mode64);
4240            hreg   = mkHReg(True, HRcInt64, 0, j++);
4241            hregHI = mkHReg(True, HRcInt64, 0, j++);
4242            break;
4243         case Ity_F32:
4244            if (mode64) {
4245               hreg = mkHReg(True, HRcFlt64, 0, j++);
4246               break;
4247            } else {
4248               hreg = mkHReg(True, HRcFlt32, 0, j++);
4249               break;
4250            }
4251         case Ity_F64:
4252            hreg = mkHReg(True, HRcFlt64, 0, j++);
4253            break;
4254         default:
4255            ppIRType(bb->tyenv->types[i]);
4256            vpanic("iselBB(mips): IRTemp type");
4257            break;
4258      }
4259      env->vregmap[i] = hreg;
4260      env->vregmapHI[i] = hregHI;
4261   }
4262   env->vreg_ctr = j;
4263
4264   /* The very first instruction must be an event check. */
4265   amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, GuestStatePointer(mode64));
4266   amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, GuestStatePointer(mode64));
4267   addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr));
4268
4269   /* Possibly a block counter increment (for profiling).  At this
4270      point we don't know the address of the counter, so just pretend
4271      it is zero.  It will have to be patched later, but before this
4272      translation is used, by a call to LibVEX_patchProfCtr. */
4273   if (addProfInc) {
4274      addInstr(env, MIPSInstr_ProfInc());
4275   }
4276
4277   /* Ok, finally we can iterate over the statements. */
4278   for (i = 0; i < bb->stmts_used; i++)
4279      iselStmt(env, bb->stmts[i]);
4280
4281   iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
4282
4283   /* record the number of vregs we used. */
4284   env->code->n_vregs = env->vreg_ctr;
4285   return env->code;
4286
4287}
4288
4289/*---------------------------------------------------------------*/
4290/*--- end                                    host_mips_isel.c ---*/
4291/*---------------------------------------------------------------*/
4292