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