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