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