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