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