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