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