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