• 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-2012 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_mips_defs.h"
39 
40 /*---------------------------------------------------------*/
41 /*--- Register Usage Conventions                        ---*/
42 /*---------------------------------------------------------*/
43 /*
44 
45 Integer Regs
46 ------------
47 ZERO0       Reserved
48 GPR1:9      Allocateable
49 10          GuestStatePointer
50 GPR1:9      Allocateable
51 SP          StackFramePointer
52 RA          LinkRegister
53 
54 */
55 
56 static Bool mode64 = False;
57 
58 /* GPR register class for mips32/64 */
59 #define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32)
60 
61 /* FPR register class for mips32/64 */
62 #define HRcFPR(__mode64) (__mode64 ? HRcFlt64 : HRcFlt32)
63 
64 /*---------------------------------------------------------*/
65 /*--- ISelEnv                                           ---*/
66 /*---------------------------------------------------------*/
67 
68 /* This carries around:
69 
70    - A mapping from IRTemp to IRType, giving the type of any IRTemp we
71      might encounter.  This is computed before insn selection starts,
72      and does not change.
73 
74    - A mapping from IRTemp to HReg.  This tells the insn selector
75      which virtual register(s) are associated with each IRTemp
76      temporary.  This is computed before insn selection starts, and
77      does not change.  We expect this mapping to map precisely the
78      same set of IRTemps as the type mapping does.
79 
80         - vregmap   holds the primary register for the IRTemp.
81         - vregmapHI is only used for 64-bit integer-typed
82              IRTemps.  It holds the identity of a second
83              32-bit virtual HReg, which holds the high half
84              of the value.
85 
86    - The code array, that is, the insns selected so far.
87 
88    - A counter, for generating new virtual registers.
89 
90    - The host subarchitecture we are selecting insns for.
91      This is set at the start and does not change.
92 
93    - A Bool for indicating whether we may generate chain-me
94      instructions for control flow transfers, or whether we must use
95      XAssisted.
96 
97    - The maximum guest address of any guest insn in this block.
98      Actually, the address of the highest-addressed byte from any insn
99      in this block.  Is set at the start and does not change.  This is
100      used for detecting jumps which are definitely forward-edges from
101      this block, and therefore can be made (chained) to the fast entry
102      point of the destination, thereby avoiding the destination's
103      event check.
104 
105    Note, this is all (well, mostly) host-independent.
106 */
107 
108 typedef
109    struct {
110       /* Constant -- are set at the start and do not change. */
111       IRTypeEnv*   type_env;
112 
113       HReg*        vregmap;
114       HReg*        vregmapHI;
115       Int          n_vregmap;
116 
117       UInt         hwcaps;
118       Bool         mode64;
119 
120       Bool         chainingAllowed;
121       Addr64       max_ga;
122 
123       /* These are modified as we go along. */
124       HInstrArray* code;
125       Int          vreg_ctr;
126    }
127    ISelEnv;
128 
lookupIRTemp(ISelEnv * env,IRTemp tmp)129 static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp)
130 {
131    vassert(tmp >= 0);
132    vassert(tmp < env->n_vregmap);
133    return env->vregmap[tmp];
134 }
135 
lookupIRTemp64(HReg * vrHI,HReg * vrLO,ISelEnv * env,IRTemp tmp)136 static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
137 {
138    vassert(tmp >= 0);
139    vassert(tmp < env->n_vregmap);
140    vassert(env->vregmapHI[tmp] != INVALID_HREG);
141    *vrLO = env->vregmap[tmp];
142    *vrHI = env->vregmapHI[tmp];
143 }
144 
145 static void
lookupIRTempPair(HReg * vrHI,HReg * vrLO,ISelEnv * env,IRTemp tmp)146 lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
147 {
148    vassert(env->mode64);
149    vassert(tmp >= 0);
150    vassert(tmp < env->n_vregmap);
151    vassert(env->vregmapHI[tmp] != INVALID_HREG);
152    *vrLO = env->vregmap[tmp];
153    *vrHI = env->vregmapHI[tmp];
154 }
155 
addInstr(ISelEnv * env,MIPSInstr * instr)156 static void addInstr(ISelEnv * env, MIPSInstr * instr)
157 {
158    addHInstr(env->code, instr);
159    if (vex_traceflags & VEX_TRACE_VCODE) {
160       ppMIPSInstr(instr, mode64);
161       vex_printf("\n");
162    }
163 }
164 
newVRegI(ISelEnv * env)165 static HReg newVRegI(ISelEnv * env)
166 {
167    HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64),
168                      True /*virtual reg */ );
169    env->vreg_ctr++;
170    return reg;
171 }
172 
newVRegD(ISelEnv * env)173 static HReg newVRegD(ISelEnv * env)
174 {
175    HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /*virtual reg */ );
176    env->vreg_ctr++;
177    return reg;
178 }
179 
newVRegF(ISelEnv * env)180 static HReg newVRegF(ISelEnv * env)
181 {
182    HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->mode64),
183                      True /*virtual reg */ );
184    env->vreg_ctr++;
185    return reg;
186 }
187 
add_to_sp(ISelEnv * env,UInt n)188 static void add_to_sp(ISelEnv * env, UInt n)
189 {
190    HReg sp = StackPointer(mode64);
191    vassert(n < 256 && (n % 8) == 0);
192    addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True,
193                                                             toUShort(n))));
194 }
195 
sub_from_sp(ISelEnv * env,UInt n)196 static void sub_from_sp(ISelEnv * env, UInt n)
197 {
198    HReg sp = StackPointer(mode64);
199    vassert(n < 256 && (n % 8) == 0);
200    addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp,
201                                MIPSRH_Imm(True, toUShort(n))));
202 }
203 
204 /*---------------------------------------------------------*/
205 /*--- ISEL: Forward declarations                        ---*/
206 /*---------------------------------------------------------*/
207 
208 /* These are organised as iselXXX and iselXXX_wrk pairs.  The
209    iselXXX_wrk do the real work, but are not to be called directly.
210    For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
211    checks that all returned registers are virtual.  You should not
212    call the _wrk version directly.
213 */
214 /* 32-bit mode: Compute an I8/I16/I32 into a RH
215                 (reg-or-halfword-immediate).
216    It's important to specify whether the immediate is to be regarded
217    as signed or not.  If yes, this will never return -32768 as an
218    immediate; this guaranteed that all signed immediates that are
219    return can have their sign inverted if need be.
220 */
221 static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
222 static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
223 
224 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an immediate in
225    the range 1 .. 31 inclusive.  Used for doing shift amounts. */
226 static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
227 static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
228 
229 /* compute an I8/I16/I32 into a GPR*/
230 static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
231 static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
232 
233 /* compute an I32 into an AMode. */
234 static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
235                                          IRType xferTy);
236 static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy);
237 
238 static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
239                               IRExpr * e);
240 static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
241 
242 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
243 static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo,
244                                ISelEnv * env, IRExpr * e);
245 static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
246 
247 static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
248 static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e);
249 
250 static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e);
251 static HReg iselDblExpr(ISelEnv * env, IRExpr * e);
252 
253 static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e);
254 static HReg iselFltExpr(ISelEnv * env, IRExpr * e);
255 
set_MIPS_rounding_mode(ISelEnv * env,IRExpr * mode)256 static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode)
257 {
258    /*
259       rounding mode | MIPS | IR
260       ------------------------
261       to nearest    | 00  | 00
262       to zero       | 01  | 11
263       to +infinity  | 10  | 10
264       to -infinity  | 11  | 01
265     */
266    // rm_MIPS32  = XOR(rm_IR , (rm_IR << 1)) & 2
267    HReg irrm = iselWordExpr_R(env, mode);
268    HReg tmp = newVRegI(env);
269    HReg fcsr_old = newVRegI(env);
270    MIPSAMode *am_addr;
271 
272    addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
273                                 MIPSRH_Imm(False, 1)));
274    addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
275    addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, MIPSRH_Imm(False, 3)));
276    /* save old value of FCSR */
277    addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
278    sub_from_sp(env, 8); // Move SP down 4 bytes
279    am_addr = MIPSAMode_IR(0, StackPointer(mode64));
280 
281    //store old FCSR to stack
282    addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
283 
284    //set new value of FCSR
285    addInstr(env, MIPSInstr_MtFCSR(irrm));
286 }
287 
set_MIPS_rounding_default(ISelEnv * env)288 static void set_MIPS_rounding_default(ISelEnv * env)
289 {
290    HReg fcsr = newVRegI(env);
291    // load as float
292    MIPSAMode *am_addr;
293    am_addr = MIPSAMode_IR(0, StackPointer(mode64));
294 
295    addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64));
296 
297    add_to_sp(env, 8);   // Reset SP
298 
299    //set new value of FCSR
300    addInstr(env, MIPSInstr_MtFCSR(fcsr));
301 }
302 
303 /*---------------------------------------------------------*/
304 /*--- ISEL: Misc helpers                                ---*/
305 /*---------------------------------------------------------*/
306 
307 /* Make an int reg-reg move. */
mk_iMOVds_RR(HReg r_dst,HReg r_src)308 static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src)
309 {
310    vassert(hregClass(r_dst) == hregClass(r_src));
311    vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64);
312    return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src));
313 }
314 
315 /*---------------------------------------------------------*/
316 /*--- ISEL: Function call helpers                       ---*/
317 /*---------------------------------------------------------*/
318 
319 /* Used only in doHelperCall.  See big comment in doHelperCall re
320    handling of register-parameter args.  This function figures out
321    whether evaluation of an expression might require use of a fixed
322    register.  If in doubt return True (safe but suboptimal).
323 */
mightRequireFixedRegs(IRExpr * e)324 static Bool mightRequireFixedRegs(IRExpr * e)
325 {
326    switch (e->tag) {
327       case Iex_RdTmp:
328       case Iex_Const:
329       case Iex_Get:
330          return False;
331       default:
332          return True;
333    }
334 }
335 
336 /* Load 2*I32 regs to fp reg */
mk_LoadRR32toFPR(ISelEnv * env,HReg r_srcHi,HReg r_srcLo)337 static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
338 {
339    HReg fr_dst = newVRegD(env);
340    MIPSAMode *am_addr0, *am_addr1;
341 
342    vassert(hregClass(r_srcHi) == HRcInt32);
343    vassert(hregClass(r_srcLo) == HRcInt32);
344 
345    sub_from_sp(env, 16);   // Move SP down 16 bytes
346    am_addr0 = MIPSAMode_IR(0, StackPointer(mode64));
347    am_addr1 = MIPSAMode_IR(8, StackPointer(mode64));
348 
349    // store hi,lo as Ity_I32's
350    addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64));
351    addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64));
352 
353    // load as float
354    addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0));
355 
356    add_to_sp(env, 16);  // Reset SP
357    return fr_dst;
358 }
359 
360 /* Do a complete function call.  guard is a Ity_Bit expression
361    indicating whether or not the call happens.  If guard==NULL, the
362    call is unconditional. */
363 
doHelperCall(ISelEnv * env,Bool passBBP,IRExpr * guard,IRCallee * cee,IRExpr ** args)364 static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
365                          IRCallee * cee, IRExpr ** args)
366 {
367    MIPSCondCode cc;
368    HReg argregs[MIPS_N_REGPARMS];
369    HReg tmpregs[MIPS_N_REGPARMS];
370    Bool go_fast;
371    Int n_args, i, argreg;
372    UInt argiregs;
373    ULong target;
374    HReg src = 0;
375 
376    /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
377       are allowed to be used for passing integer arguments. They correspond
378       to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
379       on MIPS host (since we only implement one calling convention) and so we
380       always ignore it. */
381 
382    /* MIPS 64 calling convention: up to four registers ($a0 ... $a7)
383       are allowed to be used for passing integer arguments. They correspond
384       to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
385       on MIPS host (since we only implement one calling convention) and so we
386       always ignore it. */
387    n_args = 0;
388    for (i = 0; args[i]; i++)
389       n_args++;
390 
391    if (MIPS_N_REGPARMS < n_args + (passBBP ? 1 : 0)) {
392       vpanic("doHelperCall(MIPS): cannot currently handle > 4 args");
393    }
394    argregs[0] = hregMIPS_GPR4(mode64);
395    argregs[1] = hregMIPS_GPR5(mode64);
396    argregs[2] = hregMIPS_GPR6(mode64);
397    argregs[3] = hregMIPS_GPR7(mode64);
398    argiregs = 0;
399 
400    tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
401 
402    /* First decide which scheme (slow or fast) is to be used.  First
403       assume the fast scheme, and select slow if any contraindications
404       (wow) appear. */
405 
406    go_fast = True;
407 
408    if (guard) {
409       if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
410           && guard->Iex.Const.con->Ico.U1 == True) {
411          /* unconditional */
412       } else {
413          /* Not manifestly unconditional -- be conservative. */
414          go_fast = False;
415       }
416    }
417 
418    if (go_fast) {
419       for (i = 0; i < n_args; i++) {
420          if (mightRequireFixedRegs(args[i])) {
421             go_fast = False;
422             break;
423          }
424       }
425    }
426 
427    /* save GuestStatePointer on the stack */
428    sub_from_sp(env, 8);   // Move SP down 4 bytes
429    addInstr(env, MIPSInstr_Store(4, MIPSAMode_IR(0, StackPointer(mode64)),
430                                     GuestStatePointer(mode64), mode64));
431 
432    /* At this point the scheme to use has been established.  Generate
433       code to get the arg values into the argument rregs. */
434    if (go_fast) {
435       /* FAST SCHEME */
436       argreg = 0;
437       if (passBBP) {
438          argiregs |= (1 << (argreg + 4));
439          addInstr(env, mk_iMOVds_RR(argregs[argreg],
440                   GuestStatePointer(mode64)));
441          argreg++;
442       }
443 
444       for (i = 0; i < n_args; i++) {
445          vassert(argreg < MIPS_N_REGPARMS);
446          vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
447                  || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
448          if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
449             argiregs |= (1 << (argreg + 4));
450             addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env,
451                      args[i])));
452          } else { // Ity_I64
453             vassert(mode64);
454             argiregs |= (1 << (argreg + 4));
455             addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env,
456                      args[i])));
457          }
458          argreg++;
459       }
460       /* Fast scheme only applies for unconditional calls.  Hence: */
461       cc = MIPScc_AL;
462    } else {
463       /* SLOW SCHEME; move via temporaries */
464       argreg = 0;
465       if (passBBP) {
466          /* This is pretty stupid; better to move directly to r3
467             after the rest of the args are done. */
468          tmpregs[argreg] = newVRegI(env);
469          addInstr(env, mk_iMOVds_RR(tmpregs[argreg],
470                   GuestStatePointer(mode64)));
471          argreg++;
472       }
473       for (i = 0; i < n_args; i++) {
474          vassert(argreg < MIPS_N_REGPARMS);
475          vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
476                  || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
477          if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
478             tmpregs[argreg] = iselWordExpr_R(env, args[i]);
479          } else { // Ity_I64
480             vassert(mode64);
481             tmpregs[argreg] = iselWordExpr_R(env, args[i]);
482          }
483          argreg++;
484       }
485 
486       /* Now we can compute the condition.  We can't do it earlier
487          because the argument computations could trash the condition
488          codes.  Be a bit clever to handle the common case where the
489          guard is 1:Bit. */
490       cc = MIPScc_AL;
491       if (guard) {
492          if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
493              && guard->Iex.Const.con->Ico.U1 == True) {
494             /* unconditional -- do nothing */
495          } else {
496             cc = iselCondCode(env, guard);
497             src = iselWordExpr_R(env, guard);
498          }
499       }
500       /* Move the args to their final destinations. */
501       for (i = 0; i < argreg; i++) {
502          if (tmpregs[i] == INVALID_HREG)  // Skip invalid regs
503             continue;
504          /* None of these insns, including any spill code that might
505             be generated, may alter the condition codes. */
506          argiregs |= (1 << (i + 4));
507          addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
508       }
509    }
510 
511    target = toUInt(Ptr_to_ULong(cee->addr));
512 
513    /* Finally, the call itself. */
514    if (mode64)
515       if (cc == MIPScc_AL) {
516          addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs));
517       } else {
518          addInstr(env, MIPSInstr_Call(cc, target, argiregs, src));
519    } else if (cc == MIPScc_AL) {
520       addInstr(env, MIPSInstr_CallAlways(cc, (Addr32) target, argiregs));
521    } else {
522       addInstr(env, MIPSInstr_Call(cc, (Addr32) target, argiregs, src));
523    }
524    /* restore GuestStatePointer */
525    addInstr(env, MIPSInstr_Load(4, GuestStatePointer(mode64),
526             MIPSAMode_IR(0, StackPointer(mode64)), mode64));
527    add_to_sp(env, 8);  // Reset SP
528 }
529 
530 /*---------------------------------------------------------*/
531 /*--- ISEL: Integer expression auxiliaries              ---*/
532 /*---------------------------------------------------------*/
533 
534 /* --------------------- AMODEs --------------------- */
535 
536 /* Return an AMode which computes the value of the specified
537    expression, possibly also adding insns to the code list as a
538    result.  The expression may only be a word-size one.
539 */
540 
uInt_fits_in_16_bits(UInt u)541 static Bool uInt_fits_in_16_bits(UInt u)
542 {
543    Int i = u & 0xFFFF;
544    i <<= 16;
545    i >>= 16;
546    return toBool(u == (UInt) i);
547 }
548 
sane_AMode(ISelEnv * env,MIPSAMode * am)549 static Bool sane_AMode(ISelEnv * env, MIPSAMode * am)
550 {
551    switch (am->tag) {
552       case Mam_IR:
553          return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) &&
554                   hregIsVirtual(am->Mam.IR.base) &&
555                   uInt_fits_in_16_bits(am->Mam.IR.index));
556       case Mam_RR:
557          return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) &&
558                   hregIsVirtual(am->Mam.RR.base) &&
559                   hregClass(am->Mam.RR.index) == HRcGPR(mode64) &&
560                   hregIsVirtual(am->Mam.IR.index));
561       default:
562          vpanic("sane_AMode: unknown mips amode tag");
563    }
564 }
565 
iselWordExpr_AMode(ISelEnv * env,IRExpr * e,IRType xferTy)566 static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy)
567 {
568    MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
569    vassert(sane_AMode(env, am));
570    return am;
571 }
572 
573 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_AMode_wrk(ISelEnv * env,IRExpr * e,IRType xferTy)574 static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
575                 IRType xferTy)
576 {
577    IRType ty = typeOfIRExpr(env->type_env, e);
578    {
579       vassert(ty == Ity_I32);
580 
581       /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
582       if (e->tag == Iex_Binop
583           && e->Iex.Binop.op == Iop_Add32
584           && e->Iex.Binop.arg2->tag == Iex_Const
585           && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
586           && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) {
587          return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
588                               iselWordExpr_R(env, e->Iex.Binop.arg1));
589       }
590 
591       /* Add32(expr,expr) */
592       if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) {
593          HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
594          HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
595 
596          return MIPSAMode_RR(r_idx, r_base);
597       }
598    }
599 
600    /* Doesn't match anything in particular.  Generate it into
601       a register and use that. */
602    return MIPSAMode_IR(0, iselWordExpr_R(env, e));
603 }
604 
605 /*---------------------------------------------------------*/
606 /*--- ISEL: Integer expressions (64/32/16/8 bit)        ---*/
607 /*---------------------------------------------------------*/
608 
609 /* Select insns for an integer-typed expression, and add them to the
610    code list.  Return a reg holding the result.  This reg will be a
611    virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you
612    want to modify it, ask for a new vreg, copy it in there, and modify
613    the copy.  The register allocator will do its best to map both
614    vregs to the same real register, so the copies will often disappear
615    later in the game.
616 
617    This should handle expressions of 64, 32, 16 and 8-bit type.
618    All results are returned in a (mode64 ? 64bit : 32bit) register.
619    For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
620    are arbitrary, so you should mask or sign extend partial values
621    if necessary.
622 */
iselWordExpr_R(ISelEnv * env,IRExpr * e)623 static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e)
624 {
625    HReg r = iselWordExpr_R_wrk(env, e);
626    /* sanity checks ... */
627 
628    vassert(hregClass(r) == HRcGPR(env->mode64));
629    vassert(hregIsVirtual(r));
630    return r;
631 }
632 
633 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_R_wrk(ISelEnv * env,IRExpr * e)634 static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
635 {
636    IRType ty = typeOfIRExpr(env->type_env, e);
637    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1
638            || ty == Ity_F32 || (ty == Ity_I64 && mode64)
639            || (ty == Ity_I128 && mode64));
640 
641    switch (e->tag) {
642       /* --------- TEMP --------- */
643       case Iex_RdTmp:
644          return lookupIRTemp(env, e->Iex.RdTmp.tmp);
645 
646       /* --------- LOAD --------- */
647       case Iex_Load: {
648          HReg r_dst = newVRegI(env);
649          MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
650 
651          if (e->Iex.Load.end != Iend_LE
652              && e->Iex.Load.end != Iend_BE)
653             goto irreducible;
654 
655          addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)),
656                                       r_dst, am_addr, mode64));
657          return r_dst;
658       }
659 
660       /* --------- BINARY OP --------- */
661       case Iex_Binop: {
662          MIPSAluOp aluOp;
663          MIPSShftOp shftOp;
664 
665          /* Is it an addition or logical style op? */
666          switch (e->Iex.Binop.op) {
667             case Iop_Add32:
668                aluOp = Malu_ADD;
669                break;
670 
671             case Iop_Sub8:
672             case Iop_Sub16:
673             case Iop_Sub32:
674                aluOp = Malu_SUB;
675                break;
676 
677             case Iop_And32:
678             case Iop_And64:
679                aluOp = Malu_AND;
680                break;
681 
682             case Iop_Or32:
683             case Iop_Or64:
684                aluOp = Malu_OR;
685                break;
686 
687             case Iop_Xor32:
688             case Iop_Xor64:
689                aluOp = Malu_XOR;
690                break;
691 
692             default:
693                aluOp = Malu_INVALID;
694                break;
695          }
696 
697          /* For commutative ops we assume any literal
698             values are on the second operand. */
699          if (aluOp != Malu_INVALID) {
700             HReg r_dst = newVRegI(env);
701             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
702             MIPSRH *ri_srcR = NULL;
703             /* get right arg into an RH, in the appropriate way */
704             switch (aluOp) {
705                case Malu_ADD:
706                case Malu_SUB:
707                   ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
708                                             e->Iex.Binop.arg2);
709                   break;
710                case Malu_AND:
711                case Malu_OR:
712                case Malu_XOR:
713                   ri_srcR = iselWordExpr_RH(env, False /*unsigned */,
714                                             e->Iex.Binop.arg2);
715                   break;
716                default:
717                   vpanic("iselWordExpr_R_wrk-aluOp-arg2");
718             }
719             addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
720             return r_dst;
721          }
722 
723          /* a shift? */
724          switch (e->Iex.Binop.op) {
725             case Iop_Shl32:
726             case Iop_Shl64:
727                shftOp = Mshft_SLL;
728                break;
729             case Iop_Shr32:
730             case Iop_Shr64:
731                shftOp = Mshft_SRL;
732                break;
733             case Iop_Sar32:
734             case Iop_Sar64:
735                shftOp = Mshft_SRA;
736                break;
737             default:
738                shftOp = Mshft_INVALID;
739                break;
740          }
741 
742          /* we assume any literal values are on the second operand. */
743          if (shftOp != Mshft_INVALID) {
744             HReg r_dst = newVRegI(env);
745             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
746             MIPSRH *ri_srcR = NULL;
747             /* get right arg into an RH, in the appropriate way */
748             switch (shftOp) {
749                case Mshft_SLL:
750                case Mshft_SRL:
751                case Mshft_SRA:
752                   ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop. arg2);
753                   break;
754                default:
755                   vpanic("iselIntExpr_R_wrk-shftOp-arg2");
756             }
757             /* widen the left arg if needed */
758             /*TODO do we need this? */
759             if (ty == Ity_I8 || ty == Ity_I16)
760                goto irreducible;
761             if (ty == Ity_I64) {
762                vassert(mode64);
763                addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */,
764                                             r_dst, r_srcL, ri_srcR));
765             } else {
766                addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
767                                             r_dst, r_srcL, ri_srcR));
768             }
769             return r_dst;
770          }
771 
772          /* Cmp*32*(x,y) ? */
773          if (e->Iex.Binop.op == Iop_CmpEQ32
774              || e->Iex.Binop.op == Iop_CmpNE32
775              || e->Iex.Binop.op == Iop_CmpNE64
776              || e->Iex.Binop.op == Iop_CmpLT32S
777              || e->Iex.Binop.op == Iop_CmpLT32U
778              || e->Iex.Binop.op == Iop_CmpLT64U
779              || e->Iex.Binop.op == Iop_CmpLE32S
780              || e->Iex.Binop.op == Iop_CmpLE64S
781              || e->Iex.Binop.op == Iop_CmpLT64S
782              || e->Iex.Binop.op == Iop_CmpEQ64) {
783 
784             Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
785                          || e->Iex.Binop.op == Iop_CmpLE32S
786                          || e->Iex.Binop.op == Iop_CmpLT64S
787                          || e->Iex.Binop.op == Iop_CmpLE64S);
788             Bool size32;
789             HReg dst = newVRegI(env);
790             HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
791             HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
792 
793             MIPSCondCode cc;
794 
795             switch (e->Iex.Binop.op) {
796                case Iop_CmpEQ32:
797                   cc = MIPScc_EQ;
798                   size32 = True;
799                   break;
800                case Iop_CmpNE32:
801                   cc = MIPScc_NE;
802                   size32 = True;
803                   break;
804                case Iop_CmpNE64:
805                   cc = MIPScc_NE;
806                   size32 = True;
807                   break;
808                case Iop_CmpLT32S:
809                   cc = MIPScc_LT;
810                   size32 = True;
811                   break;
812                case Iop_CmpLT32U:
813                   cc = MIPScc_LO;
814                   size32 = True;
815                   break;
816                case Iop_CmpLT64U:
817                   cc = MIPScc_LO;
818                   size32 = False;
819                   break;
820                case Iop_CmpLE32S:
821                   cc = MIPScc_LE;
822                   size32 = True;
823                   break;
824                case Iop_CmpLE64S:
825                   cc = MIPScc_LE;
826                   size32 = False;
827                   break;
828                case Iop_CmpLT64S:
829                   cc = MIPScc_LT;
830                   size32 = False;
831                   break;
832                case Iop_CmpEQ64:
833                   cc = MIPScc_EQ;
834                   size32 = False;
835                   break;
836                default:
837                   vpanic
838                       ("iselCondCode(mips): CmpXX32 or CmpXX64");
839             }
840 
841             addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
842             return dst;
843          }
844 
845          if (e->Iex.Binop.op == Iop_Max32U) {
846             /*
847                tmp = argR - argL;
848                dst = argL;
849                bltz tmp,2;
850                dst = argR;
851 
852              */
853             HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
854             MIPSRH *argR = iselWordExpr_RH(env, False /*signed */ ,
855                                            e->Iex.Binop.arg2);
856             HReg dst = newVRegI(env);
857             HReg tmp = newVRegI(env);
858             addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, argL, argR));
859             addInstr(env, MIPSInstr_MovCond(dst, argL, argR, tmp, MIPScc_MI));
860 
861             return dst;
862          }
863 
864          if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) {
865             Bool sz32 = (e->Iex.Binop.op == Iop_Mul32);
866             HReg r_dst = newVRegI(env);
867             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
868             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
869             addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ ,
870                                        False /*widen */ ,
871                                        sz32 /*32bit or 64bit */,
872                                        r_dst, r_srcL, r_srcR));
873             return r_dst;
874          }
875 
876          if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) {
877             HReg r_dst = newVRegI(env);
878             HReg tHi = newVRegI(env);
879             HReg tLo = newVRegI(env);
880             HReg tLo_1 = newVRegI(env);
881             HReg tHi_1 = newVRegI(env);
882             HReg mask = newVRegI(env);
883 
884             Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
885             Bool size = toBool(e->Iex.Binop.op == Iop_MullS32)
886                         || toBool(e->Iex.Binop.op == Iop_MullU32);
887             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
888             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
889             addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ ,
890                                         True /*widen */ ,
891                                         size /*32bit or 64bit mul */ ,
892                                         r_dst, r_srcL, r_srcR));
893 
894             addInstr(env, MIPSInstr_Mfhi(tHi));
895             addInstr(env, MIPSInstr_Mflo(tLo));
896 
897             addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1,
898                           tHi, MIPSRH_Imm(False, 32)));
899 
900             addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
901             addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
902                           MIPSRH_Reg(mask)));
903 
904             addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
905                           MIPSRH_Reg(tLo_1)));
906 
907             return r_dst;
908          }
909 
910          if (e->Iex.Binop.op == Iop_CmpF64) {
911             HReg r_srcL, r_srcR;
912             {
913                r_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
914                r_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
915             }
916             HReg tmp = newVRegI(env);
917             HReg r_ccMIPS = newVRegI(env);
918             HReg r_ccIR = newVRegI(env);
919             HReg r_ccIR_b0 = newVRegI(env);
920             HReg r_ccIR_b2 = newVRegI(env);
921             HReg r_ccIR_b6 = newVRegI(env);
922 
923             /* Create in dst, the IRCmpF64Result encoded result. */
924             // chech for EQ
925             addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
926                                               toUChar(2)));
927             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_ccMIPS, tmp,
928                                          MIPSRH_Imm(False, 22)));
929             // chech for UN
930             addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
931                                               toUChar(1)));
932             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
933                                         MIPSRH_Imm(False, 23)));
934             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
935                                         MIPSRH_Reg(tmp)));
936             // chech for LT
937             addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
938                                               toUChar(12)));
939             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp,
940                                          tmp, MIPSRH_Imm(False, 21)));
941             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
942                                         MIPSRH_Reg(tmp)));
943             // chech for GT
944             addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
945                                               toUChar(15)));
946             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
947                                          MIPSRH_Imm(False, 20)));
948 
949             addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp)));
950             addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
951                                         MIPSRH_Imm(False, 8)));
952             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
953                                         MIPSRH_Reg(tmp)));
954             /* Map compare result from PPC to IR,
955                conforming to CmpF64 definition. */
956             /*
957                FP cmp result | MIPS | IR
958                --------------------------
959                UN            | 0x1 | 0x45
960                EQ            | 0x2 | 0x40
961                GT            | 0x4 | 0x00
962                LT            | 0x8 | 0x01
963              */
964 
965             // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
966             addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS,
967                           MIPSRH_Imm(False, 0x3)));
968             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS,
969                           MIPSRH_Reg(r_ccIR_b0)));
970             addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0,
971                           MIPSRH_Imm(False, 0x1)));
972 
973             // r_ccIR_b2 = r_ccPPC[0]
974             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS,
975                           MIPSRH_Imm(False, 0x2)));
976             addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2,
977                           MIPSRH_Imm(False, 0x4)));
978 
979             // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
980             addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6,
981                           r_ccMIPS, MIPSRH_Imm(False, 0x1)));
982             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS,
983                           MIPSRH_Reg(r_ccIR_b6)));
984             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6,
985                           MIPSRH_Imm(False, 0x6)));
986             addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6,
987                           MIPSRH_Imm(False, 0x40)));
988 
989             // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
990             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0,
991                           MIPSRH_Reg(r_ccIR_b2)));
992             addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR,
993                           MIPSRH_Reg(r_ccIR_b6)));
994             return r_ccIR;
995          }
996 
997          if (e->Iex.Binop.op == Iop_DivModU64to32 ||
998              e->Iex.Binop.op == Iop_DivModS64to32) {
999             HReg tLo = newVRegI(env);
1000             HReg tHi = newVRegI(env);
1001             HReg mask = newVRegI(env);
1002             HReg tLo_1 = newVRegI(env);
1003             HReg tHi_1 = newVRegI(env);
1004             HReg r_dst = newVRegI(env);
1005             Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32);
1006 
1007             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1008             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1009 
1010             addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
1011             addInstr(env, MIPSInstr_Mfhi(tHi));
1012             addInstr(env, MIPSInstr_Mflo(tLo));
1013 
1014             addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1015                                          MIPSRH_Imm(False, 32)));
1016 
1017             addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1018             addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1019                           MIPSRH_Reg(mask)));
1020 
1021             addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1022                           MIPSRH_Reg(tLo_1)));
1023 
1024             return r_dst;
1025          }
1026 
1027          if (e->Iex.Binop.op == Iop_32HLto64) {
1028             vassert(mode64);
1029             HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1030             HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1031             HReg tLo_1 = newVRegI(env);
1032             HReg tHi_1 = newVRegI(env);
1033             HReg r_dst = newVRegI(env);
1034             HReg mask = newVRegI(env);
1035 
1036             addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1037                                          MIPSRH_Imm(False, 32)));
1038 
1039             addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1040             addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1041                           MIPSRH_Reg(mask)));
1042             addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1043                           MIPSRH_Reg(tLo_1)));
1044 
1045             return r_dst;
1046          }
1047 
1048          if (e->Iex.Binop.op == Iop_F64toI32S) {
1049             HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
1050             HReg valS = newVRegF(env);
1051             HReg r_dst = newVRegI(env);
1052             MIPSAMode *am_addr;
1053 
1054             set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1055             addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1056             set_MIPS_rounding_default(env);
1057 
1058             sub_from_sp(env, 16);   // Move SP down 16 bytes
1059             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
1060 
1061             // store as F32
1062             addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 4, valS, am_addr));
1063             // load as I32
1064             addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64));
1065 
1066             add_to_sp(env, 16);  // Reset SP
1067 
1068             return r_dst;
1069          }
1070 
1071       break;
1072    }
1073 
1074       /* --------- UNARY OP --------- */
1075    case Iex_Unop: {
1076       IROp op_unop = e->Iex.Unop.op;
1077 
1078       switch (op_unop) {
1079          case Iop_1Sto32:
1080          case Iop_8Sto32:
1081          case Iop_16Sto32:
1082          case Iop_16Sto64:
1083          case Iop_8Sto64:
1084          case Iop_1Sto64: {
1085             HReg r_dst = newVRegI(env);
1086             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1087             Bool sz32;
1088             UShort amt;
1089             switch (op_unop) {
1090                case Iop_1Sto32:
1091                   amt = 31;
1092                   sz32 = True;
1093                   break;
1094                case Iop_16Sto32:
1095                   amt = 16;
1096                   sz32 = True;
1097                   break;
1098                case Iop_16Sto64:
1099                   amt = 48;
1100                   sz32 = False;
1101                   break;
1102                case Iop_8Sto32:
1103                   amt = 24;
1104                   sz32 = True;
1105                   break;
1106                case Iop_8Sto64:
1107                   amt = 56;
1108                   sz32 = False;
1109                   break;
1110                case Iop_1Sto64:
1111                   amt = 63;
1112                   sz32 = False;
1113                   break;
1114                default:
1115                   vassert(0);
1116             }
1117 
1118             addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src,
1119                                          MIPSRH_Imm(False, amt)));
1120             addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst,
1121                                          MIPSRH_Imm(False, amt)));
1122             return r_dst;
1123          }
1124 
1125          /*not(x) = nor(x,x) */
1126          case Iop_Not1: {
1127             HReg r_dst = newVRegI(env);
1128             HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1129             MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1130 
1131             addInstr(env, MIPSInstr_LI(r_dst, 0x1));
1132             addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
1133             return r_dst;
1134          }
1135 
1136          case Iop_Not32:
1137          case Iop_Not64: {
1138             HReg r_dst = newVRegI(env);
1139             HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1140             MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1141 
1142             addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR));
1143             return r_dst;
1144          }
1145 
1146          case Iop_ReinterpF32asI32: {
1147             MIPSAMode *am_addr;
1148             HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1149             HReg r_dst = newVRegI(env);
1150 
1151             sub_from_sp(env, 16);   // Move SP down 16 bytes
1152             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
1153 
1154             // store as F32
1155             addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 4, fr_src,
1156                                            am_addr));
1157             // load as Ity_I32
1158             addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64));
1159 
1160             add_to_sp(env, 16);  // Reset SP
1161             return r_dst;
1162          }
1163 
1164          case Iop_ReinterpF64asI64: {
1165             vassert(mode64);
1166             MIPSAMode *am_addr;
1167             HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1168             HReg r_dst = newVRegI(env);
1169 
1170             sub_from_sp(env, 16);   // Move SP down 16 bytes
1171             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
1172 
1173             // store as F64
1174             addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 8, fr_src,
1175                                            am_addr));
1176             // load as Ity_I64
1177             addInstr(env, MIPSInstr_Load(8, r_dst, am_addr, mode64));
1178 
1179             add_to_sp(env, 16);  // Reset SP
1180             return r_dst;
1181          }
1182 
1183          case Iop_32to8:
1184          case Iop_32to16:
1185             return iselWordExpr_R(env, e->Iex.Unop.arg);
1186 
1187          case Iop_64to8: {
1188             vassert(mode64);
1189             HReg r_src, r_dst;
1190             r_dst = newVRegI(env);
1191             r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1192             addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1193                           MIPSRH_Imm(False, 0xFF)));
1194             return r_dst;
1195          }
1196 
1197          case Iop_16Uto32:
1198          case Iop_8Uto32:
1199          case Iop_1Uto32: {
1200             HReg r_dst = newVRegI(env);
1201             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1202             UShort amt;
1203             switch (op_unop) {
1204                case Iop_1Uto32:
1205                case Iop_1Uto8:
1206                   amt = 31;
1207                   break;
1208 
1209                case Iop_16Uto32:
1210                   amt = 16;
1211                   break;
1212 
1213                default:
1214                   amt = 24;
1215                   break;
1216             }
1217 
1218             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_dst, r_src,
1219                           MIPSRH_Imm(False, amt)));
1220             addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_dst, r_dst,
1221                           MIPSRH_Imm(False, amt)));
1222             return r_dst;
1223          }
1224 
1225          case Iop_8Uto16:
1226          case Iop_8Uto64:
1227          case Iop_16Uto64: {
1228             vassert(mode64);
1229             HReg r_dst = newVRegI(env);
1230             HReg r_src = iselWordExpr_R(env,  e->Iex.Unop.arg);
1231             UShort mask = toUShort(op_unop == Iop_16Uto64 ? 0xFFFF :
1232                                    op_unop == Iop_16Uto32 ? 0xFFFF : 0xFF);
1233             addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1234                           MIPSRH_Imm(False, mask)));
1235             return r_dst;
1236          }
1237 
1238          case Iop_32Uto64: {
1239             HReg r_dst = newVRegI(env);
1240             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1241             vassert(mode64);
1242             addInstr(env, MIPSInstr_Shft(Mshft_SLL, False/*!32bit shift */,
1243                                          r_dst, r_src, MIPSRH_Imm(False, 32)));
1244             addInstr(env, MIPSInstr_Shft(Mshft_SRL, False/*!32bit shift */,
1245                                          r_dst, r_dst, MIPSRH_Imm(False, 32)));
1246             return r_dst;
1247          }
1248 
1249          case Iop_1Uto64:
1250             vassert(mode64);
1251             return iselWordExpr_R(env, e->Iex.Unop.arg);
1252 
1253          case Iop_64HIto32: {
1254             HReg rHi, rLo;
1255             iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1256             return rHi;
1257          }
1258 
1259          case Iop_64to32: {
1260             HReg rHi, rLo;
1261             iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1262             return rLo;
1263          }
1264 
1265          case Iop_64to16: {
1266             vassert(env->mode64);
1267             HReg r_dst = newVRegI(env);
1268             r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1269             return r_dst;
1270          }
1271 
1272          case Iop_32Sto64: {
1273             HReg r_dst = newVRegI(env);
1274             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1275             vassert(mode64);
1276             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True/*!32bit shift */,
1277                                          r_dst, r_src, MIPSRH_Imm(True, 0)));
1278             return r_dst;
1279          }
1280 
1281          case Iop_CmpNEZ8: {
1282             HReg r_dst = newVRegI(env);
1283             HReg tmp = newVRegI(env);
1284             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1285 
1286             MIPSCondCode cc;
1287 
1288             cc = MIPScc_NE;
1289             addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src,
1290                                         MIPSRH_Imm(False, 0xFF)));
1291             addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp,
1292                                         hregMIPS_GPR0(mode64), cc));
1293             return r_dst;
1294          }
1295 
1296          case Iop_CmpNEZ32: {
1297             HReg r_dst = newVRegI(env);
1298             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1299 
1300             MIPSCondCode cc;
1301 
1302             cc = MIPScc_NE;
1303 
1304             addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src,
1305                                         hregMIPS_GPR0(mode64), cc));
1306             return r_dst;
1307          }
1308 
1309          case Iop_CmpwNEZ32: {
1310             HReg r_dst = newVRegI(env);
1311             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1312 
1313             addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
1314                           MIPSRH_Reg(r_src)));
1315 
1316             addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1317                                         MIPSRH_Reg(r_src)));
1318             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst,
1319                                          MIPSRH_Imm(False, 31)));
1320             return r_dst;
1321          }
1322 
1323          case Iop_Left8:
1324          case Iop_Left32:
1325          case Iop_Left64: {
1326             if (op_unop == Iop_Left64 && !mode64)
1327                goto irreducible;
1328             HReg r_dst = newVRegI(env);
1329             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1330             addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
1331                           MIPSRH_Reg(r_src)));
1332             addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1333                           MIPSRH_Reg(r_src)));
1334             return r_dst;
1335          }
1336 
1337          case Iop_Clz32: {
1338             HReg r_dst = newVRegI(env);
1339             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1340             addInstr(env, MIPSInstr_Unary(Mun_CLZ, r_dst, r_src));
1341             return r_dst;
1342          }
1343 
1344          case Iop_CmpNEZ64: {
1345             HReg hi, lo;
1346             HReg r_dst = newVRegI(env);
1347             HReg r_src;
1348             r_src = newVRegI(env);
1349             iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg);
1350             addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi)));
1351             MIPSCondCode cc;
1352 
1353             cc = MIPScc_NE;
1354 
1355             addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src,
1356                                         hregMIPS_GPR0(mode64), cc));
1357             return r_dst;
1358          }
1359 
1360          case Iop_CmpwNEZ64: {
1361             HReg tmp1;
1362             HReg tmp2 = newVRegI(env);
1363             vassert(env->mode64);
1364             tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
1365 
1366             addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
1367                           MIPSRH_Reg(tmp1)));
1368 
1369             addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
1370             addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2,
1371                                          MIPSRH_Imm (False, 63)));
1372             return tmp2;
1373          }
1374 
1375          case Iop_128HIto64: {
1376             vassert(mode64);
1377             HReg rHi, rLo;
1378             iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1379             return rHi; /* and abandon rLo .. poor wee thing :-) */
1380          }
1381 
1382          case Iop_128to64: {
1383             vassert(mode64);
1384             HReg rHi, rLo;
1385             iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1386             return rLo; /* and abandon rLo .. poor wee thing :-) */
1387          }
1388 
1389          default:
1390             break;
1391       }
1392       break;
1393    }
1394 
1395       /* --------- GET --------- */
1396    case Iex_Get: {
1397       if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
1398           || ((ty == Ity_I64) && mode64)) {
1399          HReg r_dst = newVRegI(env);
1400 
1401          MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
1402                                            GuestStatePointer(mode64));
1403          addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr,
1404                                       mode64));
1405          return r_dst;
1406       }
1407       break;
1408    }
1409 
1410       /* --------- MULTIPLEX --------- */
1411    case Iex_Mux0X: {
1412       if ((ty == Ity_I8 || ty == Ity_I16 ||
1413            ty == Ity_I32 || ((ty == Ity_I64))) &&
1414            typeOfIRExpr(env->type_env, e->Iex.Mux0X.cond) == Ity_I8) {
1415          /*
1416           * r_dst = cond && rX
1417           * cond = not(cond)
1418           * tmp = cond && r0
1419           * r_dst = tmp + r_dst
1420           */
1421          HReg r0 = iselWordExpr_R(env, e->Iex.Mux0X.expr0);
1422          HReg rX = iselWordExpr_R(env, e->Iex.Mux0X.exprX);
1423          HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
1424          HReg r_dst = newVRegI(env);
1425          HReg r_tmp = newVRegI(env);
1426          HReg r_tmp1 = newVRegI(env);
1427          HReg r_cond_neg = newVRegI(env);
1428 
1429          addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp, r_cond, MIPSRH_Reg(rX)));
1430          addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond,
1431                        MIPSRH_Reg(r_cond)));
1432          addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1, r_cond_neg,
1433                        MIPSRH_Reg(r0)));
1434          addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst, r_tmp,
1435                        MIPSRH_Reg(r_tmp1)));
1436 
1437          return r_dst;
1438       }
1439       break;
1440    }
1441 
1442       /* --------- LITERAL --------- */
1443       /* 32/16/8-bit literals */
1444    case Iex_Const: {
1445       Long l;
1446       HReg r_dst = newVRegI(env);
1447       IRConst *con = e->Iex.Const.con;
1448       switch (con->tag) {
1449          case Ico_U64:
1450             if (!mode64)
1451                goto irreducible;
1452             l = (Long) con->Ico.U64;
1453             break;
1454          case Ico_U32:
1455             l = (Long) (Int) con->Ico.U32;
1456             break;
1457          case Ico_U16:
1458             l = (Long) (Int) (Short) con->Ico.U16;
1459             break;
1460          case Ico_U8:
1461             l = (Long) (Int) (Char) con->Ico.U8;
1462             break;
1463          default:
1464             vpanic("iselIntExpr_R.const(mips)");
1465       }
1466       addInstr(env, MIPSInstr_LI(r_dst, (ULong) l));
1467       return r_dst;
1468    }
1469 
1470       /* --------- CCALL --------- */
1471    case Iex_CCall: {
1472       HReg r_dst = newVRegI(env);
1473       vassert(ty == e->Iex.CCall.retty);
1474 
1475       /* be very restrictive for now.  Only 32/64-bit ints allowed
1476          for args, and 32 bits for return type. */
1477       if (e->Iex.CCall.retty != Ity_I32 && !mode64)
1478          goto irreducible;
1479 
1480       /* Marshal args, do the call, clear stack. */
1481       doHelperCall(env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args);
1482       addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
1483       return r_dst;
1484    }
1485 
1486    default:
1487       break;
1488    }        /* end switch(e->tag) */
1489 
1490    /* We get here if no pattern matched. */
1491    irreducible:
1492       vex_printf("--------------->\n");
1493       if (e->tag == Iex_RdTmp)
1494          vex_printf("Iex_RdTmp \n");
1495       ppIRExpr(e);
1496 
1497       vpanic("iselWordExpr_R(mips): cannot reduce tree");
1498 }
1499 
1500 /* --------------------- RH --------------------- */
1501 
1502 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
1503    (reg-or-halfword-immediate).  It's important to specify whether the
1504    immediate is to be regarded as signed or not.  If yes, this will
1505    never return -32768 as an immediate; this guaranteed that all
1506    signed immediates that are return can have their sign inverted if
1507    need be. */
1508 
iselWordExpr_RH(ISelEnv * env,Bool syned,IRExpr * e)1509 static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e)
1510 {
1511    MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e);
1512    /* sanity checks ... */
1513    switch (ri->tag) {
1514       case Mrh_Imm:
1515          vassert(ri->Mrh.Imm.syned == syned);
1516          if (syned)
1517             vassert(ri->Mrh.Imm.imm16 != 0x8000);
1518          return ri;
1519       case Mrh_Reg:
1520          vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
1521          vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1522          return ri;
1523       default:
1524          vpanic("iselIntExpr_RH: unknown mips RH tag");
1525    }
1526 }
1527 
1528 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH_wrk(ISelEnv * env,Bool syned,IRExpr * e)1529 static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e)
1530 {
1531    ULong u;
1532    Long l;
1533    IRType ty = typeOfIRExpr(env->type_env, e);
1534    vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1535           ((ty == Ity_I64) && env->mode64));
1536 
1537    /* special case: immediate */
1538    if (e->tag == Iex_Const) {
1539       IRConst *con = e->Iex.Const.con;
1540       /* What value are we aiming to generate? */
1541       switch (con->tag) {
1542          /* Note: Not sign-extending - we carry 'syned' around */
1543          case Ico_U64:
1544             vassert(env->mode64);
1545             u = con->Ico.U64;
1546             break;
1547          case Ico_U32:
1548             u = 0xFFFFFFFF & con->Ico.U32;
1549             break;
1550          case Ico_U16:
1551             u = 0x0000FFFF & con->Ico.U16;
1552             break;
1553          case Ico_U8:
1554             u = 0x000000FF & con->Ico.U8;
1555             break;
1556          default:
1557             vpanic("iselIntExpr_RH.Iex_Const(mips)");
1558       }
1559       l = (Long) u;
1560       /* Now figure out if it's representable. */
1561       if (!syned && u <= 65535) {
1562          return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
1563       }
1564       if (syned && l >= -32767 && l <= 32767) {
1565          return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
1566       }
1567       /* no luck; use the Slow Way. */
1568    }
1569    /* default case: calculate into a register and return that */
1570    return MIPSRH_Reg(iselWordExpr_R(env, e));
1571 }
1572 
1573 /* --------------------- RH5u --------------------- */
1574 
1575 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
1576    being an immediate in the range 1 .. 31 inclusive.  Used for doing
1577    shift amounts. */
1578 
iselWordExpr_RH5u(ISelEnv * env,IRExpr * e)1579 static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e)
1580 {
1581    MIPSRH *ri;
1582    ri = iselWordExpr_RH5u_wrk(env, e);
1583    /* sanity checks ... */
1584    switch (ri->tag) {
1585       case Mrh_Imm:
1586          vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31);
1587          vassert(!ri->Mrh.Imm.syned);
1588          return ri;
1589       case Mrh_Reg:
1590          vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32);
1591          vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1592          return ri;
1593       default:
1594          vpanic("iselIntExpr_RH5u: unknown mips RH tag");
1595    }
1596 }
1597 
1598 /* DO NOT CALL THIS DIRECTLY ! */
iselWordExpr_RH5u_wrk(ISelEnv * env,IRExpr * e)1599 static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e)
1600 {
1601    IRType ty = typeOfIRExpr(env->type_env, e);
1602    vassert(ty == Ity_I8);
1603 
1604    /* special case: immediate */
1605    if (e->tag == Iex_Const
1606        && e->Iex.Const.con->tag == Ico_U8
1607        && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) {
1608       return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
1609    }
1610 
1611    /* default case: calculate into a register and return that */
1612    return MIPSRH_Reg(iselWordExpr_R(env, e));
1613 }
1614 
1615 /* --------------------- CONDCODE --------------------- */
1616 
1617 /* Generate code to evaluated a bit-typed expression, returning the
1618    condition code which would correspond when the expression would
1619    notionally have returned 1. */
1620 
iselCondCode(ISelEnv * env,IRExpr * e)1621 static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e)
1622 {
1623    MIPSCondCode cc = iselCondCode_wrk(env,e);
1624    vassert(cc != MIPScc_NV);
1625    return cc;
1626 }
1627 
1628 /* DO NOT CALL THIS DIRECTLY ! */
iselCondCode_wrk(ISelEnv * env,IRExpr * e)1629 static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
1630 {
1631    vassert(e);
1632    vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
1633    /* Cmp*32*(x,y) ? */
1634    if (e->Iex.Binop.op == Iop_CmpEQ32
1635        || e->Iex.Binop.op == Iop_CmpNE32
1636        || e->Iex.Binop.op == Iop_CmpNE64
1637        || e->Iex.Binop.op == Iop_CmpLT32S
1638        || e->Iex.Binop.op == Iop_CmpLT32U
1639        || e->Iex.Binop.op == Iop_CmpLT64U
1640        || e->Iex.Binop.op == Iop_CmpLE32S
1641        || e->Iex.Binop.op == Iop_CmpLE64S
1642        || e->Iex.Binop.op == Iop_CmpLT64S
1643        || e->Iex.Binop.op == Iop_CmpEQ64) {
1644 
1645       Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
1646                    || e->Iex.Binop.op == Iop_CmpLE32S
1647                    || e->Iex.Binop.op == Iop_CmpLT64S
1648                    || e->Iex.Binop.op == Iop_CmpLE64S);
1649       Bool size32;
1650       HReg dst = newVRegI(env);
1651       HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
1652       HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
1653 
1654       MIPSCondCode cc;
1655 
1656       switch (e->Iex.Binop.op) {
1657          case Iop_CmpEQ32:
1658             cc = MIPScc_EQ;
1659             size32 = True;
1660             break;
1661          case Iop_CmpNE32:
1662             cc = MIPScc_NE;
1663             size32 = True;
1664             break;
1665          case Iop_CmpNE64:
1666             cc = MIPScc_NE;
1667             size32 = True;
1668             break;
1669          case Iop_CmpLT32S:
1670             cc = MIPScc_LT;
1671             size32 = True;
1672             break;
1673          case Iop_CmpLT32U:
1674             cc = MIPScc_LO;
1675             size32 = True;
1676             break;
1677          case Iop_CmpLT64U:
1678             cc = MIPScc_LO;
1679             size32 = False;
1680             break;
1681          case Iop_CmpLE32S:
1682             cc = MIPScc_LE;
1683             size32 = True;
1684             break;
1685          case Iop_CmpLE64S:
1686             cc = MIPScc_LE;
1687             size32 = False;
1688             break;
1689          case Iop_CmpLT64S:
1690             cc = MIPScc_LT;
1691             size32 = False;
1692             break;
1693          case Iop_CmpEQ64:
1694             cc = MIPScc_EQ;
1695             size32 = False;
1696             break;
1697          default:
1698             vpanic
1699                 ("iselCondCode(mips): CmpXX32 or CmpXX64");
1700       }
1701 
1702       addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
1703       // Store result to guest_COND
1704       MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
1705 
1706       addInstr(env, MIPSInstr_Store(4,
1707                MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base),
1708                dst, mode64));
1709       return cc;
1710    }
1711    if (e->Iex.Binop.op == Iop_Not1) {
1712       HReg r_dst = newVRegI(env);
1713       HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1714       MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1715 
1716       addInstr(env, MIPSInstr_LI(r_dst, 0x1));
1717       addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
1718       // Store result to guest_COND
1719       MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
1720 
1721       addInstr(env, MIPSInstr_Store(4,
1722                MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base),
1723                r_dst, mode64));
1724       return MIPScc_NE;
1725    }
1726    if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) {
1727       HReg r_dst = iselWordExpr_R_wrk(env, e);
1728       // Store result to guest_COND
1729       MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
1730 
1731       addInstr(env, MIPSInstr_Store(4,
1732                MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base),
1733                r_dst, mode64));
1734       return MIPScc_EQ;
1735    }
1736 
1737    vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag);
1738    ppIRExpr(e);
1739    vpanic("iselCondCode(mips)");
1740 }
1741 
1742 /*---------------------------------------------------------*/
1743 /*--- ISEL: Integer expressions (128 bit)               ---*/
1744 /*---------------------------------------------------------*/
1745 
1746 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
1747    which is returned as the first two parameters.  As with
1748    iselWordExpr_R, these may be either real or virtual regs; in any
1749    case they must not be changed by subsequent code emitted by the
1750    caller.  */
1751 
iselInt128Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e)1752 static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
1753 {
1754    vassert(env->mode64);
1755    iselInt128Expr_wrk(rHi, rLo, env, e);
1756 #  if 0
1757    vex_printf("\n");
1758    ppIRExpr(e);
1759    vex_printf("\n");
1760 #  endif
1761    vassert(hregClass(*rHi) == HRcGPR(env->mode64));
1762    vassert(hregIsVirtual(*rHi));
1763    vassert(hregClass(*rLo) == HRcGPR(env->mode64));
1764    vassert(hregIsVirtual(*rLo));
1765 }
1766 
1767 /* DO NOT CALL THIS DIRECTLY ! */
iselInt128Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e)1768 static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
1769                                IRExpr * e)
1770 {
1771    vassert(e);
1772    vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
1773 
1774    /* read 128-bit IRTemp */
1775    if (e->tag == Iex_RdTmp) {
1776       lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
1777       return;
1778    }
1779 
1780    /* --------- BINARY ops --------- */
1781    if (e->tag == Iex_Binop) {
1782       switch (e->Iex.Binop.op) {
1783          /* 64 x 64 -> 128 multiply */
1784          case Iop_MullU64:
1785          case Iop_MullS64:
1786             {
1787                HReg tLo = newVRegI(env);
1788                HReg tHi = newVRegI(env);
1789                Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
1790                HReg r_dst = newVRegI(env);
1791                HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1792                HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1793                addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ ,
1794                                            r_dst, r_srcL, r_srcR));
1795                addInstr(env, MIPSInstr_Mfhi(tHi));
1796                addInstr(env, MIPSInstr_Mflo(tLo));
1797                *rHi = tHi;
1798                *rLo = tLo;
1799                return;
1800             }
1801 
1802          /* 64HLto128(e1,e2) */
1803          case Iop_64HLto128:
1804             *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1805             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1806             return;
1807 
1808          case Iop_DivModS64to64: {
1809             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1810             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1811             HReg tLo = newVRegI(env);
1812             HReg tHi = newVRegI(env);
1813             Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
1814 
1815             addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
1816             addInstr(env, MIPSInstr_Mfhi(tHi));
1817             addInstr(env, MIPSInstr_Mflo(tLo));
1818             *rHi = tHi;
1819             *rLo = tLo;
1820             return;
1821          }
1822 
1823          case Iop_DivModU128to64: {
1824             vassert(mode64);
1825             HReg rHi1, rLo1;
1826             iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1);
1827 
1828             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1829             HReg tLo = newVRegI(env);
1830             HReg tHi = newVRegI(env);
1831             Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64);
1832 
1833             addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR));
1834             addInstr(env, MIPSInstr_Mfhi(tHi));
1835             addInstr(env, MIPSInstr_Mflo(tLo));
1836             *rHi = tHi;
1837             *rLo = tLo;
1838             return;
1839          }
1840 
1841          default:
1842             break;
1843       }
1844    }
1845    vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag);
1846    ppIRExpr(e);
1847    vpanic("iselInt128Expr(mips64)");
1848 }
1849 
1850 /*---------------------------------------------------------*/
1851 /*--- ISEL: Integer expressions (64 bit)                ---*/
1852 /*---------------------------------------------------------*/
1853 
1854 /* 32-bit mode ONLY. Compute a 64-bit value into the register
1855  * pair HI, LO. HI and LO must not be changed by subsequent
1856  *  code emitted by the caller. */
1857 
iselInt64Expr(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e)1858 static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
1859 {
1860    vassert(!env->mode64);
1861    iselInt64Expr_wrk(rHi, rLo, env, e);
1862    vassert(hregClass(*rHi) == HRcInt32);
1863    vassert(hregIsVirtual(*rHi));
1864    vassert(hregClass(*rLo) == HRcInt32);
1865    vassert(hregIsVirtual(*rLo));
1866 }
1867 
1868 /* DO NOT CALL THIS DIRECTLY ! */
iselInt64Expr_wrk(HReg * rHi,HReg * rLo,ISelEnv * env,IRExpr * e)1869 static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
1870 {
1871    vassert(e);
1872    vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
1873 
1874    /* read 64-bit IRTemp */
1875    if (e->tag == Iex_RdTmp) {
1876       lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp);
1877       return;
1878    }
1879    /* 64-bit load */
1880    if (e->tag == Iex_Load) {
1881       HReg tLo = newVRegI(env);
1882       HReg tHi = newVRegI(env);
1883       HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
1884       addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64));
1885       addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64));
1886       *rHi = tHi;
1887       *rLo = tLo;
1888       return;
1889    }
1890 
1891    /* 64-bit literal */
1892    if (e->tag == Iex_Const) {
1893       ULong w64 = e->Iex.Const.con->Ico.U64;
1894       UInt wHi = toUInt(w64 >> 32);
1895       UInt wLo = toUInt(w64);
1896       HReg tLo = newVRegI(env);
1897       HReg tHi = newVRegI(env);
1898       vassert(e->Iex.Const.con->tag == Ico_U64);
1899 
1900       if (wLo == wHi) {
1901          /* Save a precious Int register in this special case. */
1902          addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
1903          *rHi = tLo;
1904          *rLo = tLo;
1905       } else {
1906          addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi));
1907          addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
1908          *rHi = tHi;
1909          *rLo = tLo;
1910       }
1911 
1912       return;
1913    }
1914 
1915    /* 64-bit GET */
1916    if (e->tag == Iex_Get) {
1917       HReg tLo = newVRegI(env);
1918       HReg tHi = newVRegI(env);
1919 
1920       MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
1921                                         GuestStatePointer(mode64));
1922       addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
1923       addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64));
1924       *rHi = tHi;
1925       *rLo = tLo;
1926       return;
1927    }
1928 
1929    /* 64-bit Mux0X */
1930    if (e->tag == Iex_Mux0X) {
1931       HReg expr0Lo, expr0Hi;
1932       HReg exprXLo, exprXHi;
1933       HReg tmpHi = newVRegI(env);
1934       HReg tmpLo = newVRegI(env);
1935       HReg tmp1Hi = newVRegI(env);
1936       HReg tmp1Lo = newVRegI(env);
1937       HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
1938       HReg r_cond_neg = newVRegI(env);
1939       HReg desLo = newVRegI(env);
1940       HReg desHi = newVRegI(env);
1941 
1942       /* expr0Hi:expr0Lo = expr0 */
1943       /* exprXHi:exprXLo = exprX */
1944       iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.Mux0X.expr0);
1945       iselInt64Expr(&exprXHi, &exprXLo, env, e->Iex.Mux0X.exprX);
1946 
1947       addInstr(env, MIPSInstr_Alu(Malu_AND, tmpLo, r_cond,
1948                                   MIPSRH_Reg(exprXLo)));
1949       addInstr(env, MIPSInstr_Alu(Malu_AND, tmpHi, r_cond,
1950                                   MIPSRH_Reg(exprXHi)));
1951       addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond,
1952                                   MIPSRH_Reg(r_cond)));
1953       addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Lo, r_cond_neg,
1954                                   MIPSRH_Reg(exprXLo)));
1955       addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Hi, r_cond_neg,
1956                                   MIPSRH_Reg(exprXHi)));
1957       addInstr(env, MIPSInstr_Alu(Malu_ADD, desLo, tmpLo,
1958                                   MIPSRH_Reg(tmp1Lo)));
1959       addInstr(env, MIPSInstr_Alu(Malu_ADD, desHi, tmpHi,
1960                                   MIPSRH_Reg(tmp1Hi)));
1961       *rHi = desHi;
1962       *rLo = desLo;
1963       return;
1964    }
1965 
1966    /* --------- BINARY ops --------- */
1967    if (e->tag == Iex_Binop) {
1968       IROp op_binop = e->Iex.Binop.op;
1969       switch (op_binop) {
1970          /* 32 x 32 -> 64 multiply */
1971          /* Add64 */
1972          case Iop_Add64: {
1973             HReg xLo, xHi, yLo, yHi;
1974             HReg tHi = newVRegI(env);
1975             HReg tLo = newVRegI(env);
1976             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
1977             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
1978             addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, xHi, MIPSRH_Reg(yHi)));
1979             addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo)));
1980             *rHi = tHi;
1981             *rLo = tLo;
1982             return;
1983          }
1984          case Iop_MullU32:
1985          case Iop_MullS32: {
1986             HReg tLo = newVRegI(env);
1987             HReg tHi = newVRegI(env);
1988             HReg r_dst = newVRegI(env);
1989             Bool syned = toBool(op_binop == Iop_MullS32);
1990             HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1991             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1992 
1993             addInstr(env, MIPSInstr_Mul(syned/*Unsigned or Signed */ ,
1994                                         True /*widen */ , True,
1995                                         r_dst, r_srcL, r_srcR));
1996             addInstr(env, MIPSInstr_Mfhi(tHi));
1997             addInstr(env, MIPSInstr_Mflo(tLo));
1998             *rHi = tHi;
1999             *rLo = tLo;
2000 
2001             return;
2002          }
2003          case Iop_DivModS64to32:
2004          case Iop_DivModU64to32: {
2005             HReg r_sHi, r_sLo;
2006             HReg tLo = newVRegI(env);
2007             HReg tHi = newVRegI(env);
2008             Bool syned = toBool(op_binop == Iop_DivModS64to32);
2009             HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2010 
2011             iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1);
2012             addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR));
2013             addInstr(env, MIPSInstr_Mfhi(tHi));
2014             addInstr(env, MIPSInstr_Mflo(tLo));
2015             *rHi = tHi;
2016             *rLo = tLo;
2017 
2018             return;
2019          }
2020 
2021             /* 32HLto64(e1,e2) */
2022          case Iop_32HLto64:
2023             *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2024             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2025 
2026             return;
2027             /* Or64/And64/Xor64 */
2028          case Iop_Or64:
2029          case Iop_And64:
2030          case Iop_Xor64: {
2031             HReg xLo, xHi, yLo, yHi;
2032             HReg tLo = newVRegI(env);
2033             HReg tHi = newVRegI(env);
2034             MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR :
2035                            (op_binop == Iop_And64) ? Malu_AND : Malu_XOR;
2036             iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2037             iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2038             addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi)));
2039             addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo)));
2040             *rHi = tHi;
2041             *rLo = tLo;
2042             return;
2043          }
2044 
2045          default:
2046             break;
2047       }
2048    }
2049 
2050    /* --------- UNARY ops --------- */
2051    if (e->tag == Iex_Unop) {
2052 
2053       switch (e->Iex.Unop.op) {
2054          case Iop_1Sto64: {
2055             HReg tLo = newVRegI(env);
2056             HReg tHi = newVRegI(env);
2057             HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2058             HReg tmp = newVRegI(env);
2059 
2060             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src,
2061                           MIPSRH_Imm(False, 31)));
2062             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, src,
2063                           MIPSRH_Imm(False, 31)));
2064 
2065             addInstr(env, mk_iMOVds_RR(tHi, tmp));
2066             addInstr(env, mk_iMOVds_RR(tLo, tmp));
2067 
2068             *rHi = tHi;
2069             *rLo = tLo;
2070             return;
2071          }
2072 
2073          /* 32Sto64(e) */
2074          case Iop_32Sto64: {
2075             HReg tLo = newVRegI(env);
2076             HReg tHi = newVRegI(env);
2077             HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2078             addInstr(env, mk_iMOVds_RR(tHi, src));
2079             addInstr(env, mk_iMOVds_RR(tLo, src));
2080             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi,
2081                           MIPSRH_Imm(False, 31)));
2082             *rHi = tHi;
2083             *rLo = tLo;
2084             return;
2085          }
2086 
2087          /* 32Uto64(e) */
2088          case Iop_32Uto64: {
2089             HReg tLo = newVRegI(env);
2090             HReg tHi = newVRegI(env);
2091             HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2092             addInstr(env, mk_iMOVds_RR(tLo, src));
2093             addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2094                           MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2095             *rHi = tHi;
2096             *rLo = tLo;
2097             return;
2098          }
2099 
2100          case Iop_CmpwNEZ64: {
2101             HReg srcLo, srcHi;
2102             HReg tmp1 = newVRegI(env);
2103             HReg tmp2 = newVRegI(env);
2104             /* srcHi:srcLo = arg */
2105             iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
2106             /* tmp1 = srcHi | srcLo */
2107             addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo,
2108                                         MIPSRH_Reg(srcHi)));
2109             /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2110 
2111             addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
2112                                         MIPSRH_Reg(tmp1)));
2113 
2114             addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
2115             addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2,
2116                           MIPSRH_Imm(False, 31)));
2117             *rHi = tmp2;
2118             *rLo = tmp2;
2119             return;
2120 
2121          }
2122          case Iop_ReinterpF64asI64: {
2123             HReg tLo = newVRegI(env);
2124             HReg tHi = newVRegI(env);
2125             MIPSAMode *am_addr;
2126             HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
2127 
2128             sub_from_sp(env, 16);   // Move SP down 16 bytes
2129             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2130 
2131             // store as F64
2132             addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
2133                                            am_addr));
2134             // load as 2xI32
2135             addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2136             addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2137                                          mode64));
2138 
2139             add_to_sp(env, 16);  // Reset SP
2140 
2141             *rHi = tHi;
2142             *rLo = tLo;
2143             return;
2144          }
2145 
2146          default:
2147             vex_printf("UNARY: No such op: ");
2148             ppIROp(e->Iex.Unop.op);
2149             vex_printf("\n");
2150             break;
2151       }
2152    }
2153 
2154    vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag);
2155    ppIRExpr(e);
2156    vpanic("iselInt64Expr(mips)");
2157 }
2158 
2159 /*---------------------------------------------------------*/
2160 /*--- ISEL: Floating point expressions (32 bit)         ---*/
2161 /*---------------------------------------------------------*/
2162 
2163 /* Nothing interesting here; really just wrappers for
2164    64-bit stuff. */
2165 
iselFltExpr(ISelEnv * env,IRExpr * e)2166 static HReg iselFltExpr(ISelEnv * env, IRExpr * e)
2167 {
2168    HReg r = iselFltExpr_wrk(env, e);
2169    vassert(hregIsVirtual(r));
2170    return r;
2171 }
2172 
2173 /* DO NOT CALL THIS DIRECTLY */
iselFltExpr_wrk(ISelEnv * env,IRExpr * e)2174 static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
2175 {
2176    IRType ty = typeOfIRExpr(env->type_env, e);
2177    vassert(ty == Ity_F32 || (ty == Ity_F64 && mode64));
2178 
2179    if (e->tag == Iex_RdTmp) {
2180       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2181    }
2182 
2183    if (e->tag == Iex_Load) {
2184       MIPSAMode *am_addr;
2185       HReg r_dst = newVRegF(env);
2186       vassert(e->Iex.Load.ty == Ity_F32
2187              || (e->Iex.Load.ty == Ity_F64 && mode64));
2188       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
2189       addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr));
2190       return r_dst;
2191    }
2192 
2193    if (e->tag == Iex_Get) {
2194       HReg r_dst = newVRegF(env);
2195       MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
2196                                         GuestStatePointer(mode64));
2197       addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr));
2198       return r_dst;
2199    }
2200 
2201    if (e->tag == Iex_Unop) {
2202       switch (e->Iex.Unop.op) {
2203       case Iop_ReinterpI32asF32: {
2204          MIPSAMode *am_addr;
2205          HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2206          HReg r_dst = newVRegF(env);
2207 
2208          sub_from_sp(env, 16);   // Move SP down 16 bytes
2209          am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2210 
2211          // store as I32
2212          addInstr(env, MIPSInstr_Store(4, am_addr, fr_src, mode64));
2213 
2214          // load as Ity_F32
2215          addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr));
2216 
2217          add_to_sp(env, 16);  // Reset SP
2218          return r_dst;
2219 
2220       }
2221       case Iop_F32toF64: {
2222          /* first arg is rounding mode; we ignore it. */
2223          MIPSAMode *am_addr;
2224          HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2225          HReg dst = newVRegF(env);
2226 
2227          sub_from_sp(env, 16);   // Move SP down 16 bytes
2228          am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2229 
2230          addInstr(env, MIPSInstr_Store(4,
2231                                        MIPSAMode_IR(am_addr->Mam.IR.index + 4,
2232                                        am_addr->Mam.IR.base),
2233                                        hregMIPS_GPR0(mode64), mode64));
2234          addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, src, am_addr));
2235 
2236          // load as Ity_F32
2237          addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, dst, am_addr));
2238          add_to_sp(env, 16);  // Reset SP
2239 
2240          return dst;
2241       }
2242       case Iop_ReinterpI64asF64:
2243          {
2244             vassert(mode64);
2245             MIPSAMode *am_addr;
2246             HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2247             HReg r_dst = newVRegF(env);
2248 
2249             sub_from_sp(env, 16);   // Move SP down 16 bytes
2250             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2251 
2252             // store as I32
2253             addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
2254 
2255             // load as Ity_F32
2256             addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
2257 
2258             add_to_sp(env, 16);  // Reset SP
2259             return r_dst;
2260          }
2261       case Iop_AbsF32:
2262       case Iop_AbsF64: {
2263          Bool sz32 = e->Iex.Unop.op == Iop_AbsF32;
2264          HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2265          HReg dst = newVRegF(env);
2266          addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src));
2267          return dst;
2268       }
2269       case Iop_NegF32:
2270       case Iop_NegF64: {
2271          Bool sz32 = e->Iex.Unop.op == Iop_NegF32;
2272          HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2273          HReg dst = newVRegF(env);
2274          addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src));
2275          return dst;
2276       }
2277       default:
2278          break;
2279       }
2280    }
2281 
2282    if (e->tag == Iex_Triop) {
2283       switch (e->Iex.Triop.details->op) {
2284          case Iop_DivF32:
2285          case Iop_DivF64:
2286          case Iop_MulF32:
2287          case Iop_MulF64:
2288          case Iop_AddF32:
2289          case Iop_AddF64:
2290          case Iop_SubF32:
2291          case Iop_SubF64: {
2292             MIPSFpOp op = 0;
2293             /*INVALID*/ HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2);
2294             HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3);
2295             HReg dst = newVRegF(env);
2296             switch (e->Iex.Triop.details->op) {
2297                case Iop_DivF32:
2298                   op = Mfp_DIVS;
2299                   break;
2300                case Iop_MulF32:
2301                   op = Mfp_MULS;
2302                   break;
2303                case Iop_AddF32:
2304                   op = Mfp_ADDS;
2305                   break;
2306                case Iop_SubF32:
2307                   op = Mfp_SUBS;
2308                   break;
2309                default:
2310                   vassert(0);
2311             }
2312             addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
2313             return dst;
2314          }
2315          default:
2316             break;
2317       }
2318    }
2319 
2320    if (e->tag == Iex_Binop) {
2321       switch (e->Iex.Binop.op) {
2322          case Iop_F64toF32: {
2323             HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
2324             HReg valS = newVRegF(env);
2325 
2326             set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2327             addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD));
2328             set_MIPS_rounding_default(env);
2329             return valS;
2330          }
2331 
2332          case Iop_RoundF32toInt: {
2333                HReg valS = newVRegF(env);
2334                HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
2335 
2336                set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2337                addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
2338 
2339                set_MIPS_rounding_default(env);
2340                return valS;
2341             }
2342 
2343          case Iop_I32StoF32: {
2344             HReg r_dst = newVRegF(env);
2345 
2346             MIPSAMode *am_addr;
2347             HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
2348             HReg tmp = newVRegF(env);
2349 
2350             sub_from_sp(env, 16);   // Move SP down 16 bytes
2351             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2352 
2353             // store as I32
2354             addInstr(env, MIPSInstr_Store(4, am_addr, fr_src, mode64));
2355 
2356             // load as Ity_F32
2357             addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, tmp, am_addr));
2358 
2359             add_to_sp(env, 16);  // Reset SP
2360 
2361             set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2362             addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp));
2363             set_MIPS_rounding_default(env);
2364 
2365             return r_dst;
2366          }
2367 
2368          case Iop_SqrtF32:
2369          case Iop_SqrtF64: {
2370             /* first arg is rounding mode; we ignore it. */
2371             Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32;
2372             HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
2373             HReg dst = newVRegF(env);
2374             set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2375             addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst,
2376                                             src));
2377             set_MIPS_rounding_default(env);
2378             return dst;
2379          }
2380 
2381          default:
2382             break;
2383       }
2384    }
2385 
2386    if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
2387       /* This is quite subtle.  The only way to do the relevant
2388          truncation is to do a single-precision store and then a
2389          double precision load to get it back into a register.  The
2390          problem is, if the data is then written to memory a second
2391          time, as in
2392 
2393          STbe(...) = TruncF64asF32(...)
2394 
2395          then will the second truncation further alter the value?  The
2396          answer is no: flds (as generated here) followed by fsts
2397          (generated for the STbe) is the identity function on 32-bit
2398          floats, so we are safe.
2399 
2400          Another upshot of this is that if iselStmt can see the
2401          entirety of
2402 
2403          STbe(...) = TruncF64asF32(arg)
2404 
2405          then it can short circuit having to deal with TruncF64asF32
2406          individually; instead just compute arg into a 64-bit FP
2407          register and do 'fsts' (since that itself does the
2408          truncation).
2409 
2410          We generate pretty poor code here (should be ok both for
2411          32-bit and 64-bit mode); but it is expected that for the most
2412          part the latter optimisation will apply and hence this code
2413          will not often be used.
2414        */
2415       HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
2416       HReg fdst = newVRegF(env);
2417       MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64));
2418 
2419       sub_from_sp(env, 16);
2420       // store as F32, hence truncating
2421       addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1));
2422       // and reload.  Good huh?! (sigh)
2423       addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1));
2424       add_to_sp(env, 16);
2425       return fdst;
2426    }
2427 
2428    vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag);
2429    ppIRExpr(e);
2430    vpanic("iselFltExpr_wrk(mips)");
2431 }
2432 
iselDblExpr(ISelEnv * env,IRExpr * e)2433 static HReg iselDblExpr(ISelEnv * env, IRExpr * e)
2434 {
2435    HReg r = iselDblExpr_wrk(env, e);
2436    vassert(hregClass(r) == HRcFlt64);
2437    vassert(hregIsVirtual(r));
2438    return r;
2439 }
2440 
2441 /* DO NOT CALL THIS DIRECTLY */
iselDblExpr_wrk(ISelEnv * env,IRExpr * e)2442 static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e)
2443 {
2444    IRType ty = typeOfIRExpr(env->type_env, e);
2445    vassert(e);
2446    vassert(ty == Ity_F64);
2447 
2448    if (e->tag == Iex_RdTmp) {
2449       return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2450    }
2451 
2452    /* --------- LOAD --------- */
2453    if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
2454       HReg r_dst = newVRegD(env);
2455       MIPSAMode *am_addr;
2456       vassert(e->Iex.Load.ty == Ity_F64);
2457       am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
2458       addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
2459       return r_dst;
2460    }
2461 
2462    /* --------- GET --------- */
2463    if (e->tag == Iex_Get) {
2464 
2465       HReg r_dst = newVRegD(env);
2466       MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
2467                                         GuestStatePointer(mode64));
2468       addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
2469       return r_dst;
2470    }
2471 
2472    if (e->tag == Iex_Unop) {
2473       MIPSFpOp fpop = Mfp_INVALID;
2474       switch (e->Iex.Unop.op) {
2475          case Iop_NegF64:
2476             fpop = Mfp_NEGD;
2477             break;
2478          case Iop_AbsF64:
2479             fpop = Mfp_ABSD;
2480             break;
2481          case Iop_F32toF64: {
2482             HReg src = iselFltExpr(env, e->Iex.Unop.arg);
2483             HReg dst = newVRegD(env);
2484 
2485             HReg irrm = newVRegI(env);
2486 
2487             MIPSAMode *am_addr1 = MIPSAMode_IR(284, GuestStatePointer(mode64));
2488 
2489             addInstr(env, MIPSInstr_Load(4, irrm, am_addr1, mode64));
2490 
2491             // set new FCSR
2492             HReg tmp = newVRegI(env);
2493             HReg fcsr_old = newVRegI(env);
2494             MIPSAMode *am_addr;
2495 
2496             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
2497                                         MIPSRH_Imm(False, 1)));
2498             addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
2499             addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp,
2500                                         MIPSRH_Imm(False, 3)));
2501             /* save old value of FCSR */
2502             addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
2503             sub_from_sp(env, 8); // Move SP down 4 bytes
2504             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2505 
2506             //store old FCSR to stack
2507             addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
2508 
2509             //set new value of FCSR
2510             addInstr(env, MIPSInstr_MtFCSR(irrm));
2511 
2512             //set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2513             addInstr(env, MIPSInstr_FpUnary(Mfp_CVTD, dst, src));
2514             set_MIPS_rounding_default(env);
2515             return dst;
2516          }
2517          case Iop_ReinterpI64asF64: {
2518             HReg Hi;
2519             HReg Lo;
2520             HReg dst = newVRegD(env);
2521 
2522             iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
2523 
2524             dst = mk_LoadRR32toFPR(env, Hi, Lo);   // 2*I32 -> F64
2525             return dst;
2526          }
2527          case Iop_I32StoF64: {
2528             HReg dst = newVRegD(env);
2529             HReg tmp1 = newVRegF(env);
2530             HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2531             MIPSAMode *am_addr;
2532             sub_from_sp(env, 16);   // Move SP down 16 bytes
2533             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2534 
2535             // store as I32
2536             addInstr(env, MIPSInstr_Store(4, am_addr, r_src, mode64));
2537 
2538             // load as Ity_F32
2539             addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, tmp1, am_addr));
2540 
2541             add_to_sp(env, 16);  // Reset SP
2542 
2543             HReg irrm = newVRegI(env);
2544 
2545             MIPSAMode *am_addr1 = MIPSAMode_IR(284, GuestStatePointer(mode64));
2546 
2547             addInstr(env, MIPSInstr_Load(4, irrm, am_addr1, mode64));
2548 
2549             //set rounding mode
2550             HReg tmp = newVRegI(env);
2551             HReg fcsr_old = newVRegI(env);
2552 
2553             addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
2554                                          MIPSRH_Imm(False, 1)));
2555             addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
2556             addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp,
2557                                         MIPSRH_Imm(False, 3)));
2558             /* save old value of FCSR */
2559             addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
2560             sub_from_sp(env, 8); // Move SP down 4 bytes
2561             am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2562 
2563             //store old FCSR to stack
2564             addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
2565 
2566             //set new value of FCSR
2567             addInstr(env, MIPSInstr_MtFCSR(irrm));
2568 
2569             // and do convert
2570             addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp1));
2571             set_MIPS_rounding_default(env);
2572 
2573             return dst;
2574          }
2575          default:
2576             break;
2577       }
2578 
2579       if (fpop != Mfp_INVALID) {
2580          HReg src = iselDblExpr(env, e->Iex.Unop.arg);
2581          HReg dst = newVRegD(env);
2582          addInstr(env, MIPSInstr_FpUnary(fpop, dst, src));
2583          return dst;
2584       }
2585    }
2586 
2587    if (e->tag == Iex_Binop) {
2588       switch (e->Iex.Binop.op) {
2589          case Iop_RoundF64toInt: {
2590             HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
2591             MIPSRH *fmt = iselWordExpr_RH(env, False, e->Iex.Binop.arg1);
2592             HReg valD1 = newVRegD(env);
2593 
2594             if (fmt->Mrh.Imm.imm16 == 0x3)
2595                addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, valD1, valD));
2596             else if (fmt->Mrh.Imm.imm16 == 0x2)
2597                addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, valD1, valD));
2598             else
2599                vassert(0);
2600             return valD1;
2601          }
2602 
2603          case Iop_SqrtF64:{
2604             /* first arg is rounding mode; we ignore it. */
2605             HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
2606             HReg dst = newVRegD(env);
2607             addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src));
2608             return dst;
2609          }
2610 
2611          default:
2612             break;
2613 
2614       }
2615    }
2616 
2617    if (e->tag == Iex_Triop) {
2618       switch (e->Iex.Triop.details->op) {
2619          case Iop_DivF64:
2620          case Iop_DivF32:
2621          case Iop_MulF64:
2622          case Iop_AddF64:
2623          case Iop_SubF64: {
2624             MIPSFpOp op = 0;
2625             /*INVALID*/ HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2);
2626             HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3);
2627             HReg dst = newVRegD(env);
2628             switch (e->Iex.Triop.details->op) {
2629                case Iop_DivF64:
2630                   op = Mfp_DIVD;
2631                   break;
2632                case Iop_MulF64:
2633                   op = Mfp_MULD;
2634                   break;
2635                case Iop_AddF64:
2636                   op = Mfp_ADDD;
2637                   break;
2638                case Iop_SubF64:
2639                   op = Mfp_SUBD;
2640                   break;
2641                default:
2642                   vassert(0);
2643             }
2644             addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
2645             return dst;
2646          }
2647          default:
2648             break;
2649       }
2650    }
2651 
2652    /* --------- MULTIPLEX --------- */
2653    if (e->tag == Iex_Mux0X) {
2654       if (ty == Ity_F64
2655           && typeOfIRExpr(env->type_env, e->Iex.Mux0X.cond) == Ity_I8) {
2656          HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
2657          HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
2658          HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
2659          HReg r_cond_neg = newVRegI(env);
2660          HReg r_dst = newVRegD(env);
2661          HReg r_tmp_lo = newVRegI(env);
2662          HReg r_tmp_hi = newVRegI(env);
2663          HReg r_tmp1_lo = newVRegI(env);
2664          HReg r_tmp1_hi = newVRegI(env);
2665          HReg r_r0_lo = newVRegI(env);
2666          HReg r_r0_hi = newVRegI(env);
2667          HReg r_rX_lo = newVRegI(env);
2668          HReg r_rX_hi = newVRegI(env);
2669          HReg r_dst_lo = newVRegI(env);
2670          HReg r_dst_hi = newVRegI(env);
2671 
2672          sub_from_sp(env, 16);   // Move SP down 16 bytes
2673          MIPSAMode *am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2674 
2675          // store as Ity_F64
2676          addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, r0, am_addr));
2677 
2678          // load as 2xI32
2679          addInstr(env, MIPSInstr_Load(4, r_r0_lo, am_addr, mode64));
2680          addInstr(env, MIPSInstr_Load(4, r_r0_hi, nextMIPSAModeFloat(am_addr),
2681                                       mode64));
2682 
2683          add_to_sp(env, 16);  // Reset SP
2684 
2685          addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp_lo, r_cond,
2686                                      MIPSRH_Reg(r_r0_lo)));
2687          addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp_hi, r_cond,
2688                        MIPSRH_Reg(r_r0_hi)));
2689 
2690          addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond,
2691                        MIPSRH_Reg(r_cond)));
2692 
2693          sub_from_sp(env, 16);   // Move SP down 16 bytes
2694          am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2695 
2696          // store as Ity_F64
2697          addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, rX, am_addr));
2698 
2699          // load as 2xI32
2700          addInstr(env, MIPSInstr_Load(4, r_rX_lo, am_addr, mode64));
2701          addInstr(env, MIPSInstr_Load(4, r_rX_hi, nextMIPSAModeFloat(am_addr),
2702                                       mode64));
2703 
2704          add_to_sp(env, 16);  // Reset SP
2705 
2706          addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1_lo, r_cond_neg,
2707                                      MIPSRH_Reg(r_rX_lo)));
2708          addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1_hi, r_cond_neg,
2709                                      MIPSRH_Reg(r_rX_hi)));
2710 
2711          addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst_lo, r_tmp_lo,
2712                                      MIPSRH_Reg(r_tmp1_lo)));
2713          addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst_hi, r_tmp_hi,
2714                                      MIPSRH_Reg(r_tmp1_hi)));
2715 
2716          sub_from_sp(env, 16);   // Move SP down 16 bytes
2717          am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2718 
2719          // store as I32
2720          addInstr(env, MIPSInstr_Store(4, am_addr, r_dst_lo, mode64));
2721          addInstr(env, MIPSInstr_Store(4, nextMIPSAModeFloat(am_addr),
2722                   r_dst_hi, mode64));
2723 
2724          // load as Ity_F32
2725          addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
2726 
2727          add_to_sp(env, 16);  // Reset SP
2728 
2729          return r_dst;
2730       }
2731    }
2732 
2733    vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag);
2734    ppIRExpr(e);
2735    vpanic("iselDblExpr_wrk(mips)");
2736 }
2737 
2738 /*---------------------------------------------------------*/
2739 /*--- ISEL: Statements                                  ---*/
2740 /*---------------------------------------------------------*/
2741 
iselStmt(ISelEnv * env,IRStmt * stmt)2742 static void iselStmt(ISelEnv * env, IRStmt * stmt)
2743 {
2744    if (vex_traceflags & VEX_TRACE_VCODE) {
2745       vex_printf("\n-- ");
2746 
2747       ppIRStmt(stmt);
2748       vex_printf("\n");
2749    }
2750 
2751    switch (stmt->tag) {
2752       /* --------- STORE --------- */
2753       case Ist_Store: {
2754          MIPSAMode *am_addr;
2755          IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
2756 
2757          /*constructs addressing mode from address provided */
2758          am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
2759 
2760          if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
2761              (mode64 && (tyd == Ity_I64))) {
2762             HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
2763             addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)),
2764                      am_addr, r_src, mode64));
2765             return;
2766          }
2767          if (!mode64 && (tyd == Ity_I64)) {
2768             HReg vHi, vLo;
2769             HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
2770 
2771             iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
2772 
2773             addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
2774                           MIPSAMode_IR(0, r_addr), vHi, mode64));
2775             addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
2776                           MIPSAMode_IR(4, r_addr), vLo, mode64));
2777             return;
2778          }
2779          if (tyd == Ity_F32) {
2780             HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
2781             addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
2782                                            am_addr));
2783             return;
2784          }
2785 
2786          break;
2787       }
2788 
2789       /* --------- PUT --------- */
2790       case Ist_Put: {
2791          IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
2792 
2793          if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
2794              (ty == Ity_I64 && mode64)) {
2795             HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
2796             MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
2797                                               GuestStatePointer(mode64));
2798             addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)),
2799                                           am_addr, r_src, mode64));
2800             return;
2801          }
2802 
2803          if (ty == Ity_I64 && !mode64) {
2804             HReg vHi, vLo;
2805             MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
2806                                               GuestStatePointer(mode64));
2807             MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4,
2808                                                GuestStatePointer(mode64));
2809             iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
2810             addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
2811                                           am_addr, vLo, mode64));
2812             addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
2813                                           am_addr4, vHi, mode64));
2814             return;
2815 
2816          }
2817 
2818          if (ty == Ity_F32) {
2819             HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
2820             MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
2821                                               GuestStatePointer(mode64));
2822             addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
2823                                            am_addr));
2824             return;
2825          }
2826 
2827          if (ty == Ity_F64) {
2828             HReg fr_src;
2829             fr_src = iselDblExpr(env, stmt->Ist.Put.data);
2830             MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
2831                                               GuestStatePointer(mode64));
2832             addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
2833                                            am_addr));
2834             return;
2835          }
2836          break;
2837       }
2838 
2839       /* --------- TMP --------- */
2840       case Ist_WrTmp: {
2841          IRTemp tmp = stmt->Ist.WrTmp.tmp;
2842          IRType ty = typeOfIRTemp(env->type_env, tmp);
2843 
2844          if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) {
2845             HReg r_dst = lookupIRTemp(env, tmp);
2846             HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
2847             addInstr(env, mk_iMOVds_RR(r_dst, r_src));
2848             return;
2849          }
2850 
2851          if (ty == Ity_I64) {
2852              HReg rHi, rLo, dstHi, dstLo;
2853              iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
2854              lookupIRTemp64(&dstHi, &dstLo, env, tmp);
2855              addInstr(env, mk_iMOVds_RR(dstHi, rHi));
2856              addInstr(env, mk_iMOVds_RR(dstLo, rLo));
2857              return;
2858          }
2859 
2860          if (ty == Ity_F32) {
2861             HReg fr_dst = lookupIRTemp(env, tmp);
2862             HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
2863             addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src));
2864             return;
2865          }
2866 
2867          if (ty == Ity_F64) {
2868              HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
2869              HReg dst = lookupIRTemp(env, tmp);
2870              addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
2871              return;
2872          }
2873          break;
2874       }
2875 
2876       /* --------- Call to DIRTY helper --------- */
2877       case Ist_Dirty: {
2878          IRType retty;
2879          IRDirty *d = stmt->Ist.Dirty.details;
2880          Bool passBBP = False;
2881 
2882          if (d->nFxState == 0)
2883             vassert(!d->needsBBP);
2884          passBBP = toBool(d->nFxState > 0 && d->needsBBP);
2885 
2886          /* Marshal args, do the call, clear stack. */
2887          doHelperCall(env, passBBP, d->guard, d->cee, d->args);
2888 
2889          /* Now figure out what to do with the returned value, if any. */
2890          if (d->tmp == IRTemp_INVALID)
2891             /* No return value.  Nothing to do. */
2892             return;
2893 
2894          retty = typeOfIRTemp(env->type_env, d->tmp);
2895          if (retty == Ity_I64 && !mode64) {
2896             vex_printf
2897                 ("Dirty! Return 64 bits. Not implemented (yet!)\n");
2898             return;
2899          }
2900          if (retty == Ity_I8 || retty == Ity_I16 || retty == Ity_I32
2901              || (retty == Ity_I64 && mode64)) {
2902             /* The returned value is in %r2.  Park it in the register
2903                associated with tmp. */
2904             HReg r_dst = lookupIRTemp(env, d->tmp);
2905             addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
2906             return;
2907          }
2908          break;
2909       }
2910 
2911       /* --------- Load Linked or Store Conditional --------- */
2912       case Ist_LLSC: {
2913          //Temporary solution; this need to be rewritten again for MIPS.
2914          //On MIPS you can not read from address that is locked with LL before SC.
2915          // If you read from address that is locked than SC will fall.
2916          IRTemp res = stmt->Ist.LLSC.result;
2917          IRType tyRes = typeOfIRTemp(env->type_env, res);
2918          IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
2919 
2920          if (!mode64 && (tyAddr != Ity_I32))
2921             goto stmt_fail;
2922 
2923          if (stmt->Ist.LLSC.storedata == NULL) {
2924             /* LL */
2925             MIPSAMode *r_addr;
2926             /*constructs addressing mode from address provided */
2927             r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
2928 
2929             HReg r_dst = lookupIRTemp(env, res);
2930             if (tyRes == Ity_I32) {
2931                addInstr(env, MIPSInstr_Load(4, r_dst, r_addr, mode64));
2932                return;
2933             } else if (tyRes == Ity_I64 && mode64) {
2934                addInstr(env, MIPSInstr_Load(8, r_dst, r_addr, mode64));
2935                return;
2936             }
2937             /* fallthru */ ;
2938          } else {
2939             /* SC */
2940             MIPSAMode *r_addr;
2941             r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
2942             HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
2943             HReg r_dst = lookupIRTemp(env, res);
2944             IRType tyData = typeOfIRExpr(env->type_env,
2945                                          stmt->Ist.LLSC.storedata);
2946 
2947             if (tyData == Ity_I32) {
2948                addInstr(env, MIPSInstr_Store(4, r_addr, r_src, mode64));
2949                addInstr(env, MIPSInstr_LI(r_dst, 0x1));
2950                return;
2951             } else if (tyData == Ity_I64 && mode64) {
2952                addInstr(env, MIPSInstr_Store(8, r_addr, r_src, mode64));
2953                addInstr(env, MIPSInstr_LI(r_dst, 0x1));
2954                return;
2955             }
2956             /* fallthru */
2957          }
2958          goto stmt_fail;
2959        /*NOTREACHED*/}
2960 
2961       /* --------- INSTR MARK --------- */
2962       /* Doesn't generate any executable code ... */
2963    case Ist_IMark:
2964       return;
2965 
2966       /* --------- ABI HINT --------- */
2967       /* These have no meaning (denotation in the IR) and so we ignore
2968          them ... if any actually made it this far. */
2969    case Ist_AbiHint:
2970       return;
2971 
2972       /* --------- NO-OP --------- */
2973       /* Fairly self-explanatory, wouldn't you say? */
2974    case Ist_NoOp:
2975       return;
2976 
2977    /* --------- EXIT --------- */
2978    case Ist_Exit: {
2979       IRConst* dst = stmt->Ist.Exit.dst;
2980       if (!mode64 && dst->tag != Ico_U32)
2981          vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value");
2982       if (mode64 && dst->tag != Ico_U64)
2983          vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value");
2984 
2985       MIPSCondCode cc   = iselCondCode(env, stmt->Ist.Exit.guard);
2986       MIPSAMode*   amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP,
2987                                       hregMIPS_GPR10(mode64));
2988 
2989       /* Case: boring transfer to known address */
2990       if (stmt->Ist.Exit.jk == Ijk_Boring
2991           || stmt->Ist.Exit.jk == Ijk_Call
2992           /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
2993          if (env->chainingAllowed) {
2994             /* .. almost always true .. */
2995             /* Skip the event check at the dst if this is a forwards
2996                edge. */
2997             Bool toFastEP
2998                = mode64
2999                ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
3000                : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
3001             if (0) vex_printf("%s", toFastEP ? "Y" : ",");
3002             addInstr(env, MIPSInstr_XDirect(
3003                              mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
3004                                     : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
3005                              amPC, cc, toFastEP));
3006          } else {
3007             /* .. very occasionally .. */
3008             /* We can't use chaining, so ask for an assisted transfer,
3009                as that's the only alternative that is allowable. */
3010             HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
3011             addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring));
3012          }
3013          return;
3014       }
3015 
3016       /* Case: assisted transfer to arbitrary address */
3017       switch (stmt->Ist.Exit.jk) {
3018          /* Keep this list in sync with that in iselNext below */
3019          case Ijk_ClientReq:
3020          case Ijk_EmFail:
3021          case Ijk_EmWarn:
3022          case Ijk_NoDecode:
3023          case Ijk_NoRedir:
3024          case Ijk_SigBUS:
3025          case Ijk_SigTRAP:
3026          case Ijk_Sys_syscall:
3027          case Ijk_TInval:
3028          {
3029             HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
3030             addInstr(env, MIPSInstr_XAssisted(r, amPC, cc,
3031                                              stmt->Ist.Exit.jk));
3032             return;
3033          }
3034          default:
3035             break;
3036       }
3037 
3038       /* Do we ever expect to see any other kind? */
3039       goto stmt_fail;
3040    }
3041 
3042    default:
3043       break;
3044    }
3045 
3046    stmt_fail:
3047       vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
3048       ppIRStmt(stmt);
3049       vpanic("iselStmt:\n");
3050 }
3051 
3052 /*---------------------------------------------------------*/
3053 /*--- ISEL: Basic block terminators (Nexts)             ---*/
3054 /*---------------------------------------------------------*/
3055 
iselNext(ISelEnv * env,IRExpr * next,IRJumpKind jk,Int offsIP)3056 static void iselNext ( ISelEnv* env,
3057                        IRExpr* next, IRJumpKind jk, Int offsIP )
3058 {
3059    if (vex_traceflags & VEX_TRACE_VCODE) {
3060       vex_printf( "\n-- PUT(%d) = ", offsIP);
3061       ppIRExpr( next );
3062       vex_printf( "; exit-");
3063       ppIRJumpKind(jk);
3064       vex_printf( "\n");
3065    }
3066 
3067    /* Case: boring transfer to known address */
3068    if (next->tag == Iex_Const) {
3069       IRConst* cdst = next->Iex.Const.con;
3070       vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
3071       if (jk == Ijk_Boring || jk == Ijk_Call) {
3072          /* Boring transfer to known address */
3073          MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64));
3074          if (env->chainingAllowed) {
3075             /* .. almost always true .. */
3076             /* Skip the event check at the dst if this is a forwards
3077                edge. */
3078             Bool toFastEP
3079                = env->mode64
3080                ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
3081                : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
3082             if (0) vex_printf("%s", toFastEP ? "X" : ".");
3083             addInstr(env, MIPSInstr_XDirect(
3084                              env->mode64 ? (Addr64)cdst->Ico.U64
3085                                          : (Addr64)cdst->Ico.U32,
3086                              amPC, MIPScc_AL, toFastEP));
3087          } else {
3088             /* .. very occasionally .. */
3089             /* We can't use chaining, so ask for an assisted transfer,
3090                as that's the only alternative that is allowable. */
3091             HReg r = iselWordExpr_R(env, next);
3092             addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
3093                                               Ijk_Boring));
3094          }
3095          return;
3096       }
3097    }
3098 
3099    /* Case: call/return (==boring) transfer to any address */
3100    switch (jk) {
3101       case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
3102 
3103          HReg       r     = iselWordExpr_R(env, next);
3104          MIPSAMode*  amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64));
3105          if (env->chainingAllowed) {
3106             addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL));
3107          } else {
3108             addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
3109                                              Ijk_Boring));
3110          }
3111          return;
3112       }
3113       default:
3114          break;
3115    }
3116 
3117    /* Case: assisted transfer to arbitrary address */
3118    switch (jk) {
3119       /* Keep this list in sync with that for Ist_Exit above */
3120       case Ijk_ClientReq:
3121       case Ijk_EmFail:
3122       case Ijk_EmWarn:
3123       case Ijk_NoDecode:
3124       case Ijk_NoRedir:
3125       case Ijk_SigBUS:
3126       case Ijk_SigTRAP:
3127       case Ijk_Sys_syscall:
3128       case Ijk_TInval: {
3129          HReg      r     = iselWordExpr_R(env, next);
3130          MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64));
3131          addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk));
3132          return;
3133       }
3134       default:
3135          break;
3136    }
3137 
3138    vex_printf( "\n-- PUT(%d) = ", offsIP);
3139    ppIRExpr( next );
3140    vex_printf( "; exit-");
3141    ppIRJumpKind(jk);
3142    vex_printf( "\n");
3143    vassert(0); // are we expecting any other kind?
3144 }
3145 
3146 /*---------------------------------------------------------*/
3147 /*--- Insn selector top-level                           ---*/
3148 /*---------------------------------------------------------*/
3149 
3150 /* 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)3151 HInstrArray *iselSB_MIPS ( IRSB* bb,
3152                            VexArch arch_host,
3153                            VexArchInfo* archinfo_host,
3154                            VexAbiInfo* vbi,
3155                            Int offs_Host_EvC_Counter,
3156                            Int offs_Host_EvC_FailAddr,
3157                            Bool chainingAllowed,
3158                            Bool addProfInc,
3159                            Addr64 max_ga )
3160 {
3161    Int      i, j;
3162    HReg     hreg, hregHI;
3163    ISelEnv* env;
3164    UInt     hwcaps_host = archinfo_host->hwcaps;
3165    MIPSAMode *amCounter, *amFailAddr;
3166 
3167    /* sanity ... */
3168    vassert(arch_host == VexArchMIPS32);
3169    vassert(VEX_PRID_COMP_MIPS == hwcaps_host
3170            || VEX_PRID_COMP_BROADCOM == hwcaps_host);
3171 
3172    mode64 = arch_host != VexArchMIPS32;
3173 
3174    /* Make up an initial environment to use. */
3175    env = LibVEX_Alloc(sizeof(ISelEnv));
3176    env->vreg_ctr = 0;
3177    env->mode64 = mode64;
3178 
3179    /* Set up output code array. */
3180    env->code = newHInstrArray();
3181 
3182    /* Copy BB's type env. */
3183    env->type_env = bb->tyenv;
3184 
3185    /* Make up an IRTemp -> virtual HReg mapping.  This doesn't
3186       change as we go along. */
3187    env->n_vregmap = bb->tyenv->types_used;
3188    env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3189    env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
3190 
3191    /* and finally ... */
3192    env->hwcaps          = hwcaps_host;
3193    env->chainingAllowed = chainingAllowed;
3194    env->hwcaps          = hwcaps_host;
3195    env->max_ga          = max_ga;
3196 
3197    /* For each IR temporary, allocate a suitably-kinded virtual
3198       register. */
3199    j = 0;
3200    for (i = 0; i < env->n_vregmap; i++) {
3201       hregHI = hreg = INVALID_HREG;
3202       switch (bb->tyenv->types[i]) {
3203          case Ity_I1:
3204          case Ity_I8:
3205          case Ity_I16:
3206          case Ity_I32: {
3207             hreg = mkHReg(j++, HRcInt32, True);
3208             break;
3209          }
3210          case Ity_I64: {
3211             hreg = mkHReg(j++, HRcInt32, True);
3212             hregHI = mkHReg(j++, HRcInt32, True);
3213             break;
3214          }
3215          case Ity_I128:
3216             vassert(mode64);
3217             hreg = mkHReg(j++, HRcInt64, True);
3218             hregHI = mkHReg(j++, HRcInt64, True);
3219             break;
3220          case Ity_F32: {
3221             hreg = mkHReg(j++, HRcFlt32, True);
3222             break;
3223          }
3224          case Ity_F64:
3225             hreg = mkHReg(j++, HRcFlt64, True);
3226             break;
3227          default:
3228             ppIRType(bb->tyenv->types[i]);
3229             vpanic("iselBB(mips): IRTemp type");
3230       }
3231       env->vregmap[i] = hreg;
3232       env->vregmapHI[i] = hregHI;
3233    }
3234    env->vreg_ctr = j;
3235 
3236    /* The very first instruction must be an event check. */
3237    amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, hregMIPS_GPR10(mode64));
3238    amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, hregMIPS_GPR10(mode64));
3239    addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr));
3240 
3241    /* Possibly a block counter increment (for profiling).  At this
3242       point we don't know the address of the counter, so just pretend
3243       it is zero.  It will have to be patched later, but before this
3244       translation is used, by a call to LibVEX_patchProfCtr. */
3245    if (addProfInc) {
3246       addInstr(env, MIPSInstr_ProfInc());
3247    }
3248 
3249    /* Ok, finally we can iterate over the statements. */
3250    for (i = 0; i < bb->stmts_used; i++)
3251       iselStmt(env, bb->stmts[i]);
3252 
3253    iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
3254 
3255    /* record the number of vregs we used. */
3256    env->code->n_vregs = env->vreg_ctr;
3257    return env->code;
3258 
3259 }
3260 
3261 /*---------------------------------------------------------------*/
3262 /*--- end                                    host_mips_isel.c ---*/
3263 /*---------------------------------------------------------------*/
3264