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