blob: 0c51c07030060442df2b84ba2e071591a51aafe6 [file] [log] [blame]
sewardj362cf842012-06-07 08:59:53 +00001
2/*---------------------------------------------------------------*/
petarj0c30de82013-04-19 12:35:00 +00003/*--- begin host_mips_isel.c ---*/
sewardj362cf842012-06-07 08:59:53 +00004/*---------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
Elliott Hughesed398002017-06-21 14:41:24 -070010 Copyright (C) 2010-2017 RT-RK
sewardj362cf842012-06-07 08:59:53 +000011 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"
dejanjc3fee0d2013-07-25 09:08:03 +000038#include "host_generic_simd64.h" /* for 64-bit SIMD helpers */
sewardj362cf842012-06-07 08:59:53 +000039#include "host_mips_defs.h"
40
41/*---------------------------------------------------------*/
42/*--- Register Usage Conventions ---*/
43/*---------------------------------------------------------*/
sewardj362cf842012-06-07 08:59:53 +000044
petarjb92a9542013-02-27 22:57:17 +000045/* Integer Regs
46 ------------
47 ZERO0 Reserved
48 GPR12:22 Allocateable
49 23 GuestStatePointer
petarjb92a9542013-02-27 22:57:17 +000050 SP StackFramePointer
51 RA LinkRegister */
sewardj362cf842012-06-07 08:59:53 +000052
53static Bool mode64 = False;
54
dejanj0e006f22014-02-19 11:56:29 +000055/* Host CPU has FPU and 32 dbl. prec. FP registers. */
56static Bool fp_mode64 = False;
57
sewardj362cf842012-06-07 08:59:53 +000058/* GPR register class for mips32/64 */
sewardja5b50222015-03-26 07:18:32 +000059#define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
sewardj362cf842012-06-07 08:59:53 +000060
61/* FPR register class for mips32/64 */
sewardja5b50222015-03-26 07:18:32 +000062#define HRcFPR(_mode64) ((_mode64) ? HRcFlt64 : HRcFlt32)
sewardj362cf842012-06-07 08:59:53 +000063
64/*---------------------------------------------------------*/
65/*--- ISelEnv ---*/
66/*---------------------------------------------------------*/
67
68/* This carries around:
69
70 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
71 might encounter. This is computed before insn selection starts,
72 and does not change.
73
74 - A mapping from IRTemp to HReg. This tells the insn selector
75 which virtual register(s) are associated with each IRTemp
76 temporary. This is computed before insn selection starts, and
77 does not change. We expect this mapping to map precisely the
78 same set of IRTemps as the type mapping does.
79
80 - vregmap holds the primary register for the IRTemp.
81 - vregmapHI is only used for 64-bit integer-typed
82 IRTemps. It holds the identity of a second
83 32-bit virtual HReg, which holds the high half
84 of the value.
85
86 - The code array, that is, the insns selected so far.
87
88 - A counter, for generating new virtual registers.
89
dejanjc3fee0d2013-07-25 09:08:03 +000090 - The host subarchitecture we are selecting insns for.
sewardj362cf842012-06-07 08:59:53 +000091 This is set at the start and does not change.
92
93 - A Bool for indicating whether we may generate chain-me
94 instructions for control flow transfers, or whether we must use
95 XAssisted.
96
97 - The maximum guest address of any guest insn in this block.
98 Actually, the address of the highest-addressed byte from any insn
99 in this block. Is set at the start and does not change. This is
100 used for detecting jumps which are definitely forward-edges from
101 this block, and therefore can be made (chained) to the fast entry
102 point of the destination, thereby avoiding the destination's
103 event check.
104
105 Note, this is all (well, mostly) host-independent.
106*/
107
108typedef
109 struct {
110 /* Constant -- are set at the start and do not change. */
111 IRTypeEnv* type_env;
112
113 HReg* vregmap;
114 HReg* vregmapHI;
115 Int n_vregmap;
116
117 UInt hwcaps;
118 Bool mode64;
dejanj0e006f22014-02-19 11:56:29 +0000119 Bool fp_mode64;
sewardj362cf842012-06-07 08:59:53 +0000120
121 Bool chainingAllowed;
122 Addr64 max_ga;
123
124 /* These are modified as we go along. */
125 HInstrArray* code;
126 Int vreg_ctr;
127 }
128 ISelEnv;
129
130static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp)
131{
sewardj362cf842012-06-07 08:59:53 +0000132 vassert(tmp < env->n_vregmap);
133 return env->vregmap[tmp];
134}
135
136static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
137{
sewardj362cf842012-06-07 08:59:53 +0000138 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000139 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj362cf842012-06-07 08:59:53 +0000140 *vrLO = env->vregmap[tmp];
141 *vrHI = env->vregmapHI[tmp];
142}
143
144static void
145lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
146{
147 vassert(env->mode64);
sewardj362cf842012-06-07 08:59:53 +0000148 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000149 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj362cf842012-06-07 08:59:53 +0000150 *vrLO = env->vregmap[tmp];
151 *vrHI = env->vregmapHI[tmp];
152}
153
154static void addInstr(ISelEnv * env, MIPSInstr * instr)
155{
156 addHInstr(env->code, instr);
157 if (vex_traceflags & VEX_TRACE_VCODE) {
158 ppMIPSInstr(instr, mode64);
159 vex_printf("\n");
160 }
161}
162
163static HReg newVRegI(ISelEnv * env)
164{
sewardja5b50222015-03-26 07:18:32 +0000165 HReg reg = mkHReg(True/*virtual reg*/,
166 HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
sewardj362cf842012-06-07 08:59:53 +0000167 env->vreg_ctr++;
168 return reg;
169}
170
171static HReg newVRegD(ISelEnv * env)
172{
sewardja5b50222015-03-26 07:18:32 +0000173 HReg reg = mkHReg(True/*virtual reg*/,
174 HRcFlt64, 0/*enc*/, env->vreg_ctr);
sewardj362cf842012-06-07 08:59:53 +0000175 env->vreg_ctr++;
176 return reg;
177}
178
179static HReg newVRegF(ISelEnv * env)
180{
sewardja5b50222015-03-26 07:18:32 +0000181 HReg reg = mkHReg(True/*virtual reg*/,
182 HRcFPR(env->mode64), 0/*enc*/, env->vreg_ctr);
sewardj362cf842012-06-07 08:59:53 +0000183 env->vreg_ctr++;
184 return reg;
185}
186
187static void add_to_sp(ISelEnv * env, UInt n)
188{
189 HReg sp = StackPointer(mode64);
190 vassert(n < 256 && (n % 8) == 0);
petarjb92a9542013-02-27 22:57:17 +0000191 if (mode64)
192 addInstr(env, MIPSInstr_Alu(Malu_DADD, sp, sp, MIPSRH_Imm(True,
193 toUShort(n))));
194 else
195 addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True,
196 toUShort(n))));
sewardj362cf842012-06-07 08:59:53 +0000197}
198
199static void sub_from_sp(ISelEnv * env, UInt n)
200{
201 HReg sp = StackPointer(mode64);
202 vassert(n < 256 && (n % 8) == 0);
petarjb92a9542013-02-27 22:57:17 +0000203 if (mode64)
204 addInstr(env, MIPSInstr_Alu(Malu_DSUB, sp, sp,
205 MIPSRH_Imm(True, toUShort(n))));
206 else
207 addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp,
208 MIPSRH_Imm(True, toUShort(n))));
sewardj362cf842012-06-07 08:59:53 +0000209}
210
211/*---------------------------------------------------------*/
212/*--- ISEL: Forward declarations ---*/
213/*---------------------------------------------------------*/
214
215/* These are organised as iselXXX and iselXXX_wrk pairs. The
216 iselXXX_wrk do the real work, but are not to be called directly.
217 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
218 checks that all returned registers are virtual. You should not
219 call the _wrk version directly.
220*/
221/* 32-bit mode: Compute an I8/I16/I32 into a RH
222 (reg-or-halfword-immediate).
223 It's important to specify whether the immediate is to be regarded
224 as signed or not. If yes, this will never return -32768 as an
225 immediate; this guaranteed that all signed immediates that are
dejanjc3fee0d2013-07-25 09:08:03 +0000226 return can have their sign inverted if need be.
sewardj362cf842012-06-07 08:59:53 +0000227*/
228static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
229static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
230
dejanj0e006f22014-02-19 11:56:29 +0000231/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an
232 immediate in the range 1 .. 31 inclusive. Used for doing shift amounts. */
sewardj362cf842012-06-07 08:59:53 +0000233static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
234static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
235
dejanj0e006f22014-02-19 11:56:29 +0000236/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an
237 immediate in the range 1 .. 63 inclusive. Used for doing shift amounts. */
petarjb92a9542013-02-27 22:57:17 +0000238static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e);
239static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e);
240
sewardj362cf842012-06-07 08:59:53 +0000241/* compute an I8/I16/I32 into a GPR*/
242static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
243static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
244
245/* compute an I32 into an AMode. */
246static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
247 IRType xferTy);
248static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy);
249
250static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
251 IRExpr * e);
252static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
253
254/* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
255static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo,
256 ISelEnv * env, IRExpr * e);
257static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
258
259static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
260static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e);
261
262static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e);
263static HReg iselDblExpr(ISelEnv * env, IRExpr * e);
264
265static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e);
266static HReg iselFltExpr(ISelEnv * env, IRExpr * e);
267
268static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode)
269{
270 /*
271 rounding mode | MIPS | IR
272 ------------------------
273 to nearest | 00 | 00
274 to zero | 01 | 11
275 to +infinity | 10 | 10
276 to -infinity | 11 | 01
277 */
petarjb92a9542013-02-27 22:57:17 +0000278 /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 2 */
sewardj362cf842012-06-07 08:59:53 +0000279 HReg irrm = iselWordExpr_R(env, mode);
280 HReg tmp = newVRegI(env);
281 HReg fcsr_old = newVRegI(env);
282 MIPSAMode *am_addr;
283
284 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
285 MIPSRH_Imm(False, 1)));
286 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
Elliott Hughesed398002017-06-21 14:41:24 -0700287 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, MIPSRH_Imm(False, 3)));
sewardj362cf842012-06-07 08:59:53 +0000288 /* save old value of FCSR */
289 addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
petarjb92a9542013-02-27 22:57:17 +0000290 sub_from_sp(env, 8); /* Move SP down 8 bytes */
sewardj362cf842012-06-07 08:59:53 +0000291 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
292
petarjb92a9542013-02-27 22:57:17 +0000293 /* store old FCSR to stack */
sewardj362cf842012-06-07 08:59:53 +0000294 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
295
petarjb92a9542013-02-27 22:57:17 +0000296 /* set new value of FCSR */
Elliott Hughesed398002017-06-21 14:41:24 -0700297 addInstr(env, MIPSInstr_MtFCSR(tmp));
sewardj362cf842012-06-07 08:59:53 +0000298}
299
300static void set_MIPS_rounding_default(ISelEnv * env)
301{
302 HReg fcsr = newVRegI(env);
petarjb92a9542013-02-27 22:57:17 +0000303 /* load as float */
sewardj362cf842012-06-07 08:59:53 +0000304 MIPSAMode *am_addr;
305 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
306
307 addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64));
308
petarjb92a9542013-02-27 22:57:17 +0000309 add_to_sp(env, 8); /* Reset SP */
sewardj362cf842012-06-07 08:59:53 +0000310
petarjb92a9542013-02-27 22:57:17 +0000311 /* set new value of FCSR*/
sewardj362cf842012-06-07 08:59:53 +0000312 addInstr(env, MIPSInstr_MtFCSR(fcsr));
313}
314
315/*---------------------------------------------------------*/
316/*--- ISEL: Misc helpers ---*/
317/*---------------------------------------------------------*/
318
319/* Make an int reg-reg move. */
320static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src)
321{
322 vassert(hregClass(r_dst) == hregClass(r_src));
323 vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64);
324 return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src));
325}
326
327/*---------------------------------------------------------*/
328/*--- ISEL: Function call helpers ---*/
329/*---------------------------------------------------------*/
330
331/* Used only in doHelperCall. See big comment in doHelperCall re
332 handling of register-parameter args. This function figures out
333 whether evaluation of an expression might require use of a fixed
334 register. If in doubt return True (safe but suboptimal).
335*/
336static Bool mightRequireFixedRegs(IRExpr * e)
337{
338 switch (e->tag) {
339 case Iex_RdTmp:
340 case Iex_Const:
341 case Iex_Get:
342 return False;
343 default:
344 return True;
345 }
346}
347
348/* Load 2*I32 regs to fp reg */
349static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
350{
351 HReg fr_dst = newVRegD(env);
352 MIPSAMode *am_addr0, *am_addr1;
353
354 vassert(hregClass(r_srcHi) == HRcInt32);
355 vassert(hregClass(r_srcLo) == HRcInt32);
356
petarjb92a9542013-02-27 22:57:17 +0000357 sub_from_sp(env, 16); /* Move SP down 16 bytes */
sewardj362cf842012-06-07 08:59:53 +0000358 am_addr0 = MIPSAMode_IR(0, StackPointer(mode64));
petarj1ec43e02012-09-04 13:45:42 +0000359 am_addr1 = MIPSAMode_IR(4, StackPointer(mode64));
sewardj362cf842012-06-07 08:59:53 +0000360
petarjb92a9542013-02-27 22:57:17 +0000361 /* store hi,lo as Ity_I32's */
petarj0c30de82013-04-19 12:35:00 +0000362#if defined (_MIPSEL)
sewardj362cf842012-06-07 08:59:53 +0000363 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64));
364 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64));
petarj0c30de82013-04-19 12:35:00 +0000365#elif defined (_MIPSEB)
366 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcHi, mode64));
367 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcLo, mode64));
sewardjb40431f2013-05-08 08:56:45 +0000368#else
369 /* Stop gcc on other platforms complaining about am_addr1 being set
370 but not used. */
371 (void)am_addr1;
petarj0c30de82013-04-19 12:35:00 +0000372#endif
sewardj362cf842012-06-07 08:59:53 +0000373
petarjb92a9542013-02-27 22:57:17 +0000374 /* load as float */
sewardj362cf842012-06-07 08:59:53 +0000375 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0));
376
petarjb92a9542013-02-27 22:57:17 +0000377 add_to_sp(env, 16); /* Reset SP */
sewardj362cf842012-06-07 08:59:53 +0000378 return fr_dst;
379}
380
sewardj74142b82013-08-08 10:28:59 +0000381/* Do a complete function call. |guard| is a Ity_Bit expression
sewardj362cf842012-06-07 08:59:53 +0000382 indicating whether or not the call happens. If guard==NULL, the
sewardj74142b82013-08-08 10:28:59 +0000383 call is unconditional. |retloc| is set to indicate where the
384 return value is after the call. The caller (of this fn) must
385 generate code to add |stackAdjustAfterCall| to the stack pointer
386 after the call is done. */
sewardj362cf842012-06-07 08:59:53 +0000387
sewardj74142b82013-08-08 10:28:59 +0000388static void doHelperCall(/*OUT*/UInt* stackAdjustAfterCall,
389 /*OUT*/RetLoc* retloc,
390 ISelEnv* env,
391 IRExpr* guard,
392 IRCallee* cee, IRType retTy, IRExpr** args )
sewardj362cf842012-06-07 08:59:53 +0000393{
394 MIPSCondCode cc;
Elliott Hughesed398002017-06-21 14:41:24 -0700395 HReg argregs[8];
396 HReg tmpregs[8];
sewardj362cf842012-06-07 08:59:53 +0000397 Bool go_fast;
398 Int n_args, i, argreg;
399 UInt argiregs;
petarja81d9be2013-01-30 18:06:26 +0000400 HReg src = INVALID_HREG;
sewardj362cf842012-06-07 08:59:53 +0000401
sewardj74142b82013-08-08 10:28:59 +0000402 /* Set default returns. We'll update them later if needed. */
403 *stackAdjustAfterCall = 0;
404 *retloc = mk_RetLoc_INVALID();
405
406 /* These are used for cross-checking that IR-level constraints on
Elliott Hughesed398002017-06-21 14:41:24 -0700407 the use of IRExpr_VECRET() and IRExpr_GSPTR() are observed. */
sewardj74142b82013-08-08 10:28:59 +0000408 UInt nVECRETs = 0;
Elliott Hughesed398002017-06-21 14:41:24 -0700409 UInt nGSPTRs = 0;
sewardj74142b82013-08-08 10:28:59 +0000410
sewardj362cf842012-06-07 08:59:53 +0000411 /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
412 are allowed to be used for passing integer arguments. They correspond
dejanjc3fee0d2013-07-25 09:08:03 +0000413 to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
414 on MIPS host (since we only implement one calling convention) and so we
sewardj362cf842012-06-07 08:59:53 +0000415 always ignore it. */
416
417 /* MIPS 64 calling convention: up to four registers ($a0 ... $a7)
418 are allowed to be used for passing integer arguments. They correspond
dejanjc3fee0d2013-07-25 09:08:03 +0000419 to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
420 on MIPS host (since we only implement one calling convention) and so we
sewardj362cf842012-06-07 08:59:53 +0000421 always ignore it. */
sewardj362cf842012-06-07 08:59:53 +0000422
sewardj74142b82013-08-08 10:28:59 +0000423 /* The return type can be I{64,32,16,8} or V{128,256}. In the
424 latter two cases, it is expected that |args| will contain the
florian90419562013-08-15 20:54:52 +0000425 special node IRExpr_VECRET(), in which case this routine
sewardj74142b82013-08-08 10:28:59 +0000426 generates code to allocate space on the stack for the vector
427 return value. Since we are not passing any scalars on the
428 stack, it is enough to preallocate the return space before
429 marshalling any arguments, in this case.
430
Elliott Hughesed398002017-06-21 14:41:24 -0700431 |args| may also contain IRExpr_GSPTR(), in which case the value
sewardj74142b82013-08-08 10:28:59 +0000432 in the guest state pointer register is passed as the
433 corresponding argument. */
434
435 n_args = 0;
436 for (i = 0; args[i]; i++) {
437 IRExpr* arg = args[i];
florian90419562013-08-15 20:54:52 +0000438 if (UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000439 nVECRETs++;
Elliott Hughesed398002017-06-21 14:41:24 -0700440 } else if (UNLIKELY(arg->tag == Iex_GSPTR)) {
441 nGSPTRs++;
sewardj74142b82013-08-08 10:28:59 +0000442 }
443 n_args++;
444 }
445
446 if (n_args > MIPS_N_REGPARMS) {
petarjb92a9542013-02-27 22:57:17 +0000447 vpanic("doHelperCall(MIPS): cannot currently handle > 4 or 8 args");
sewardj362cf842012-06-07 08:59:53 +0000448 }
petarjb92a9542013-02-27 22:57:17 +0000449 if (mode64) {
450 argregs[0] = hregMIPS_GPR4(mode64);
451 argregs[1] = hregMIPS_GPR5(mode64);
452 argregs[2] = hregMIPS_GPR6(mode64);
453 argregs[3] = hregMIPS_GPR7(mode64);
454 argregs[4] = hregMIPS_GPR8(mode64);
455 argregs[5] = hregMIPS_GPR9(mode64);
456 argregs[6] = hregMIPS_GPR10(mode64);
457 argregs[7] = hregMIPS_GPR11(mode64);
458 argiregs = 0;
sewardj74142b82013-08-08 10:28:59 +0000459 tmpregs[0] = tmpregs[1] = tmpregs[2] =
460 tmpregs[3] = tmpregs[4] = tmpregs[5] =
461 tmpregs[6] = tmpregs[7] = INVALID_HREG;
petarjb92a9542013-02-27 22:57:17 +0000462 } else {
463 argregs[0] = hregMIPS_GPR4(mode64);
464 argregs[1] = hregMIPS_GPR5(mode64);
465 argregs[2] = hregMIPS_GPR6(mode64);
466 argregs[3] = hregMIPS_GPR7(mode64);
467 argiregs = 0;
sewardj74142b82013-08-08 10:28:59 +0000468 tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
petarjb92a9542013-02-27 22:57:17 +0000469 }
sewardj362cf842012-06-07 08:59:53 +0000470
petarjb92a9542013-02-27 22:57:17 +0000471 /* First decide which scheme (slow or fast) is to be used. First assume the
472 fast scheme, and select slow if any contraindications (wow) appear. */
sewardj362cf842012-06-07 08:59:53 +0000473
474 go_fast = True;
475
sewardj74142b82013-08-08 10:28:59 +0000476 /* We'll need space on the stack for the return value. Avoid
477 possible complications with nested calls by using the slow
478 scheme. */
479 if (retTy == Ity_V128 || retTy == Ity_V256)
480 go_fast = False;
481
482 if (go_fast && guard) {
sewardj362cf842012-06-07 08:59:53 +0000483 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
484 && guard->Iex.Const.con->Ico.U1 == True) {
485 /* unconditional */
486 } else {
487 /* Not manifestly unconditional -- be conservative. */
488 go_fast = False;
489 }
490 }
491
492 if (go_fast) {
493 for (i = 0; i < n_args; i++) {
494 if (mightRequireFixedRegs(args[i])) {
495 go_fast = False;
496 break;
497 }
498 }
499 }
500
sewardj362cf842012-06-07 08:59:53 +0000501 /* At this point the scheme to use has been established. Generate
502 code to get the arg values into the argument rregs. */
503 if (go_fast) {
504 /* FAST SCHEME */
505 argreg = 0;
sewardj362cf842012-06-07 08:59:53 +0000506
507 for (i = 0; i < n_args; i++) {
sewardj74142b82013-08-08 10:28:59 +0000508 IRExpr* arg = args[i];
sewardj362cf842012-06-07 08:59:53 +0000509 vassert(argreg < MIPS_N_REGPARMS);
sewardj74142b82013-08-08 10:28:59 +0000510
511 IRType aTy = Ity_INVALID;
Elliott Hughesed398002017-06-21 14:41:24 -0700512 if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +0000513 aTy = typeOfIRExpr(env->type_env, arg);
514
515 if (aTy == Ity_I32 || mode64) {
sewardj362cf842012-06-07 08:59:53 +0000516 argiregs |= (1 << (argreg + 4));
sewardj74142b82013-08-08 10:28:59 +0000517 addInstr(env, mk_iMOVds_RR(argregs[argreg],
518 iselWordExpr_R(env, arg)));
519 argreg++;
520 } else if (aTy == Ity_I64) { /* Ity_I64 */
petarj1ec43e02012-09-04 13:45:42 +0000521 if (argreg & 1) {
522 argreg++;
523 argiregs |= (1 << (argreg + 4));
524 }
525 HReg rHi, rLo;
sewardj74142b82013-08-08 10:28:59 +0000526 iselInt64Expr(&rHi, &rLo, env, arg);
sewardj362cf842012-06-07 08:59:53 +0000527 argiregs |= (1 << (argreg + 4));
petarj1ec43e02012-09-04 13:45:42 +0000528 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
529 argiregs |= (1 << (argreg + 4));
530 addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
sewardj74142b82013-08-08 10:28:59 +0000531 argreg++;
Elliott Hughesed398002017-06-21 14:41:24 -0700532 } else if (arg->tag == Iex_GSPTR) {
sewardj74142b82013-08-08 10:28:59 +0000533 vassert(0); // ATC
534 addInstr(env, mk_iMOVds_RR(argregs[argreg],
535 GuestStatePointer(mode64)));
536 argreg++;
florian90419562013-08-15 20:54:52 +0000537 } else if (arg->tag == Iex_VECRET) {
sewardj74142b82013-08-08 10:28:59 +0000538 // If this happens, it denotes ill-formed IR.
539 vassert(0);
sewardj362cf842012-06-07 08:59:53 +0000540 }
sewardj362cf842012-06-07 08:59:53 +0000541 }
542 /* Fast scheme only applies for unconditional calls. Hence: */
543 cc = MIPScc_AL;
544 } else {
545 /* SLOW SCHEME; move via temporaries */
546 argreg = 0;
sewardj74142b82013-08-08 10:28:59 +0000547
sewardj362cf842012-06-07 08:59:53 +0000548 for (i = 0; i < n_args; i++) {
549 vassert(argreg < MIPS_N_REGPARMS);
sewardj74142b82013-08-08 10:28:59 +0000550 IRExpr* arg = args[i];
551
552 IRType aTy = Ity_INVALID;
Elliott Hughesed398002017-06-21 14:41:24 -0700553 if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +0000554 aTy = typeOfIRExpr(env->type_env, arg);
555
Elliott Hughesed398002017-06-21 14:41:24 -0700556 if (aTy == Ity_I32 || (mode64 && arg->tag != Iex_GSPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000557 tmpregs[argreg] = iselWordExpr_R(env, arg);
558 argreg++;
559 } else if (aTy == Ity_I64) { /* Ity_I64 */
petarj1ec43e02012-09-04 13:45:42 +0000560 if (argreg & 1)
561 argreg++;
562 if (argreg + 1 >= MIPS_N_REGPARMS)
563 vassert(0); /* out of argregs */
564 HReg raHi, raLo;
sewardj74142b82013-08-08 10:28:59 +0000565 iselInt64Expr(&raHi, &raLo, env, arg);
petarj1ec43e02012-09-04 13:45:42 +0000566 tmpregs[argreg] = raLo;
567 argreg++;
dejanjc3fee0d2013-07-25 09:08:03 +0000568 tmpregs[argreg] = raHi;
sewardj74142b82013-08-08 10:28:59 +0000569 argreg++;
Elliott Hughesed398002017-06-21 14:41:24 -0700570 } else if (arg->tag == Iex_GSPTR) {
sewardj74142b82013-08-08 10:28:59 +0000571 tmpregs[argreg] = GuestStatePointer(mode64);
572 argreg++;
sewardj362cf842012-06-07 08:59:53 +0000573 }
florian90419562013-08-15 20:54:52 +0000574 else if (arg->tag == Iex_VECRET) {
sewardj74142b82013-08-08 10:28:59 +0000575 // If this happens, it denotes ill-formed IR
576 vassert(0);
577 }
sewardj362cf842012-06-07 08:59:53 +0000578 }
579
580 /* Now we can compute the condition. We can't do it earlier
581 because the argument computations could trash the condition
582 codes. Be a bit clever to handle the common case where the
583 guard is 1:Bit. */
584 cc = MIPScc_AL;
585 if (guard) {
586 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
587 && guard->Iex.Const.con->Ico.U1 == True) {
588 /* unconditional -- do nothing */
589 } else {
590 cc = iselCondCode(env, guard);
591 src = iselWordExpr_R(env, guard);
592 }
593 }
594 /* Move the args to their final destinations. */
595 for (i = 0; i < argreg; i++) {
petarjb92a9542013-02-27 22:57:17 +0000596 if (hregIsInvalid(tmpregs[i])) /* Skip invalid regs */
sewardj362cf842012-06-07 08:59:53 +0000597 continue;
598 /* None of these insns, including any spill code that might
599 be generated, may alter the condition codes. */
600 argiregs |= (1 << (i + 4));
601 addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
602 }
603 }
604
sewardj74142b82013-08-08 10:28:59 +0000605 /* Do final checks, set the return values, and generate the call
606 instruction proper. */
Elliott Hughesed398002017-06-21 14:41:24 -0700607 vassert(nGSPTRs == 0 || nGSPTRs == 1);
608 vassert(nVECRETs == ((retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0));
sewardj74142b82013-08-08 10:28:59 +0000609 vassert(*stackAdjustAfterCall == 0);
610 vassert(is_RetLoc_INVALID(*retloc));
611 switch (retTy) {
612 case Ity_INVALID:
613 /* Function doesn't return a value. */
614 *retloc = mk_RetLoc_simple(RLPri_None);
615 break;
616 case Ity_I64:
617 *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
618 break;
619 case Ity_I32: case Ity_I16: case Ity_I8:
620 *retloc = mk_RetLoc_simple(RLPri_Int);
621 break;
622 case Ity_V128:
623 vassert(0); // ATC
624 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
625 *stackAdjustAfterCall = 16;
626 break;
627 case Ity_V256:
628 vassert(0); // ATC
629 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
630 *stackAdjustAfterCall = 32;
631 break;
632 default:
633 /* IR can denote other possible return types, but we don't
634 handle those here. */
635 vassert(0);
636 }
sewardj362cf842012-06-07 08:59:53 +0000637
florian93a09742015-01-07 20:14:48 +0000638 Addr64 target = mode64 ? (Addr)cee->addr :
639 toUInt((Addr)cee->addr);
sewardj74142b82013-08-08 10:28:59 +0000640
641 /* Finally, generate the call itself. This needs the *retloc value
642 set in the switch above, which is why it's at the end. */
petarjb92a9542013-02-27 22:57:17 +0000643 if (cc == MIPScc_AL)
florian93a09742015-01-07 20:14:48 +0000644 addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs,
sewardj74142b82013-08-08 10:28:59 +0000645 *retloc));
petarjb92a9542013-02-27 22:57:17 +0000646 else
florian93a09742015-01-07 20:14:48 +0000647 addInstr(env, MIPSInstr_Call(cc, target, argiregs, src, *retloc));
sewardj362cf842012-06-07 08:59:53 +0000648}
649
650/*---------------------------------------------------------*/
651/*--- ISEL: Integer expression auxiliaries ---*/
652/*---------------------------------------------------------*/
653
654/* --------------------- AMODEs --------------------- */
655
656/* Return an AMode which computes the value of the specified
657 expression, possibly also adding insns to the code list as a
658 result. The expression may only be a word-size one.
659*/
660
661static Bool uInt_fits_in_16_bits(UInt u)
662{
663 Int i = u & 0xFFFF;
664 i <<= 16;
665 i >>= 16;
666 return toBool(u == (UInt) i);
667}
668
petarjb92a9542013-02-27 22:57:17 +0000669static Bool uLong_fits_in_16_bits ( ULong u )
670{
671 Long i = u & 0xFFFFULL;
672 i <<= 48;
673 i >>= 48;
674 return toBool(u == (ULong) i);
675}
676
677static Bool uLong_is_4_aligned ( ULong u )
678{
679 return toBool((u & 3ULL) == 0);
680}
681
sewardj362cf842012-06-07 08:59:53 +0000682static Bool sane_AMode(ISelEnv * env, MIPSAMode * am)
683{
684 switch (am->tag) {
685 case Mam_IR:
686 return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) &&
687 hregIsVirtual(am->Mam.IR.base) &&
688 uInt_fits_in_16_bits(am->Mam.IR.index));
689 case Mam_RR:
690 return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) &&
691 hregIsVirtual(am->Mam.RR.base) &&
692 hregClass(am->Mam.RR.index) == HRcGPR(mode64) &&
petarja81d9be2013-01-30 18:06:26 +0000693 hregIsVirtual(am->Mam.RR.index));
sewardj362cf842012-06-07 08:59:53 +0000694 default:
695 vpanic("sane_AMode: unknown mips amode tag");
696 }
697}
698
699static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy)
700{
701 MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
702 vassert(sane_AMode(env, am));
703 return am;
704}
705
706/* DO NOT CALL THIS DIRECTLY ! */
707static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
petarjb92a9542013-02-27 22:57:17 +0000708 IRType xferTy)
sewardj362cf842012-06-07 08:59:53 +0000709{
710 IRType ty = typeOfIRExpr(env->type_env, e);
petarjb92a9542013-02-27 22:57:17 +0000711 if (env->mode64) {
712 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
713 vassert(ty == Ity_I64);
714
715 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
716 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64
717 && e->Iex.Binop.arg2->tag == Iex_Const
718 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
719 && (aligned4imm ?
720 uLong_is_4_aligned(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64) : True)
721 && uLong_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) {
722 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
723 iselWordExpr_R(env, e->Iex.Binop.arg1));
724 }
725
726 /* Add64(expr,expr) */
727 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64) {
728 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
729 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
730 return MIPSAMode_RR(r_idx, r_base);
731 }
732 } else {
sewardj362cf842012-06-07 08:59:53 +0000733 vassert(ty == Ity_I32);
734
735 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
736 if (e->tag == Iex_Binop
737 && e->Iex.Binop.op == Iop_Add32
738 && e->Iex.Binop.arg2->tag == Iex_Const
739 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
740 && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) {
741 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
742 iselWordExpr_R(env, e->Iex.Binop.arg1));
743 }
744
745 /* Add32(expr,expr) */
746 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) {
747 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
748 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
749
750 return MIPSAMode_RR(r_idx, r_base);
751 }
752 }
753
754 /* Doesn't match anything in particular. Generate it into
755 a register and use that. */
756 return MIPSAMode_IR(0, iselWordExpr_R(env, e));
757}
758
759/*---------------------------------------------------------*/
760/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
761/*---------------------------------------------------------*/
762
763/* Select insns for an integer-typed expression, and add them to the
764 code list. Return a reg holding the result. This reg will be a
765 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
766 want to modify it, ask for a new vreg, copy it in there, and modify
767 the copy. The register allocator will do its best to map both
768 vregs to the same real register, so the copies will often disappear
769 later in the game.
770
771 This should handle expressions of 64, 32, 16 and 8-bit type.
772 All results are returned in a (mode64 ? 64bit : 32bit) register.
773 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
774 are arbitrary, so you should mask or sign extend partial values
775 if necessary.
776*/
777static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e)
778{
779 HReg r = iselWordExpr_R_wrk(env, e);
780 /* sanity checks ... */
781
782 vassert(hregClass(r) == HRcGPR(env->mode64));
783 vassert(hregIsVirtual(r));
784 return r;
785}
786
787/* DO NOT CALL THIS DIRECTLY ! */
788static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
789{
dejanjc3fee0d2013-07-25 09:08:03 +0000790 UInt argiregs = 0;
sewardj362cf842012-06-07 08:59:53 +0000791 IRType ty = typeOfIRExpr(env->type_env, e);
792 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1
793 || ty == Ity_F32 || (ty == Ity_I64 && mode64)
794 || (ty == Ity_I128 && mode64));
795
796 switch (e->tag) {
797 /* --------- TEMP --------- */
798 case Iex_RdTmp:
799 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
800
801 /* --------- LOAD --------- */
802 case Iex_Load: {
803 HReg r_dst = newVRegI(env);
804 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
805
806 if (e->Iex.Load.end != Iend_LE
807 && e->Iex.Load.end != Iend_BE)
808 goto irreducible;
809
810 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)),
811 r_dst, am_addr, mode64));
812 return r_dst;
sewardj362cf842012-06-07 08:59:53 +0000813 }
sewardj86525cb2012-06-19 16:33:47 +0000814
sewardj362cf842012-06-07 08:59:53 +0000815 /* --------- BINARY OP --------- */
816 case Iex_Binop: {
817 MIPSAluOp aluOp;
818 MIPSShftOp shftOp;
819
820 /* Is it an addition or logical style op? */
821 switch (e->Iex.Binop.op) {
dejanjc3fee0d2013-07-25 09:08:03 +0000822 case Iop_Add8:
823 case Iop_Add16:
sewardj362cf842012-06-07 08:59:53 +0000824 case Iop_Add32:
825 aluOp = Malu_ADD;
826 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000827
sewardj362cf842012-06-07 08:59:53 +0000828 case Iop_Sub8:
829 case Iop_Sub16:
830 case Iop_Sub32:
831 aluOp = Malu_SUB;
832 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000833
petarjb92a9542013-02-27 22:57:17 +0000834 case Iop_Sub64:
835 aluOp = Malu_DSUB;
836 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000837
dejanj3bc88cc2013-10-07 10:28:56 +0000838 case Iop_And8:
839 case Iop_And16:
sewardj362cf842012-06-07 08:59:53 +0000840 case Iop_And32:
841 case Iop_And64:
842 aluOp = Malu_AND;
843 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000844
845 case Iop_Or8:
846 case Iop_Or16:
sewardj362cf842012-06-07 08:59:53 +0000847 case Iop_Or32:
848 case Iop_Or64:
849 aluOp = Malu_OR;
850 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000851
dejanj3bc88cc2013-10-07 10:28:56 +0000852 case Iop_Xor8:
853 case Iop_Xor16:
sewardj362cf842012-06-07 08:59:53 +0000854 case Iop_Xor32:
855 case Iop_Xor64:
856 aluOp = Malu_XOR;
857 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000858
petarjb92a9542013-02-27 22:57:17 +0000859 case Iop_Add64:
860 aluOp = Malu_DADD;
861 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000862
sewardj362cf842012-06-07 08:59:53 +0000863 default:
864 aluOp = Malu_INVALID;
865 break;
866 }
867
868 /* For commutative ops we assume any literal
869 values are on the second operand. */
870 if (aluOp != Malu_INVALID) {
871 HReg r_dst = newVRegI(env);
872 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
873 MIPSRH *ri_srcR = NULL;
874 /* get right arg into an RH, in the appropriate way */
875 switch (aluOp) {
876 case Malu_ADD:
877 case Malu_SUB:
petarjb92a9542013-02-27 22:57:17 +0000878 case Malu_DADD:
879 case Malu_DSUB:
sewardj362cf842012-06-07 08:59:53 +0000880 ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
881 e->Iex.Binop.arg2);
882 break;
883 case Malu_AND:
884 case Malu_OR:
885 case Malu_XOR:
886 ri_srcR = iselWordExpr_RH(env, False /*unsigned */,
887 e->Iex.Binop.arg2);
888 break;
889 default:
890 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
891 }
892 addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
893 return r_dst;
894 }
895
896 /* a shift? */
897 switch (e->Iex.Binop.op) {
898 case Iop_Shl32:
899 case Iop_Shl64:
900 shftOp = Mshft_SLL;
901 break;
902 case Iop_Shr32:
903 case Iop_Shr64:
904 shftOp = Mshft_SRL;
905 break;
906 case Iop_Sar32:
907 case Iop_Sar64:
908 shftOp = Mshft_SRA;
909 break;
910 default:
911 shftOp = Mshft_INVALID;
912 break;
913 }
914
915 /* we assume any literal values are on the second operand. */
916 if (shftOp != Mshft_INVALID) {
917 HReg r_dst = newVRegI(env);
918 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
dejanjc3fee0d2013-07-25 09:08:03 +0000919 MIPSRH *ri_srcR;
920 if (mode64)
921 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
922 else
923 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2);
924
925 if (ty == Ity_I8) {
926 vassert(0);
927 } else if (ty == Ity_I32) {
928 if (mode64 && (shftOp == Mshft_SRA || shftOp == Mshft_SRL)) {
929 HReg tmp = newVRegI(env);
930 HReg r_srcL_se = newVRegI(env);
931 /* SRA, SRAV, SRL, SRLV: On 64-bit processors, if GPR rt does
932 not contain a sign-extended 32-bit value (bits 63..31
933 equal), then the result of the operation is UNPREDICTABLE.
934 So we need to sign-extend r_srcL:
935 DSLLV tmp, r_srcL, 32
936 DSRAV r_srcL_se, tmp, 32
937 */
938 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tmp,
939 r_srcL, MIPSRH_Imm(False, 32)));
940 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, r_srcL_se,
941 tmp, MIPSRH_Imm(False, 32)));
942 /* And finally do the shift. */
943 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
944 r_dst, r_srcL_se, ri_srcR));
945 } else
946 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
947 r_dst, r_srcL, ri_srcR));
948 } else if (ty == Ity_I64) {
sewardj362cf842012-06-07 08:59:53 +0000949 vassert(mode64);
950 addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */,
951 r_dst, r_srcL, ri_srcR));
petarjb92a9542013-02-27 22:57:17 +0000952 } else
953 goto irreducible;
sewardj362cf842012-06-07 08:59:53 +0000954 return r_dst;
955 }
956
957 /* Cmp*32*(x,y) ? */
958 if (e->Iex.Binop.op == Iop_CmpEQ32
dejanjc3fee0d2013-07-25 09:08:03 +0000959 || e->Iex.Binop.op == Iop_CmpEQ16
sewardj362cf842012-06-07 08:59:53 +0000960 || e->Iex.Binop.op == Iop_CmpNE32
961 || e->Iex.Binop.op == Iop_CmpNE64
962 || e->Iex.Binop.op == Iop_CmpLT32S
963 || e->Iex.Binop.op == Iop_CmpLT32U
964 || e->Iex.Binop.op == Iop_CmpLT64U
dejanjc3fee0d2013-07-25 09:08:03 +0000965 || e->Iex.Binop.op == Iop_CmpLE32U
sewardj362cf842012-06-07 08:59:53 +0000966 || e->Iex.Binop.op == Iop_CmpLE32S
967 || e->Iex.Binop.op == Iop_CmpLE64S
968 || e->Iex.Binop.op == Iop_CmpLT64S
dejanj6ced72b2014-06-04 11:28:07 +0000969 || e->Iex.Binop.op == Iop_CmpEQ64
970 || e->Iex.Binop.op == Iop_CasCmpEQ32
971 || e->Iex.Binop.op == Iop_CasCmpEQ64) {
sewardj362cf842012-06-07 08:59:53 +0000972
973 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
974 || e->Iex.Binop.op == Iop_CmpLE32S
975 || e->Iex.Binop.op == Iop_CmpLT64S
976 || e->Iex.Binop.op == Iop_CmpLE64S);
977 Bool size32;
978 HReg dst = newVRegI(env);
979 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
980 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
981
982 MIPSCondCode cc;
983
984 switch (e->Iex.Binop.op) {
985 case Iop_CmpEQ32:
dejanj6ced72b2014-06-04 11:28:07 +0000986 case Iop_CasCmpEQ32:
sewardj362cf842012-06-07 08:59:53 +0000987 cc = MIPScc_EQ;
988 size32 = True;
989 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000990 case Iop_CmpEQ16:
991 cc = MIPScc_EQ;
992 size32 = True;
993 break;
sewardj362cf842012-06-07 08:59:53 +0000994 case Iop_CmpNE32:
995 cc = MIPScc_NE;
996 size32 = True;
997 break;
998 case Iop_CmpNE64:
999 cc = MIPScc_NE;
Elliott Hughesed398002017-06-21 14:41:24 -07001000 size32 = False;
sewardj362cf842012-06-07 08:59:53 +00001001 break;
1002 case Iop_CmpLT32S:
1003 cc = MIPScc_LT;
1004 size32 = True;
1005 break;
1006 case Iop_CmpLT32U:
1007 cc = MIPScc_LO;
1008 size32 = True;
1009 break;
1010 case Iop_CmpLT64U:
1011 cc = MIPScc_LO;
1012 size32 = False;
1013 break;
dejanjc3fee0d2013-07-25 09:08:03 +00001014 case Iop_CmpLE32U:
1015 cc = MIPScc_LE;
1016 size32 = True;
1017 break;
sewardj362cf842012-06-07 08:59:53 +00001018 case Iop_CmpLE32S:
1019 cc = MIPScc_LE;
1020 size32 = True;
1021 break;
1022 case Iop_CmpLE64S:
1023 cc = MIPScc_LE;
1024 size32 = False;
1025 break;
1026 case Iop_CmpLT64S:
1027 cc = MIPScc_LT;
1028 size32 = False;
1029 break;
1030 case Iop_CmpEQ64:
dejanj6ced72b2014-06-04 11:28:07 +00001031 case Iop_CasCmpEQ64:
sewardj362cf842012-06-07 08:59:53 +00001032 cc = MIPScc_EQ;
1033 size32 = False;
1034 break;
1035 default:
petarjb92a9542013-02-27 22:57:17 +00001036 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
sewardj362cf842012-06-07 08:59:53 +00001037 }
1038
1039 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
1040 return dst;
sewardj362cf842012-06-07 08:59:53 +00001041 }
1042
1043 if (e->Iex.Binop.op == Iop_Max32U) {
sewardj362cf842012-06-07 08:59:53 +00001044 HReg tmp = newVRegI(env);
petarjb92a9542013-02-27 22:57:17 +00001045 HReg r_dst = newVRegI(env);
1046 HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1047 HReg argR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1048 MIPSRH *argRH = iselWordExpr_RH(env, False /*signed */ ,
1049 e->Iex.Binop.arg2);
1050 /* max (v0, s0)
1051 ------------
1052 slt v1, v0, s0
1053 movn v0, s0, v1 */
sewardj362cf842012-06-07 08:59:53 +00001054
petarjb92a9542013-02-27 22:57:17 +00001055 addInstr(env, MIPSInstr_Alu(Malu_SLT, tmp, argL, argRH));
1056 addInstr(env, mk_iMOVds_RR(r_dst, argL));
1057 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, argR, tmp));
1058 return r_dst;
sewardj362cf842012-06-07 08:59:53 +00001059 }
1060
1061 if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) {
1062 Bool sz32 = (e->Iex.Binop.op == Iop_Mul32);
1063 HReg r_dst = newVRegI(env);
1064 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1065 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1066 addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ ,
1067 False /*widen */ ,
1068 sz32 /*32bit or 64bit */,
1069 r_dst, r_srcL, r_srcR));
1070 return r_dst;
1071 }
1072
1073 if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) {
1074 HReg r_dst = newVRegI(env);
1075 HReg tHi = newVRegI(env);
1076 HReg tLo = newVRegI(env);
1077 HReg tLo_1 = newVRegI(env);
1078 HReg tHi_1 = newVRegI(env);
1079 HReg mask = newVRegI(env);
1080
1081 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
1082 Bool size = toBool(e->Iex.Binop.op == Iop_MullS32)
1083 || toBool(e->Iex.Binop.op == Iop_MullU32);
1084 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1085 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1086 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ ,
1087 True /*widen */ ,
1088 size /*32bit or 64bit mul */ ,
1089 r_dst, r_srcL, r_srcR));
1090
1091 addInstr(env, MIPSInstr_Mfhi(tHi));
1092 addInstr(env, MIPSInstr_Mflo(tLo));
1093
1094 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1,
1095 tHi, MIPSRH_Imm(False, 32)));
1096
1097 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1098 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1099 MIPSRH_Reg(mask)));
1100
1101 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1102 MIPSRH_Reg(tLo_1)));
1103
1104 return r_dst;
1105 }
1106
1107 if (e->Iex.Binop.op == Iop_CmpF64) {
1108 HReg r_srcL, r_srcR;
petarjb92a9542013-02-27 22:57:17 +00001109 if (mode64) {
1110 r_srcL = iselFltExpr(env, e->Iex.Binop.arg1);
1111 r_srcR = iselFltExpr(env, e->Iex.Binop.arg2);
1112 } else {
sewardj362cf842012-06-07 08:59:53 +00001113 r_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
1114 r_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
1115 }
1116 HReg tmp = newVRegI(env);
1117 HReg r_ccMIPS = newVRegI(env);
1118 HReg r_ccIR = newVRegI(env);
1119 HReg r_ccIR_b0 = newVRegI(env);
1120 HReg r_ccIR_b2 = newVRegI(env);
1121 HReg r_ccIR_b6 = newVRegI(env);
1122
1123 /* Create in dst, the IRCmpF64Result encoded result. */
petarjb92a9542013-02-27 22:57:17 +00001124 /* chech for EQ */
dejanjf37c0862014-02-25 15:25:49 +00001125 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmp, r_srcL, r_srcR));
1126 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccMIPS, tmp,
1127 MIPSRH_Imm(False, 1)));
petarjb92a9542013-02-27 22:57:17 +00001128 /* chech for UN */
dejanjf37c0862014-02-25 15:25:49 +00001129 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmp, r_srcL, r_srcR));
sewardj362cf842012-06-07 08:59:53 +00001130 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1131 MIPSRH_Reg(tmp)));
petarjb92a9542013-02-27 22:57:17 +00001132 /* chech for LT */
dejanjf37c0862014-02-25 15:25:49 +00001133 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmp, r_srcL, r_srcR));
1134 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp,
1135 tmp, MIPSRH_Imm(False, 2)));
sewardj362cf842012-06-07 08:59:53 +00001136 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1137 MIPSRH_Reg(tmp)));
petarjb92a9542013-02-27 22:57:17 +00001138 /* chech for GT */
dejanjf37c0862014-02-25 15:25:49 +00001139 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_NGT,
1140 tmp, r_srcL, r_srcR));
1141 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, tmp,
1142 MIPSRH_Imm(False, 3)));
sewardj362cf842012-06-07 08:59:53 +00001143
1144 addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp)));
1145 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1146 MIPSRH_Imm(False, 8)));
1147 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1148 MIPSRH_Reg(tmp)));
petarjb92a9542013-02-27 22:57:17 +00001149 /* Map compare result from MIPS to IR,
1150 conforming to CmpF64 definition.
sewardj362cf842012-06-07 08:59:53 +00001151 FP cmp result | MIPS | IR
1152 --------------------------
1153 UN | 0x1 | 0x45
1154 EQ | 0x2 | 0x40
1155 GT | 0x4 | 0x00
1156 LT | 0x8 | 0x01
1157 */
1158
petarjb92a9542013-02-27 22:57:17 +00001159 /* r_ccIR_b0 = r_ccMIPS[0] | r_ccMIPS[3] */
sewardj362cf842012-06-07 08:59:53 +00001160 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS,
1161 MIPSRH_Imm(False, 0x3)));
1162 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS,
1163 MIPSRH_Reg(r_ccIR_b0)));
1164 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0,
1165 MIPSRH_Imm(False, 0x1)));
1166
petarjb92a9542013-02-27 22:57:17 +00001167 /* r_ccIR_b2 = r_ccMIPS[0] */
sewardj362cf842012-06-07 08:59:53 +00001168 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS,
1169 MIPSRH_Imm(False, 0x2)));
1170 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2,
1171 MIPSRH_Imm(False, 0x4)));
1172
petarjb92a9542013-02-27 22:57:17 +00001173 /* r_ccIR_b6 = r_ccMIPS[0] | r_ccMIPS[1] */
sewardj362cf842012-06-07 08:59:53 +00001174 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6,
1175 r_ccMIPS, MIPSRH_Imm(False, 0x1)));
1176 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS,
1177 MIPSRH_Reg(r_ccIR_b6)));
1178 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6,
1179 MIPSRH_Imm(False, 0x6)));
1180 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6,
1181 MIPSRH_Imm(False, 0x40)));
1182
petarjb92a9542013-02-27 22:57:17 +00001183 /* r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 */
sewardj362cf842012-06-07 08:59:53 +00001184 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0,
1185 MIPSRH_Reg(r_ccIR_b2)));
1186 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR,
1187 MIPSRH_Reg(r_ccIR_b6)));
1188 return r_ccIR;
1189 }
1190
1191 if (e->Iex.Binop.op == Iop_DivModU64to32 ||
1192 e->Iex.Binop.op == Iop_DivModS64to32) {
1193 HReg tLo = newVRegI(env);
1194 HReg tHi = newVRegI(env);
1195 HReg mask = newVRegI(env);
1196 HReg tLo_1 = newVRegI(env);
1197 HReg tHi_1 = newVRegI(env);
1198 HReg r_dst = newVRegI(env);
1199 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32);
1200
1201 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1202 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1203
1204 addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
1205 addInstr(env, MIPSInstr_Mfhi(tHi));
1206 addInstr(env, MIPSInstr_Mflo(tLo));
1207
1208 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1209 MIPSRH_Imm(False, 32)));
1210
1211 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1212 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1213 MIPSRH_Reg(mask)));
1214
1215 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1216 MIPSRH_Reg(tLo_1)));
1217
1218 return r_dst;
1219 }
1220
dejanja759d172013-09-19 13:35:45 +00001221 if (e->Iex.Binop.op == Iop_8HLto16
1222 || e->Iex.Binop.op == Iop_16HLto32) {
1223 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1224 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00001225 HReg tLo_1 = newVRegI(env);
1226 HReg tHi_1 = newVRegI(env);
1227 HReg r_dst = newVRegI(env);
dejanja759d172013-09-19 13:35:45 +00001228 UInt shift = 0;
1229 UInt mask = 0;
1230 switch (e->Iex.Binop.op) {
1231 case Iop_8HLto16:
1232 shift = 8;
1233 mask = 0xff;
1234 break;
1235 case Iop_16HLto32:
1236 shift = 16;
1237 mask = 0xffff;
1238 break;
1239 default:
1240 break;
1241 }
dejanjc3fee0d2013-07-25 09:08:03 +00001242
dejanja759d172013-09-19 13:35:45 +00001243 /* sll tHi_1, tHi, shift
1244 and tLo_1, tLo, mask
1245 or r_dst, tHi_1, tLo_1 */
dejanjc3fee0d2013-07-25 09:08:03 +00001246 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi,
dejanja759d172013-09-19 13:35:45 +00001247 MIPSRH_Imm(False, shift)));
dejanjc3fee0d2013-07-25 09:08:03 +00001248 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
dejanja759d172013-09-19 13:35:45 +00001249 MIPSRH_Imm(False, mask)));
dejanjc3fee0d2013-07-25 09:08:03 +00001250 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1251 MIPSRH_Reg(tLo_1)));
dejanjc3fee0d2013-07-25 09:08:03 +00001252 return r_dst;
1253 }
1254
sewardj362cf842012-06-07 08:59:53 +00001255 if (e->Iex.Binop.op == Iop_32HLto64) {
1256 vassert(mode64);
1257 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1258 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1259 HReg tLo_1 = newVRegI(env);
1260 HReg tHi_1 = newVRegI(env);
1261 HReg r_dst = newVRegI(env);
1262 HReg mask = newVRegI(env);
1263
1264 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1265 MIPSRH_Imm(False, 32)));
1266
1267 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1268 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1269 MIPSRH_Reg(mask)));
1270 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1271 MIPSRH_Reg(tLo_1)));
1272
1273 return r_dst;
1274 }
petarjb1426ef2012-06-20 17:53:32 +00001275
petarjb92a9542013-02-27 22:57:17 +00001276 if (e->Iex.Binop.op == Iop_F32toI64S) {
1277 vassert(mode64);
1278 HReg valS = newVRegI(env);
1279 HReg tmpF = newVRegF(env);
1280 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1281
1282 /* CVTLS tmpF, valF */
1283 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1284 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpF, valF));
1285 set_MIPS_rounding_default(env);
1286
1287 /* Doubleword Move from Floating Point
1288 dmfc1 valS, tmpF */
1289 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF));
1290
1291 return valS;
1292 }
1293
petarjb1426ef2012-06-20 17:53:32 +00001294 if (e->Iex.Binop.op == Iop_F64toI32S) {
petarjb92a9542013-02-27 22:57:17 +00001295 HReg valD;
1296 if (mode64)
1297 valD = iselFltExpr(env, e->Iex.Binop.arg2);
1298 else
1299 valD = iselDblExpr(env, e->Iex.Binop.arg2);
petarjb1426ef2012-06-20 17:53:32 +00001300 HReg valS = newVRegF(env);
1301 HReg r_dst = newVRegI(env);
petarjb1426ef2012-06-20 17:53:32 +00001302
petarjb92a9542013-02-27 22:57:17 +00001303 /* CVTWD valS, valD */
petarjb1426ef2012-06-20 17:53:32 +00001304 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1305 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1306 set_MIPS_rounding_default(env);
1307
petarjb92a9542013-02-27 22:57:17 +00001308 /* Move Word From Floating Point
1309 mfc1 r_dst, valS */
1310 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
petarjb1426ef2012-06-20 17:53:32 +00001311
1312 return r_dst;
1313 }
1314
dejanjc3fee0d2013-07-25 09:08:03 +00001315 /* -------- DSP ASE -------- */
1316 /* All used cases involving host-side helper calls. */
1317 void* fn = NULL;
1318 switch (e->Iex.Binop.op) {
1319 case Iop_HAdd8Ux4:
1320 fn = &h_generic_calc_HAdd8Ux4; break;
1321 case Iop_HSub8Ux4:
1322 fn = &h_generic_calc_HSub8Ux4; break;
1323 case Iop_HSub16Sx2:
1324 fn = &h_generic_calc_HSub16Sx2; break;
1325 case Iop_QSub8Ux4:
1326 fn = &h_generic_calc_QSub8Ux4; break;
1327 default:
1328 break;
1329 }
1330
1331 /* What's the retloc? */
sewardj74142b82013-08-08 10:28:59 +00001332 RetLoc rloc = mk_RetLoc_INVALID();
dejanjc3fee0d2013-07-25 09:08:03 +00001333 if (ty == Ity_I32) {
sewardj74142b82013-08-08 10:28:59 +00001334 rloc = mk_RetLoc_simple(RLPri_Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001335 }
1336 else if (ty == Ity_I64) {
sewardj74142b82013-08-08 10:28:59 +00001337 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1338 mk_RetLoc_simple(RLPri_2Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001339 }
1340 else {
1341 goto irreducible;
1342 }
1343
1344 if (fn) {
1345 HReg regL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1346 HReg regR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1347 HReg res = newVRegI(env);
1348 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1349 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR5(env->mode64), regR));
1350 argiregs |= (1 << 4);
1351 argiregs |= (1 << 5);
1352 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
florian93a09742015-01-07 20:14:48 +00001353 (Addr)fn,
dejanjc3fee0d2013-07-25 09:08:03 +00001354 argiregs, rloc));
1355 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1356 return res;
1357 }
sewardj86525cb2012-06-19 16:33:47 +00001358 break;
petarjb1426ef2012-06-20 17:53:32 +00001359 }
sewardj362cf842012-06-07 08:59:53 +00001360
petarjb92a9542013-02-27 22:57:17 +00001361 /* --------- UNARY OP --------- */
sewardj362cf842012-06-07 08:59:53 +00001362 case Iex_Unop: {
1363 IROp op_unop = e->Iex.Unop.op;
1364
1365 switch (op_unop) {
dejanjc3fee0d2013-07-25 09:08:03 +00001366 case Iop_1Sto8:
1367 case Iop_1Sto16:
sewardj362cf842012-06-07 08:59:53 +00001368 case Iop_1Sto32:
dejanj3bc88cc2013-10-07 10:28:56 +00001369 case Iop_8Sto16:
sewardj362cf842012-06-07 08:59:53 +00001370 case Iop_8Sto32:
1371 case Iop_16Sto32:
1372 case Iop_16Sto64:
1373 case Iop_8Sto64:
1374 case Iop_1Sto64: {
1375 HReg r_dst = newVRegI(env);
1376 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1377 Bool sz32;
1378 UShort amt;
1379 switch (op_unop) {
dejanjc3fee0d2013-07-25 09:08:03 +00001380 case Iop_1Sto8:
1381 amt = 31;
1382 sz32 = True;
1383 break;
1384 case Iop_1Sto16:
1385 amt = 31;
1386 sz32 = True;
1387 break;
sewardj362cf842012-06-07 08:59:53 +00001388 case Iop_1Sto32:
1389 amt = 31;
1390 sz32 = True;
1391 break;
1392 case Iop_16Sto32:
1393 amt = 16;
1394 sz32 = True;
1395 break;
1396 case Iop_16Sto64:
1397 amt = 48;
1398 sz32 = False;
1399 break;
dejanj3bc88cc2013-10-07 10:28:56 +00001400 case Iop_8Sto16:
1401 amt = 24;
1402 sz32 = True;
1403 break;
sewardj362cf842012-06-07 08:59:53 +00001404 case Iop_8Sto32:
1405 amt = 24;
1406 sz32 = True;
1407 break;
1408 case Iop_8Sto64:
1409 amt = 56;
1410 sz32 = False;
1411 break;
1412 case Iop_1Sto64:
1413 amt = 63;
1414 sz32 = False;
1415 break;
1416 default:
1417 vassert(0);
1418 }
1419
1420 addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src,
1421 MIPSRH_Imm(False, amt)));
1422 addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst,
1423 MIPSRH_Imm(False, amt)));
1424 return r_dst;
1425 }
1426
petarjb92a9542013-02-27 22:57:17 +00001427 /* not(x) = nor(x,x) */
sewardj362cf842012-06-07 08:59:53 +00001428 case Iop_Not1: {
1429 HReg r_dst = newVRegI(env);
1430 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1431 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1432
1433 addInstr(env, MIPSInstr_LI(r_dst, 0x1));
1434 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
1435 return r_dst;
1436 }
1437
dejanjc3fee0d2013-07-25 09:08:03 +00001438 case Iop_Not8:
1439 case Iop_Not16:
sewardj362cf842012-06-07 08:59:53 +00001440 case Iop_Not32:
1441 case Iop_Not64: {
1442 HReg r_dst = newVRegI(env);
1443 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1444 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1445
1446 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR));
1447 return r_dst;
1448 }
1449
1450 case Iop_ReinterpF32asI32: {
sewardj362cf842012-06-07 08:59:53 +00001451 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1452 HReg r_dst = newVRegI(env);
1453
petarjb92a9542013-02-27 22:57:17 +00001454 /* Move Word From Floating Point
1455 mfc1 r_dst, fr_src */
1456 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, fr_src));
sewardj362cf842012-06-07 08:59:53 +00001457
sewardj362cf842012-06-07 08:59:53 +00001458 return r_dst;
1459 }
1460
1461 case Iop_ReinterpF64asI64: {
1462 vassert(mode64);
sewardj362cf842012-06-07 08:59:53 +00001463 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1464 HReg r_dst = newVRegI(env);
1465
petarjb92a9542013-02-27 22:57:17 +00001466 /* Doubleword Move from Floating Point
1467 mfc1 r_dst, fr_src */
1468 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, r_dst, fr_src));
sewardj362cf842012-06-07 08:59:53 +00001469
petarjb92a9542013-02-27 22:57:17 +00001470 return r_dst;
1471 }
sewardj362cf842012-06-07 08:59:53 +00001472
petarjb92a9542013-02-27 22:57:17 +00001473 case Iop_F64toI32S: {
1474 HReg valD;
1475 if (mode64)
1476 valD = iselFltExpr(env, e->Iex.Binop.arg2);
1477 else
1478 valD = iselDblExpr(env, e->Iex.Binop.arg2);
1479 HReg valS = newVRegF(env);
1480 HReg r_dst = newVRegI(env);
1481
1482 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1483 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1484 set_MIPS_rounding_default(env);
1485
1486 /* Move Word From Floating Point
1487 mfc1 r_dst, valS */
1488 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1489
sewardj362cf842012-06-07 08:59:53 +00001490 return r_dst;
1491 }
sewardj362cf842012-06-07 08:59:53 +00001492
dejanjc3fee0d2013-07-25 09:08:03 +00001493 case Iop_16to8:
dejanj3bc88cc2013-10-07 10:28:56 +00001494 case Iop_32to1:
sewardj362cf842012-06-07 08:59:53 +00001495 case Iop_32to8:
1496 case Iop_32to16:
1497 return iselWordExpr_R(env, e->Iex.Unop.arg);
dejanjc3fee0d2013-07-25 09:08:03 +00001498
1499 case Iop_32HIto16: {
1500 HReg r_dst = newVRegI(env);
1501 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1502 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1503 r_dst, r_src, MIPSRH_Imm(False, 16)));
1504 return r_dst;
1505 }
sewardj362cf842012-06-07 08:59:53 +00001506
dejanj3bc88cc2013-10-07 10:28:56 +00001507 case Iop_64to1:
sewardj362cf842012-06-07 08:59:53 +00001508 case Iop_64to8: {
1509 vassert(mode64);
1510 HReg r_src, r_dst;
dejanj3bc88cc2013-10-07 10:28:56 +00001511 UShort mask = (op_unop == Iop_64to1) ? 0x1 : 0xFF;
sewardj362cf842012-06-07 08:59:53 +00001512 r_dst = newVRegI(env);
1513 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1514 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
dejanj3bc88cc2013-10-07 10:28:56 +00001515 MIPSRH_Imm(False, mask)));
sewardj362cf842012-06-07 08:59:53 +00001516 return r_dst;
1517 }
petarja81d9be2013-01-30 18:06:26 +00001518
dejanjc3fee0d2013-07-25 09:08:03 +00001519 case Iop_16HIto8: {
1520 HReg r_dst = newVRegI(env);
1521 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1522 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1523 r_dst, r_src, MIPSRH_Imm(False, 8)));
1524 return r_dst;
1525 }
1526
dejanj3bc88cc2013-10-07 10:28:56 +00001527 case Iop_1Uto8:
petarja81d9be2013-01-30 18:06:26 +00001528 case Iop_1Uto32:
dejanja759d172013-09-19 13:35:45 +00001529 case Iop_1Uto64:
1530 case Iop_8Uto16:
sewardj362cf842012-06-07 08:59:53 +00001531 case Iop_8Uto32:
dejanja759d172013-09-19 13:35:45 +00001532 case Iop_8Uto64:
1533 case Iop_16Uto32:
1534 case Iop_16Uto64: {
sewardj362cf842012-06-07 08:59:53 +00001535 HReg r_dst = newVRegI(env);
1536 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001537 UShort mask = 0;
sewardj362cf842012-06-07 08:59:53 +00001538 switch (op_unop) {
dejanja759d172013-09-19 13:35:45 +00001539 case Iop_1Uto64:
1540 vassert(mode64);
dejanj3bc88cc2013-10-07 10:28:56 +00001541 case Iop_1Uto8:
sewardj362cf842012-06-07 08:59:53 +00001542 case Iop_1Uto32:
dejanja759d172013-09-19 13:35:45 +00001543 mask = toUShort(0x1);
sewardj362cf842012-06-07 08:59:53 +00001544 break;
dejanja759d172013-09-19 13:35:45 +00001545 case Iop_8Uto64:
1546 vassert(mode64);
1547 case Iop_8Uto16:
petarja81d9be2013-01-30 18:06:26 +00001548 case Iop_8Uto32:
dejanja759d172013-09-19 13:35:45 +00001549 mask = toUShort(0xFF);
petarja81d9be2013-01-30 18:06:26 +00001550 break;
dejanja759d172013-09-19 13:35:45 +00001551 case Iop_16Uto64:
1552 vassert(mode64);
sewardj362cf842012-06-07 08:59:53 +00001553 case Iop_16Uto32:
dejanja759d172013-09-19 13:35:45 +00001554 mask = toUShort(0xFFFF);
sewardj362cf842012-06-07 08:59:53 +00001555 break;
sewardj362cf842012-06-07 08:59:53 +00001556 default:
petarja81d9be2013-01-30 18:06:26 +00001557 vassert(0);
sewardj362cf842012-06-07 08:59:53 +00001558 break;
1559 }
sewardj362cf842012-06-07 08:59:53 +00001560 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1561 MIPSRH_Imm(False, mask)));
1562 return r_dst;
1563 }
1564
1565 case Iop_32Uto64: {
1566 HReg r_dst = newVRegI(env);
1567 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1568 vassert(mode64);
petarjb92a9542013-02-27 22:57:17 +00001569 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False /*!32bit shift */,
sewardj362cf842012-06-07 08:59:53 +00001570 r_dst, r_src, MIPSRH_Imm(False, 32)));
petarjb92a9542013-02-27 22:57:17 +00001571 addInstr(env, MIPSInstr_Shft(Mshft_SRL, False /*!32bit shift */,
sewardj362cf842012-06-07 08:59:53 +00001572 r_dst, r_dst, MIPSRH_Imm(False, 32)));
1573 return r_dst;
1574 }
1575
sewardj362cf842012-06-07 08:59:53 +00001576 case Iop_64HIto32: {
petarjb92a9542013-02-27 22:57:17 +00001577 if (env->mode64) {
1578 HReg r_dst = newVRegI(env);
1579 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1580 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False /*64bit shift */,
1581 r_dst, r_src, MIPSRH_Imm(True, 32)));
1582 return r_dst;
1583 } else {
1584 HReg rHi, rLo;
1585 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1586 return rHi;
1587 }
sewardj362cf842012-06-07 08:59:53 +00001588 }
1589
1590 case Iop_64to32: {
petarjb92a9542013-02-27 22:57:17 +00001591 if (env->mode64) {
1592 HReg r_dst = newVRegI(env);
1593 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1594 return r_dst;
1595 } else {
1596 HReg rHi, rLo;
1597 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1598 return rLo;
1599 }
sewardj362cf842012-06-07 08:59:53 +00001600 }
petarjb92a9542013-02-27 22:57:17 +00001601
sewardj362cf842012-06-07 08:59:53 +00001602 case Iop_64to16: {
1603 vassert(env->mode64);
1604 HReg r_dst = newVRegI(env);
1605 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1606 return r_dst;
1607 }
petarjb92a9542013-02-27 22:57:17 +00001608
sewardj362cf842012-06-07 08:59:53 +00001609 case Iop_32Sto64: {
1610 HReg r_dst = newVRegI(env);
1611 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1612 vassert(mode64);
petarjb92a9542013-02-27 22:57:17 +00001613 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*!32bit shift */,
sewardj362cf842012-06-07 08:59:53 +00001614 r_dst, r_src, MIPSRH_Imm(True, 0)));
1615 return r_dst;
1616 }
petarjb92a9542013-02-27 22:57:17 +00001617
dejanja759d172013-09-19 13:35:45 +00001618 case Iop_CmpNEZ8:
dejanjc3fee0d2013-07-25 09:08:03 +00001619 case Iop_CmpNEZ16: {
1620 HReg r_dst = newVRegI(env);
1621 HReg tmp = newVRegI(env);
1622 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001623 UShort mask = (op_unop == Iop_CmpNEZ8) ? 0xFF : 0xFFFF;
dejanjc3fee0d2013-07-25 09:08:03 +00001624
dejanjc3fee0d2013-07-25 09:08:03 +00001625 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src,
dejanja759d172013-09-19 13:35:45 +00001626 MIPSRH_Imm(False, mask)));
dejanjc3fee0d2013-07-25 09:08:03 +00001627 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp,
dejanja759d172013-09-19 13:35:45 +00001628 hregMIPS_GPR0(mode64), MIPScc_NE));
dejanjc3fee0d2013-07-25 09:08:03 +00001629 return r_dst;
1630 }
1631
sewardj362cf842012-06-07 08:59:53 +00001632 case Iop_CmpNEZ32: {
1633 HReg r_dst = newVRegI(env);
1634 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1635
sewardj362cf842012-06-07 08:59:53 +00001636 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src,
dejanja759d172013-09-19 13:35:45 +00001637 hregMIPS_GPR0(mode64), MIPScc_NE));
sewardj362cf842012-06-07 08:59:53 +00001638 return r_dst;
1639 }
1640
1641 case Iop_CmpwNEZ32: {
1642 HReg r_dst = newVRegI(env);
1643 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1644
1645 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
1646 MIPSRH_Reg(r_src)));
1647
1648 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1649 MIPSRH_Reg(r_src)));
1650 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst,
1651 MIPSRH_Imm(False, 31)));
1652 return r_dst;
1653 }
1654
1655 case Iop_Left8:
dejanjc3fee0d2013-07-25 09:08:03 +00001656 case Iop_Left16:
sewardj362cf842012-06-07 08:59:53 +00001657 case Iop_Left32:
1658 case Iop_Left64: {
1659 if (op_unop == Iop_Left64 && !mode64)
1660 goto irreducible;
1661 HReg r_dst = newVRegI(env);
1662 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001663 MIPSAluOp op = (op_unop == Iop_Left64) ? Malu_DSUB : Malu_SUB;
1664 addInstr(env, MIPSInstr_Alu(op, r_dst,
1665 hregMIPS_GPR0(mode64),
1666 MIPSRH_Reg(r_src)));
sewardj362cf842012-06-07 08:59:53 +00001667 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1668 MIPSRH_Reg(r_src)));
1669 return r_dst;
1670 }
1671
dejanja759d172013-09-19 13:35:45 +00001672 case Iop_Clz64:
1673 vassert(mode64);
sewardj362cf842012-06-07 08:59:53 +00001674 case Iop_Clz32: {
1675 HReg r_dst = newVRegI(env);
1676 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001677 MIPSUnaryOp op = (op_unop == Iop_Clz64) ? Mun_DCLZ : Mun_CLZ;
1678 addInstr(env, MIPSInstr_Unary(op, r_dst, r_src));
petarjb92a9542013-02-27 22:57:17 +00001679 return r_dst;
1680 }
1681
sewardj362cf842012-06-07 08:59:53 +00001682 case Iop_CmpNEZ64: {
1683 HReg hi, lo;
1684 HReg r_dst = newVRegI(env);
1685 HReg r_src;
petarjb92a9542013-02-27 22:57:17 +00001686 if (env->mode64) {
1687 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1688 } else {
1689 r_src = newVRegI(env);
1690 iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg);
1691 addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi)));
1692 }
sewardj362cf842012-06-07 08:59:53 +00001693 addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src,
dejanja759d172013-09-19 13:35:45 +00001694 hregMIPS_GPR0(mode64), MIPScc_NE));
sewardj362cf842012-06-07 08:59:53 +00001695 return r_dst;
1696 }
1697
1698 case Iop_CmpwNEZ64: {
1699 HReg tmp1;
1700 HReg tmp2 = newVRegI(env);
1701 vassert(env->mode64);
1702 tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
1703
dejanj81d4ff22013-09-11 15:34:37 +00001704 addInstr(env, MIPSInstr_Alu(Malu_DSUB, tmp2, hregMIPS_GPR0(mode64),
sewardj362cf842012-06-07 08:59:53 +00001705 MIPSRH_Reg(tmp1)));
1706
1707 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
1708 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2,
1709 MIPSRH_Imm (False, 63)));
1710 return tmp2;
1711 }
1712
1713 case Iop_128HIto64: {
1714 vassert(mode64);
1715 HReg rHi, rLo;
1716 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
petarjb92a9542013-02-27 22:57:17 +00001717 return rHi; /* and abandon rLo .. poor wee thing :-) */
sewardj362cf842012-06-07 08:59:53 +00001718 }
1719
1720 case Iop_128to64: {
1721 vassert(mode64);
1722 HReg rHi, rLo;
1723 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
petarjb92a9542013-02-27 22:57:17 +00001724 return rLo; /* and abandon rLo .. poor wee thing :-) */
sewardj362cf842012-06-07 08:59:53 +00001725 }
1726
1727 default:
1728 break;
1729 }
dejanjc3fee0d2013-07-25 09:08:03 +00001730
1731 /* -------- DSP ASE -------- */
1732 /* All Unop cases involving host-side helper calls. */
1733 void* fn = NULL;
1734 switch (e->Iex.Unop.op) {
1735 case Iop_CmpNEZ16x2:
1736 fn = &h_generic_calc_CmpNEZ16x2; break;
1737 case Iop_CmpNEZ8x4:
1738 fn = &h_generic_calc_CmpNEZ8x4; break;
1739 default:
1740 break;
1741 }
1742
sewardj74142b82013-08-08 10:28:59 +00001743 RetLoc rloc = mk_RetLoc_INVALID();
dejanjc3fee0d2013-07-25 09:08:03 +00001744 if (ty == Ity_I32) {
sewardj74142b82013-08-08 10:28:59 +00001745 rloc = mk_RetLoc_simple(RLPri_Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001746 }
1747 else if (ty == Ity_I64) {
sewardj74142b82013-08-08 10:28:59 +00001748 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1749 mk_RetLoc_simple(RLPri_2Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001750 }
1751 else {
1752 goto irreducible;
1753 }
1754
1755 if (fn) {
1756 HReg regL = iselWordExpr_R(env, e->Iex.Unop.arg);
1757 HReg res = newVRegI(env);
1758 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1759 argiregs |= (1 << 4);
1760 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
florian93a09742015-01-07 20:14:48 +00001761 (Addr)fn,
dejanjc3fee0d2013-07-25 09:08:03 +00001762 argiregs, rloc));
1763 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1764 return res;
1765 }
1766
sewardj362cf842012-06-07 08:59:53 +00001767 break;
1768 }
1769
petarjb92a9542013-02-27 22:57:17 +00001770 /* --------- GET --------- */
sewardj362cf842012-06-07 08:59:53 +00001771 case Iex_Get: {
1772 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
1773 || ((ty == Ity_I64) && mode64)) {
1774 HReg r_dst = newVRegI(env);
1775
1776 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
1777 GuestStatePointer(mode64));
1778 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr,
1779 mode64));
1780 return r_dst;
1781 }
sewardj86525cb2012-06-19 16:33:47 +00001782 break;
sewardj362cf842012-06-07 08:59:53 +00001783 }
1784
petarjb92a9542013-02-27 22:57:17 +00001785 /* --------- ITE --------- */
florian99dd03e2013-01-29 03:56:06 +00001786 case Iex_ITE: {
sewardj362cf842012-06-07 08:59:53 +00001787 if ((ty == Ity_I8 || ty == Ity_I16 ||
1788 ty == Ity_I32 || ((ty == Ity_I64))) &&
petarjd4564182013-01-29 15:42:29 +00001789 typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
dejanj781f1bd2013-10-23 14:05:15 +00001790 HReg r_dst = iselWordExpr_R(env, e->Iex.ITE.iffalse);
1791 HReg r1 = iselWordExpr_R(env, e->Iex.ITE.iftrue);
1792 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
sewardj362cf842012-06-07 08:59:53 +00001793 /*
dejanj781f1bd2013-10-23 14:05:15 +00001794 * r_dst = r0
1795 * movn r_dst, r1, r_cond
sewardj362cf842012-06-07 08:59:53 +00001796 */
dejanj781f1bd2013-10-23 14:05:15 +00001797 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, r1, r_cond));
sewardj362cf842012-06-07 08:59:53 +00001798 return r_dst;
1799 }
sewardj86525cb2012-06-19 16:33:47 +00001800 break;
sewardj362cf842012-06-07 08:59:53 +00001801 }
1802
petarjb92a9542013-02-27 22:57:17 +00001803 /* --------- LITERAL --------- */
1804 /* 32/16/8-bit literals */
sewardj362cf842012-06-07 08:59:53 +00001805 case Iex_Const: {
1806 Long l;
1807 HReg r_dst = newVRegI(env);
1808 IRConst *con = e->Iex.Const.con;
1809 switch (con->tag) {
1810 case Ico_U64:
1811 if (!mode64)
1812 goto irreducible;
1813 l = (Long) con->Ico.U64;
1814 break;
1815 case Ico_U32:
1816 l = (Long) (Int) con->Ico.U32;
1817 break;
1818 case Ico_U16:
1819 l = (Long) (Int) (Short) con->Ico.U16;
1820 break;
1821 case Ico_U8:
1822 l = (Long) (Int) (Char) con->Ico.U8;
1823 break;
1824 default:
1825 vpanic("iselIntExpr_R.const(mips)");
1826 }
1827 addInstr(env, MIPSInstr_LI(r_dst, (ULong) l));
1828 return r_dst;
1829 }
1830
petarjb92a9542013-02-27 22:57:17 +00001831 /* --------- CCALL --------- */
sewardj362cf842012-06-07 08:59:53 +00001832 case Iex_CCall: {
1833 HReg r_dst = newVRegI(env);
1834 vassert(ty == e->Iex.CCall.retty);
1835
sewardjcfe046e2013-01-17 14:23:53 +00001836 /* be very restrictive for now. Only 32/64-bit ints allowed for
dejanjd69cd9a2013-08-16 12:11:20 +00001837 args, and 64 and 32 bits for return type. Don't forget to change
sewardjcfe046e2013-01-17 14:23:53 +00001838 the RetLoc if more return types are allowed in future. */
dejanjd69cd9a2013-08-16 12:11:20 +00001839 if (e->Iex.CCall.retty != Ity_I64 && e->Iex.CCall.retty != Ity_I32)
sewardj362cf842012-06-07 08:59:53 +00001840 goto irreducible;
1841
1842 /* Marshal args, do the call, clear stack. */
sewardj74142b82013-08-08 10:28:59 +00001843 UInt addToSp = 0;
1844 RetLoc rloc = mk_RetLoc_INVALID();
1845 doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
1846 e->Iex.CCall.retty, e->Iex.CCall.args );
1847
1848 vassert(is_sane_RetLoc(rloc));
1849 vassert(rloc.pri == RLPri_Int);
1850 vassert(addToSp == 0);
sewardj362cf842012-06-07 08:59:53 +00001851 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
1852 return r_dst;
1853 }
1854
1855 default:
1856 break;
petarjb92a9542013-02-27 22:57:17 +00001857 } /* end switch(e->tag) */
sewardj362cf842012-06-07 08:59:53 +00001858
1859 /* We get here if no pattern matched. */
1860 irreducible:
1861 vex_printf("--------------->\n");
1862 if (e->tag == Iex_RdTmp)
1863 vex_printf("Iex_RdTmp \n");
1864 ppIRExpr(e);
1865
1866 vpanic("iselWordExpr_R(mips): cannot reduce tree");
1867}
1868
1869/* --------------------- RH --------------------- */
1870
1871/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
1872 (reg-or-halfword-immediate). It's important to specify whether the
1873 immediate is to be regarded as signed or not. If yes, this will
1874 never return -32768 as an immediate; this guaranteed that all
1875 signed immediates that are return can have their sign inverted if
1876 need be. */
1877
1878static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e)
1879{
1880 MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e);
1881 /* sanity checks ... */
1882 switch (ri->tag) {
1883 case Mrh_Imm:
1884 vassert(ri->Mrh.Imm.syned == syned);
1885 if (syned)
1886 vassert(ri->Mrh.Imm.imm16 != 0x8000);
1887 return ri;
1888 case Mrh_Reg:
1889 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
1890 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1891 return ri;
1892 default:
1893 vpanic("iselIntExpr_RH: unknown mips RH tag");
1894 }
1895}
1896
1897/* DO NOT CALL THIS DIRECTLY ! */
1898static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e)
1899{
1900 ULong u;
1901 Long l;
1902 IRType ty = typeOfIRExpr(env->type_env, e);
1903 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1904 ((ty == Ity_I64) && env->mode64));
1905
1906 /* special case: immediate */
1907 if (e->tag == Iex_Const) {
1908 IRConst *con = e->Iex.Const.con;
1909 /* What value are we aiming to generate? */
1910 switch (con->tag) {
1911 /* Note: Not sign-extending - we carry 'syned' around */
1912 case Ico_U64:
1913 vassert(env->mode64);
1914 u = con->Ico.U64;
1915 break;
1916 case Ico_U32:
1917 u = 0xFFFFFFFF & con->Ico.U32;
1918 break;
1919 case Ico_U16:
1920 u = 0x0000FFFF & con->Ico.U16;
1921 break;
1922 case Ico_U8:
1923 u = 0x000000FF & con->Ico.U8;
1924 break;
1925 default:
1926 vpanic("iselIntExpr_RH.Iex_Const(mips)");
1927 }
1928 l = (Long) u;
1929 /* Now figure out if it's representable. */
1930 if (!syned && u <= 65535) {
1931 return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
1932 }
1933 if (syned && l >= -32767 && l <= 32767) {
1934 return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
1935 }
1936 /* no luck; use the Slow Way. */
1937 }
1938 /* default case: calculate into a register and return that */
1939 return MIPSRH_Reg(iselWordExpr_R(env, e));
1940}
1941
1942/* --------------------- RH5u --------------------- */
1943
1944/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
1945 being an immediate in the range 1 .. 31 inclusive. Used for doing
1946 shift amounts. */
1947
1948static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e)
1949{
1950 MIPSRH *ri;
1951 ri = iselWordExpr_RH5u_wrk(env, e);
1952 /* sanity checks ... */
1953 switch (ri->tag) {
1954 case Mrh_Imm:
1955 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31);
1956 vassert(!ri->Mrh.Imm.syned);
1957 return ri;
1958 case Mrh_Reg:
1959 vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32);
1960 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1961 return ri;
1962 default:
1963 vpanic("iselIntExpr_RH5u: unknown mips RH tag");
1964 }
1965}
1966
1967/* DO NOT CALL THIS DIRECTLY ! */
1968static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e)
1969{
1970 IRType ty = typeOfIRExpr(env->type_env, e);
1971 vassert(ty == Ity_I8);
1972
1973 /* special case: immediate */
1974 if (e->tag == Iex_Const
1975 && e->Iex.Const.con->tag == Ico_U8
1976 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) {
1977 return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
1978 }
1979
1980 /* default case: calculate into a register and return that */
1981 return MIPSRH_Reg(iselWordExpr_R(env, e));
1982}
1983
petarjb92a9542013-02-27 22:57:17 +00001984/* --------------------- RH6u --------------------- */
1985
1986/* Only used in 64-bit mode. */
1987static MIPSRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e )
1988{
1989 MIPSRH *ri;
petarjb92a9542013-02-27 22:57:17 +00001990 ri = iselWordExpr_RH6u_wrk(env, e);
1991 /* sanity checks ... */
1992 switch (ri->tag) {
1993 case Mrh_Imm:
1994 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 63);
1995 vassert(!ri->Mrh.Imm.syned);
1996 return ri;
1997 case Mrh_Reg:
1998 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
1999 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2000 return ri;
2001 default:
2002 vpanic("iselIntExpr_RH6u: unknown mips64 RI tag");
2003 }
2004}
2005
2006/* DO NOT CALL THIS DIRECTLY ! */
2007static MIPSRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e )
2008{
2009 IRType ty = typeOfIRExpr(env->type_env, e);
2010 vassert(ty == Ity_I8);
2011
2012 /* special case: immediate */
2013 if (e->tag == Iex_Const
2014 && e->Iex.Const.con->tag == Ico_U8
2015 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 63)
2016 {
2017 return MIPSRH_Imm(False /*unsigned */ ,
2018 e->Iex.Const.con->Ico.U8);
2019 }
2020
2021 /* default case: calculate into a register and return that */
2022 return MIPSRH_Reg(iselWordExpr_R(env, e));
2023}
2024
sewardj362cf842012-06-07 08:59:53 +00002025/* --------------------- CONDCODE --------------------- */
2026
2027/* Generate code to evaluated a bit-typed expression, returning the
2028 condition code which would correspond when the expression would
2029 notionally have returned 1. */
2030
2031static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e)
2032{
2033 MIPSCondCode cc = iselCondCode_wrk(env,e);
2034 vassert(cc != MIPScc_NV);
2035 return cc;
2036}
2037
2038/* DO NOT CALL THIS DIRECTLY ! */
2039static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
2040{
2041 vassert(e);
2042 vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
2043 /* Cmp*32*(x,y) ? */
2044 if (e->Iex.Binop.op == Iop_CmpEQ32
2045 || e->Iex.Binop.op == Iop_CmpNE32
2046 || e->Iex.Binop.op == Iop_CmpNE64
2047 || e->Iex.Binop.op == Iop_CmpLT32S
2048 || e->Iex.Binop.op == Iop_CmpLT32U
2049 || e->Iex.Binop.op == Iop_CmpLT64U
2050 || e->Iex.Binop.op == Iop_CmpLE32S
2051 || e->Iex.Binop.op == Iop_CmpLE64S
2052 || e->Iex.Binop.op == Iop_CmpLT64S
dejanj6ced72b2014-06-04 11:28:07 +00002053 || e->Iex.Binop.op == Iop_CmpEQ64
2054 || e->Iex.Binop.op == Iop_CasCmpEQ32
2055 || e->Iex.Binop.op == Iop_CasCmpEQ64) {
sewardj362cf842012-06-07 08:59:53 +00002056
2057 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
2058 || e->Iex.Binop.op == Iop_CmpLE32S
2059 || e->Iex.Binop.op == Iop_CmpLT64S
2060 || e->Iex.Binop.op == Iop_CmpLE64S);
2061 Bool size32;
2062 HReg dst = newVRegI(env);
2063 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2064 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
2065
2066 MIPSCondCode cc;
2067
2068 switch (e->Iex.Binop.op) {
2069 case Iop_CmpEQ32:
dejanj6ced72b2014-06-04 11:28:07 +00002070 case Iop_CasCmpEQ32:
sewardj362cf842012-06-07 08:59:53 +00002071 cc = MIPScc_EQ;
2072 size32 = True;
2073 break;
2074 case Iop_CmpNE32:
2075 cc = MIPScc_NE;
2076 size32 = True;
2077 break;
2078 case Iop_CmpNE64:
2079 cc = MIPScc_NE;
Elliott Hughesed398002017-06-21 14:41:24 -07002080 size32 = False;
sewardj362cf842012-06-07 08:59:53 +00002081 break;
2082 case Iop_CmpLT32S:
2083 cc = MIPScc_LT;
2084 size32 = True;
2085 break;
2086 case Iop_CmpLT32U:
2087 cc = MIPScc_LO;
2088 size32 = True;
2089 break;
2090 case Iop_CmpLT64U:
2091 cc = MIPScc_LO;
2092 size32 = False;
2093 break;
2094 case Iop_CmpLE32S:
2095 cc = MIPScc_LE;
2096 size32 = True;
2097 break;
2098 case Iop_CmpLE64S:
2099 cc = MIPScc_LE;
2100 size32 = False;
2101 break;
2102 case Iop_CmpLT64S:
2103 cc = MIPScc_LT;
2104 size32 = False;
2105 break;
2106 case Iop_CmpEQ64:
dejanj6ced72b2014-06-04 11:28:07 +00002107 case Iop_CasCmpEQ64:
sewardj362cf842012-06-07 08:59:53 +00002108 cc = MIPScc_EQ;
2109 size32 = False;
2110 break;
2111 default:
dejanja759d172013-09-19 13:35:45 +00002112 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
2113 break;
sewardj362cf842012-06-07 08:59:53 +00002114 }
2115
2116 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
petarjb92a9542013-02-27 22:57:17 +00002117 /* Store result to guest_COND */
sewardj362cf842012-06-07 08:59:53 +00002118 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2119
2120 addInstr(env, MIPSInstr_Store(4,
petarjb92a9542013-02-27 22:57:17 +00002121 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2122 am_addr->Mam.IR.base),
sewardj362cf842012-06-07 08:59:53 +00002123 dst, mode64));
2124 return cc;
2125 }
2126 if (e->Iex.Binop.op == Iop_Not1) {
2127 HReg r_dst = newVRegI(env);
2128 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
2129 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
2130
2131 addInstr(env, MIPSInstr_LI(r_dst, 0x1));
2132 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
petarjb92a9542013-02-27 22:57:17 +00002133 /* Store result to guest_COND */
sewardj362cf842012-06-07 08:59:53 +00002134 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2135
2136 addInstr(env, MIPSInstr_Store(4,
petarjb92a9542013-02-27 22:57:17 +00002137 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2138 am_addr->Mam.IR.base),
sewardj362cf842012-06-07 08:59:53 +00002139 r_dst, mode64));
2140 return MIPScc_NE;
2141 }
2142 if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) {
2143 HReg r_dst = iselWordExpr_R_wrk(env, e);
petarjb92a9542013-02-27 22:57:17 +00002144 /* Store result to guest_COND */
sewardj362cf842012-06-07 08:59:53 +00002145 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2146
2147 addInstr(env, MIPSInstr_Store(4,
petarjb92a9542013-02-27 22:57:17 +00002148 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2149 am_addr->Mam.IR.base),
sewardj362cf842012-06-07 08:59:53 +00002150 r_dst, mode64));
2151 return MIPScc_EQ;
2152 }
2153
2154 vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag);
2155 ppIRExpr(e);
2156 vpanic("iselCondCode(mips)");
2157}
2158
2159/*---------------------------------------------------------*/
2160/*--- ISEL: Integer expressions (128 bit) ---*/
2161/*---------------------------------------------------------*/
2162
2163/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
2164 which is returned as the first two parameters. As with
2165 iselWordExpr_R, these may be either real or virtual regs; in any
2166 case they must not be changed by subsequent code emitted by the
2167 caller. */
2168
2169static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2170{
2171 vassert(env->mode64);
2172 iselInt128Expr_wrk(rHi, rLo, env, e);
sewardj362cf842012-06-07 08:59:53 +00002173 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
2174 vassert(hregIsVirtual(*rHi));
2175 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
2176 vassert(hregIsVirtual(*rLo));
2177}
2178
2179/* DO NOT CALL THIS DIRECTLY ! */
2180static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
2181 IRExpr * e)
2182{
2183 vassert(e);
2184 vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
2185
2186 /* read 128-bit IRTemp */
2187 if (e->tag == Iex_RdTmp) {
2188 lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
2189 return;
2190 }
2191
2192 /* --------- BINARY ops --------- */
2193 if (e->tag == Iex_Binop) {
2194 switch (e->Iex.Binop.op) {
2195 /* 64 x 64 -> 128 multiply */
2196 case Iop_MullU64:
dejanj3bc88cc2013-10-07 10:28:56 +00002197 case Iop_MullS64: {
2198 HReg tLo = newVRegI(env);
2199 HReg tHi = newVRegI(env);
2200 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
2201 HReg r_dst = newVRegI(env);
2202 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2203 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2204 addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ ,
2205 r_dst, r_srcL, r_srcR));
2206 addInstr(env, MIPSInstr_Mfhi(tHi));
2207 addInstr(env, MIPSInstr_Mflo(tLo));
2208 *rHi = tHi;
2209 *rLo = tLo;
2210 return;
2211 }
dejanjc3fee0d2013-07-25 09:08:03 +00002212
sewardj362cf842012-06-07 08:59:53 +00002213 /* 64HLto128(e1,e2) */
2214 case Iop_64HLto128:
2215 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2216 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2217 return;
dejanjc3fee0d2013-07-25 09:08:03 +00002218
sewardj362cf842012-06-07 08:59:53 +00002219 case Iop_DivModS64to64: {
2220 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2221 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2222 HReg tLo = newVRegI(env);
2223 HReg tHi = newVRegI(env);
2224 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
2225
2226 addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
2227 addInstr(env, MIPSInstr_Mfhi(tHi));
2228 addInstr(env, MIPSInstr_Mflo(tLo));
2229 *rHi = tHi;
2230 *rLo = tLo;
2231 return;
2232 }
dejanjc3fee0d2013-07-25 09:08:03 +00002233
dejanj3bc88cc2013-10-07 10:28:56 +00002234 case Iop_DivModU128to64:
2235 case Iop_DivModS128to64: {
sewardj362cf842012-06-07 08:59:53 +00002236 vassert(mode64);
2237 HReg rHi1, rLo1;
2238 iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1);
2239
2240 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2241 HReg tLo = newVRegI(env);
2242 HReg tHi = newVRegI(env);
2243 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64);
2244
2245 addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR));
2246 addInstr(env, MIPSInstr_Mfhi(tHi));
2247 addInstr(env, MIPSInstr_Mflo(tLo));
2248 *rHi = tHi;
2249 *rLo = tLo;
2250 return;
2251 }
dejanjc3fee0d2013-07-25 09:08:03 +00002252
sewardj362cf842012-06-07 08:59:53 +00002253 default:
2254 break;
2255 }
2256 }
2257 vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag);
2258 ppIRExpr(e);
2259 vpanic("iselInt128Expr(mips64)");
2260}
2261
2262/*---------------------------------------------------------*/
2263/*--- ISEL: Integer expressions (64 bit) ---*/
2264/*---------------------------------------------------------*/
2265
dejanjc3fee0d2013-07-25 09:08:03 +00002266/* 32-bit mode ONLY. Compute a 64-bit value into the register
sewardj362cf842012-06-07 08:59:53 +00002267 * pair HI, LO. HI and LO must not be changed by subsequent
2268 * code emitted by the caller. */
2269
2270static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2271{
2272 vassert(!env->mode64);
2273 iselInt64Expr_wrk(rHi, rLo, env, e);
2274 vassert(hregClass(*rHi) == HRcInt32);
2275 vassert(hregIsVirtual(*rHi));
2276 vassert(hregClass(*rLo) == HRcInt32);
2277 vassert(hregIsVirtual(*rLo));
2278}
2279
2280/* DO NOT CALL THIS DIRECTLY ! */
2281static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2282{
2283 vassert(e);
2284 vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
2285
2286 /* read 64-bit IRTemp */
2287 if (e->tag == Iex_RdTmp) {
2288 lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp);
2289 return;
2290 }
2291 /* 64-bit load */
2292 if (e->tag == Iex_Load) {
2293 HReg tLo = newVRegI(env);
2294 HReg tHi = newVRegI(env);
2295 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
2296 addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64));
2297 addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64));
2298 *rHi = tHi;
2299 *rLo = tLo;
2300 return;
2301 }
2302
2303 /* 64-bit literal */
2304 if (e->tag == Iex_Const) {
2305 ULong w64 = e->Iex.Const.con->Ico.U64;
2306 UInt wHi = toUInt(w64 >> 32);
2307 UInt wLo = toUInt(w64);
2308 HReg tLo = newVRegI(env);
2309 HReg tHi = newVRegI(env);
2310 vassert(e->Iex.Const.con->tag == Ico_U64);
2311
2312 if (wLo == wHi) {
2313 /* Save a precious Int register in this special case. */
2314 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
2315 *rHi = tLo;
2316 *rLo = tLo;
2317 } else {
2318 addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi));
2319 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
2320 *rHi = tHi;
2321 *rLo = tLo;
2322 }
2323
2324 return;
2325 }
2326
2327 /* 64-bit GET */
2328 if (e->tag == Iex_Get) {
2329 HReg tLo = newVRegI(env);
2330 HReg tHi = newVRegI(env);
2331
2332 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
2333 GuestStatePointer(mode64));
2334 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2335 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64));
2336 *rHi = tHi;
2337 *rLo = tLo;
2338 return;
2339 }
2340
florian99dd03e2013-01-29 03:56:06 +00002341 /* 64-bit ITE */
2342 if (e->tag == Iex_ITE) {
petarjd4564182013-01-29 15:42:29 +00002343 vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1);
sewardj362cf842012-06-07 08:59:53 +00002344 HReg expr0Lo, expr0Hi;
florian99dd03e2013-01-29 03:56:06 +00002345 HReg expr1Lo, expr1Hi;
dejanja759d172013-09-19 13:35:45 +00002346 HReg desLo = newVRegI(env);
2347 HReg desHi = newVRegI(env);
2348 HReg cond = iselWordExpr_R(env, e->Iex.ITE.cond);
petarjd4564182013-01-29 15:42:29 +00002349
florian99dd03e2013-01-29 03:56:06 +00002350 /* expr0Hi:expr0Lo = iffalse */
2351 /* expr1Hi:expr1Lo = iftrue */
2352 iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.ITE.iffalse);
2353 iselInt64Expr(&expr1Hi, &expr1Lo, env, e->Iex.ITE.iftrue);
sewardj362cf842012-06-07 08:59:53 +00002354
dejanja759d172013-09-19 13:35:45 +00002355 /* move desLo, expr0Lo
2356 * move desHi, expr0Hi
2357 * movn desLo, expr1Lo, cond
2358 * movn desHi, expr1Hi, cond */
2359 addInstr(env, mk_iMOVds_RR(desLo, expr0Lo));
2360 addInstr(env, mk_iMOVds_RR(desHi, expr0Hi));
2361 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desLo, expr1Lo, cond));
2362 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desHi, expr1Hi, cond));
dejanjc3fee0d2013-07-25 09:08:03 +00002363
sewardj362cf842012-06-07 08:59:53 +00002364 *rHi = desHi;
2365 *rLo = desLo;
2366 return;
2367 }
2368
2369 /* --------- BINARY ops --------- */
2370 if (e->tag == Iex_Binop) {
2371 IROp op_binop = e->Iex.Binop.op;
2372 switch (op_binop) {
2373 /* 32 x 32 -> 64 multiply */
2374 /* Add64 */
2375 case Iop_Add64: {
dejanjc3fee0d2013-07-25 09:08:03 +00002376 HReg xLo, xHi, yLo, yHi, carryBit;
2377
sewardj362cf842012-06-07 08:59:53 +00002378 HReg tHi = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002379 HReg tHi1 = newVRegI(env);
sewardj362cf842012-06-07 08:59:53 +00002380 HReg tLo = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002381
2382 carryBit = newVRegI(env);
2383
2384 Bool size32 = True;
2385 MIPSCondCode cc = MIPScc_LO;
2386
sewardj362cf842012-06-07 08:59:53 +00002387 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2388 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
sewardj362cf842012-06-07 08:59:53 +00002389 addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo)));
dejanjc3fee0d2013-07-25 09:08:03 +00002390
2391 /* Check carry. */
2392 addInstr(env, MIPSInstr_Cmp(False, size32, carryBit, tLo, xLo, cc));
2393
2394 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi1, xHi, MIPSRH_Reg(yHi)));
2395 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, tHi1,
2396 MIPSRH_Reg(carryBit)));
2397
2398 *rHi = tHi;
2399 *rLo = tLo;
2400 return;
2401 }
2402 case Iop_Sub64: {
2403 HReg xLo, xHi, yLo, yHi, borrow;
2404 Bool size32 = True;
2405 MIPSCondCode cc = MIPScc_LO;
2406
2407 HReg tHi = newVRegI(env);
2408 HReg tLo = newVRegI(env);
2409
2410 borrow = newVRegI(env);
2411
2412 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2413 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2414
2415 addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, xLo, MIPSRH_Reg(yLo)));
2416
2417 /* Check if borrow is nedded. */
2418 addInstr(env, MIPSInstr_Cmp(False, size32, borrow, xLo, yLo, cc));
2419
dejanj781f1bd2013-10-23 14:05:15 +00002420 addInstr(env, MIPSInstr_Alu(Malu_ADD, yHi, yHi,
2421 MIPSRH_Reg(borrow)));
dejanjc3fee0d2013-07-25 09:08:03 +00002422 addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, xHi, MIPSRH_Reg(yHi)));
2423
sewardj362cf842012-06-07 08:59:53 +00002424 *rHi = tHi;
2425 *rLo = tLo;
2426 return;
2427 }
2428 case Iop_MullU32:
2429 case Iop_MullS32: {
2430 HReg tLo = newVRegI(env);
2431 HReg tHi = newVRegI(env);
2432 HReg r_dst = newVRegI(env);
2433 Bool syned = toBool(op_binop == Iop_MullS32);
2434 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2435 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2436
petarjb92a9542013-02-27 22:57:17 +00002437 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */,
sewardj362cf842012-06-07 08:59:53 +00002438 True /*widen */ , True,
2439 r_dst, r_srcL, r_srcR));
2440 addInstr(env, MIPSInstr_Mfhi(tHi));
2441 addInstr(env, MIPSInstr_Mflo(tLo));
2442 *rHi = tHi;
2443 *rLo = tLo;
2444
2445 return;
2446 }
2447 case Iop_DivModS64to32:
2448 case Iop_DivModU64to32: {
2449 HReg r_sHi, r_sLo;
2450 HReg tLo = newVRegI(env);
2451 HReg tHi = newVRegI(env);
2452 Bool syned = toBool(op_binop == Iop_DivModS64to32);
2453 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2454
2455 iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1);
2456 addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR));
2457 addInstr(env, MIPSInstr_Mfhi(tHi));
2458 addInstr(env, MIPSInstr_Mflo(tLo));
2459 *rHi = tHi;
2460 *rLo = tLo;
2461
2462 return;
2463 }
2464
petarjb92a9542013-02-27 22:57:17 +00002465 /* 32HLto64(e1,e2) */
sewardj362cf842012-06-07 08:59:53 +00002466 case Iop_32HLto64:
2467 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2468 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2469
2470 return;
petarjb92a9542013-02-27 22:57:17 +00002471 /* Or64/And64/Xor64 */
sewardj362cf842012-06-07 08:59:53 +00002472 case Iop_Or64:
2473 case Iop_And64:
2474 case Iop_Xor64: {
2475 HReg xLo, xHi, yLo, yHi;
2476 HReg tLo = newVRegI(env);
2477 HReg tHi = newVRegI(env);
2478 MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR :
2479 (op_binop == Iop_And64) ? Malu_AND : Malu_XOR;
2480 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2481 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2482 addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi)));
2483 addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo)));
2484 *rHi = tHi;
2485 *rLo = tLo;
2486 return;
2487 }
2488
dejanjc3fee0d2013-07-25 09:08:03 +00002489 case Iop_Shr64: {
dejanj781f1bd2013-10-23 14:05:15 +00002490#if defined (_MIPSEL)
2491 /* 64-bit logical shift right based on what gcc generates:
2492 <shift>:
2493 nor v0, zero, a2
2494 sll a3, a1, 0x1
2495 sllv a3, a3, v0
2496 srlv v0, a0, a2
2497 srlv v1, a1, a2
2498 andi a0, a2, 0x20
2499 or v0, a3, v0
2500 movn v0, v1, a0
2501 jr ra
2502 movn v1, zero, a0
2503 */
2504 HReg a0, a1;
2505 HReg a0tmp = newVRegI(env);
2506 HReg a2 = newVRegI(env);
2507 HReg a3 = newVRegI(env);
2508 HReg v0 = newVRegI(env);
2509 HReg v1 = newVRegI(env);
2510 HReg zero = newVRegI(env);
2511 MIPSRH *sa = NULL;
dejanjc3fee0d2013-07-25 09:08:03 +00002512
dejanj781f1bd2013-10-23 14:05:15 +00002513 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2514 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00002515
dejanj781f1bd2013-10-23 14:05:15 +00002516 if (sa->tag == Mrh_Imm) {
2517 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2518 }
2519 else {
2520 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2521 MIPSRH_Imm(False, 0x3f)));
2522 }
dejanjc3fee0d2013-07-25 09:08:03 +00002523
dejanj781f1bd2013-10-23 14:05:15 +00002524 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2525 /* nor v0, zero, a2 */
2526 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2527 /* sll a3, a1, 0x1 */
2528 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2529 a3, a1, MIPSRH_Imm(False, 0x1)));
2530 /* sllv a3, a3, v0 */
2531 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2532 a3, a3, MIPSRH_Reg(v0)));
2533 /* srlv v0, a0, a2 */
2534 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2535 v0, a0, MIPSRH_Reg(a2)));
2536 /* srlv v1, a1, a2 */
2537 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2538 v1, a1, MIPSRH_Reg(a2)));
2539 /* andi a0, a2, 0x20 */
2540 addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2,
2541 MIPSRH_Imm(False, 0x20)));
2542 /* or v0, a3, v0 */
2543 addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0)));
dejanjc3fee0d2013-07-25 09:08:03 +00002544
dejanj781f1bd2013-10-23 14:05:15 +00002545 /* movn v0, v1, a0 */
2546 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp));
2547 /* movn v1, zero, a0 */
2548 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, zero, a0tmp));
dejanjc3fee0d2013-07-25 09:08:03 +00002549
dejanj781f1bd2013-10-23 14:05:15 +00002550 *rHi = v1;
2551 *rLo = v0;
dejanjc3fee0d2013-07-25 09:08:03 +00002552 return;
dejanj781f1bd2013-10-23 14:05:15 +00002553#elif defined (_MIPSEB)
2554 /* 64-bit logical shift right based on what gcc generates:
2555 <shift>:
2556 nor v0, zero, a2
2557 sll a3, a0, 0x1
2558 sllv a3, a3, v0
2559 srlv v1, a1, a2
2560 andi v0, a2, 0x20
2561 or v1, a3, v1
2562 srlv a2, a0, a2
2563 movn v1, a2, v0
2564 movn a2, zero, v0
2565 jr ra
2566 move v0, a2
2567 */
2568 HReg a0, a1;
2569 HReg a2 = newVRegI(env);
2570 HReg a2tmp = newVRegI(env);
2571 HReg a3 = newVRegI(env);
2572 HReg v0 = newVRegI(env);
2573 HReg v1 = newVRegI(env);
2574 HReg zero = newVRegI(env);
2575 MIPSRH *sa = NULL;
2576
2577 iselInt64Expr(&a0, &a1, env, e->Iex.Binop.arg1);
2578 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
2579
2580 if (sa->tag == Mrh_Imm) {
2581 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2582 }
2583 else {
2584 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2585 MIPSRH_Imm(False, 0x3f)));
2586 }
2587
2588 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2589 /* nor v0, zero, a2 */
2590 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2591 /* sll a3, a0, 0x1 */
2592 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2593 a3, a0, MIPSRH_Imm(False, 0x1)));
2594 /* sllv a3, a3, v0 */
2595 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2596 a3, a3, MIPSRH_Reg(v0)));
2597 /* srlv v1, a1, a2 */
2598 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2599 v1, a1, MIPSRH_Reg(a2)));
2600 /* andi v0, a2, 0x20 */
2601 addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2,
2602 MIPSRH_Imm(False, 0x20)));
2603 /* or v1, a3, v1 */
2604 addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1)));
2605 /* srlv a2, a0, a2 */
2606 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2607 a2tmp, a0, MIPSRH_Reg(a2)));
2608
2609 /* movn v1, a2, v0 */
2610 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2tmp, v0));
2611 /* movn a2, zero, v0 */
2612 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2tmp, zero, v0));
2613 /* move v0, a2 */
2614 addInstr(env, mk_iMOVds_RR(v0, a2tmp));
2615
2616 *rHi = v0;
2617 *rLo = v1;
2618 return;
2619#endif
dejanjc3fee0d2013-07-25 09:08:03 +00002620 }
dejanj781f1bd2013-10-23 14:05:15 +00002621
dejanjc3fee0d2013-07-25 09:08:03 +00002622 case Iop_Shl64: {
dejanj781f1bd2013-10-23 14:05:15 +00002623 /* 64-bit shift left based on what gcc generates:
2624 <shift>:
2625 nor v0,zero,a2
2626 srl a3,a0,0x1
2627 srlv a3,a3,v0
2628 sllv v1,a1,a2
2629 andi v0,a2,0x20
2630 or v1,a3,v1
2631 sllv a2,a0,a2
2632 movn v1,a2,v0
2633 movn a2,zero,v0
2634 jr ra
2635 move v0,a2
2636 */
2637 HReg a0, a1;
2638 HReg a2 = newVRegI(env);
2639 HReg a3 = newVRegI(env);
2640 HReg v0 = newVRegI(env);
2641 HReg v1 = newVRegI(env);
2642 HReg zero = newVRegI(env);
2643 MIPSRH *sa = NULL;
dejanjc3fee0d2013-07-25 09:08:03 +00002644
dejanj781f1bd2013-10-23 14:05:15 +00002645 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2646 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00002647
dejanj781f1bd2013-10-23 14:05:15 +00002648 if (sa->tag == Mrh_Imm) {
2649 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2650 }
2651 else {
2652 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2653 MIPSRH_Imm(False, 0x3f)));
2654 }
dejanjc3fee0d2013-07-25 09:08:03 +00002655
dejanj781f1bd2013-10-23 14:05:15 +00002656 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2657 /* nor v0, zero, a2 */
2658 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2659 /* srl a3, a0, 0x1 */
2660 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2661 a3, a0, MIPSRH_Imm(False, 0x1)));
2662 /* srlv a3, a3, v0 */
2663 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2664 a3, a3, MIPSRH_Reg(v0)));
2665 /* sllv v1, a1, a2 */
2666 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2667 v1, a1, MIPSRH_Reg(a2)));
2668 /* andi v0, a2, 0x20 */
2669 addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2,
2670 MIPSRH_Imm(False, 0x20)));
2671 /* or v1, a3, v1 */
2672 addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1)));
2673 /* sllv a2, a0, a2 */
2674 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2675 a2, a0, MIPSRH_Reg(a2)));
dejanjc3fee0d2013-07-25 09:08:03 +00002676
dejanj781f1bd2013-10-23 14:05:15 +00002677 /* movn v1, a2, v0 */
2678 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2, v0));
2679 /* movn a2, zero, v0 */
2680 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2, zero, v0));
2681 addInstr(env, mk_iMOVds_RR(v0, a2));
dejanjc3fee0d2013-07-25 09:08:03 +00002682
dejanj781f1bd2013-10-23 14:05:15 +00002683 *rHi = v1;
2684 *rLo = v0;
dejanjc3fee0d2013-07-25 09:08:03 +00002685 return;
2686 }
dejanj781f1bd2013-10-23 14:05:15 +00002687
dejanjc3fee0d2013-07-25 09:08:03 +00002688 case Iop_Sar64: {
dejanj781f1bd2013-10-23 14:05:15 +00002689 /* 64-bit arithmetic shift right based on what gcc generates:
2690 <shift>:
2691 nor v0, zero, a2
2692 sll a3, a1, 0x1
2693 sllv a3, a3, v0
2694 srlv v0, a0, a2
2695 srav v1, a1, a2
2696 andi a0, a2, 0x20
2697 sra a1, a1, 0x1f
2698 or v0, a3, v0
2699 movn v0, v1, a0
2700 jr ra
2701 movn v1, a1, a0
2702 */
2703 HReg a0, a1;
2704 HReg a0tmp = newVRegI(env);
2705 HReg a1tmp = newVRegI(env);
2706 HReg a2 = newVRegI(env);
2707 HReg a3 = newVRegI(env);
2708 HReg v0 = newVRegI(env);
2709 HReg v1 = newVRegI(env);
2710 HReg zero = newVRegI(env);
2711 MIPSRH *sa = NULL;
dejanjc3fee0d2013-07-25 09:08:03 +00002712
dejanj781f1bd2013-10-23 14:05:15 +00002713 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2714 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00002715
dejanj781f1bd2013-10-23 14:05:15 +00002716 if (sa->tag == Mrh_Imm) {
2717 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2718 }
2719 else {
2720 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2721 MIPSRH_Imm(False, 0x3f)));
2722 }
dejanjc3fee0d2013-07-25 09:08:03 +00002723
dejanj781f1bd2013-10-23 14:05:15 +00002724 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2725 /* nor v0, zero, a2 */
2726 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2727 /* sll a3, a1, 0x1 */
2728 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2729 a3, a1, MIPSRH_Imm(False, 0x1)));
2730 /* sllv a3, a3, v0 */
2731 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2732 a3, a3, MIPSRH_Reg(v0)));
2733 /* srlv v0, a0, a2 */
2734 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2735 v0, a0, MIPSRH_Reg(a2)));
2736 /* srav v1, a1, a2 */
2737 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
2738 v1, a1, MIPSRH_Reg(a2)));
2739 /* andi a0, a2, 0x20 */
2740 addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2,
2741 MIPSRH_Imm(False, 0x20)));
2742 /* sra a1, a1, 0x1f */
2743 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
2744 a1tmp, a1, MIPSRH_Imm(False, 0x1f)));
2745 /* or v0, a3, v0 */
2746 addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0)));
dejanjc3fee0d2013-07-25 09:08:03 +00002747
dejanj781f1bd2013-10-23 14:05:15 +00002748 /* movn v0, v1, a0 */
2749 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp));
2750 /* movn v1, a1, a0 */
2751 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a1tmp, a0tmp));
dejanjc3fee0d2013-07-25 09:08:03 +00002752
dejanj781f1bd2013-10-23 14:05:15 +00002753 *rHi = v1;
2754 *rLo = v0;
dejanjc3fee0d2013-07-25 09:08:03 +00002755 return;
2756 }
2757
dejanj0e006f22014-02-19 11:56:29 +00002758 case Iop_F32toI64S: {
2759 HReg tmpD = newVRegD(env);
2760 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
2761 HReg tLo = newVRegI(env);
2762 HReg tHi = newVRegI(env);
2763 MIPSAMode *am_addr;
2764
2765 /* CVTLS tmpD, valF */
2766 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2767 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
2768 set_MIPS_rounding_default(env);
2769
2770 sub_from_sp(env, 16); /* Move SP down 16 bytes */
2771 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2772
2773 /* store as F64 */
2774 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
2775 am_addr));
2776 /* load as 2xI32 */
2777#if defined (_MIPSEL)
2778 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2779 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2780 mode64));
2781#elif defined (_MIPSEB)
2782 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
2783 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
2784 mode64));
2785#endif
2786
2787 /* Reset SP */
2788 add_to_sp(env, 16);
2789
2790 *rHi = tHi;
2791 *rLo = tLo;
2792
2793 return;
2794 }
2795
sewardj362cf842012-06-07 08:59:53 +00002796 default:
2797 break;
2798 }
2799 }
2800
2801 /* --------- UNARY ops --------- */
2802 if (e->tag == Iex_Unop) {
sewardj362cf842012-06-07 08:59:53 +00002803 switch (e->Iex.Unop.op) {
2804 case Iop_1Sto64: {
2805 HReg tLo = newVRegI(env);
2806 HReg tHi = newVRegI(env);
2807 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2808 HReg tmp = newVRegI(env);
2809
2810 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src,
2811 MIPSRH_Imm(False, 31)));
dejanj781f1bd2013-10-23 14:05:15 +00002812 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
sewardj362cf842012-06-07 08:59:53 +00002813 MIPSRH_Imm(False, 31)));
2814
2815 addInstr(env, mk_iMOVds_RR(tHi, tmp));
2816 addInstr(env, mk_iMOVds_RR(tLo, tmp));
2817
2818 *rHi = tHi;
2819 *rLo = tLo;
2820 return;
2821 }
2822
2823 /* 32Sto64(e) */
2824 case Iop_32Sto64: {
2825 HReg tLo = newVRegI(env);
2826 HReg tHi = newVRegI(env);
2827 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2828 addInstr(env, mk_iMOVds_RR(tHi, src));
2829 addInstr(env, mk_iMOVds_RR(tLo, src));
2830 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi,
2831 MIPSRH_Imm(False, 31)));
2832 *rHi = tHi;
2833 *rLo = tLo;
2834 return;
2835 }
2836
petarja8e327d2013-07-04 00:39:37 +00002837 /* 8Uto64(e) */
2838 case Iop_8Uto64: {
2839 HReg tLo = newVRegI(env);
2840 HReg tHi = newVRegI(env);
2841 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2842 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo, src,
2843 MIPSRH_Imm(False, 0xFF)));
2844 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2845 MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2846 *rHi = tHi;
2847 *rLo = tLo;
2848 return;
2849 }
2850
sewardj362cf842012-06-07 08:59:53 +00002851 /* 32Uto64(e) */
2852 case Iop_32Uto64: {
2853 HReg tLo = newVRegI(env);
2854 HReg tHi = newVRegI(env);
2855 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2856 addInstr(env, mk_iMOVds_RR(tLo, src));
2857 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2858 MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2859 *rHi = tHi;
2860 *rLo = tLo;
2861 return;
2862 }
dejanjc3fee0d2013-07-25 09:08:03 +00002863
2864 case Iop_Left64: {
dejanj781f1bd2013-10-23 14:05:15 +00002865 HReg yHi, yLo;
dejanjc3fee0d2013-07-25 09:08:03 +00002866 HReg tHi = newVRegI(env);
2867 HReg tLo = newVRegI(env);
dejanj781f1bd2013-10-23 14:05:15 +00002868 HReg tmp = newVRegI(env);
2869 HReg tmp1 = newVRegI(env);
2870 HReg tmp2 = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002871 HReg zero = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002872 MIPSCondCode cc = MIPScc_LO;
2873
dejanjc3fee0d2013-07-25 09:08:03 +00002874 /* yHi:yLo = arg */
2875 iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
2876 /* zero = 0 */
2877 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2878
dejanj781f1bd2013-10-23 14:05:15 +00002879 /* tmp2:tmp1 = 0 - (yHi:yLo)*/
2880 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, zero, MIPSRH_Reg(yLo)));
2881 addInstr(env, MIPSInstr_Cmp(False, True, tmp1, zero, tmp2, cc));
2882 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, zero, MIPSRH_Reg(yHi)));
2883 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp1, tmp, MIPSRH_Reg(tmp1)));
dejanjc3fee0d2013-07-25 09:08:03 +00002884
dejanj781f1bd2013-10-23 14:05:15 +00002885 /* So now we have tmp2:tmp1 = -arg. To finish off, or 'arg'
dejanjc3fee0d2013-07-25 09:08:03 +00002886 back in, so as to give the final result
2887 tHi:tLo = arg | -arg. */
dejanj781f1bd2013-10-23 14:05:15 +00002888 addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, yHi, MIPSRH_Reg(tmp1)));
2889 addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, yLo, MIPSRH_Reg(tmp2)));
dejanjc3fee0d2013-07-25 09:08:03 +00002890 *rHi = tHi;
2891 *rLo = tLo;
2892 return;
2893 }
2894
sewardj362cf842012-06-07 08:59:53 +00002895 case Iop_CmpwNEZ64: {
2896 HReg srcLo, srcHi;
2897 HReg tmp1 = newVRegI(env);
2898 HReg tmp2 = newVRegI(env);
2899 /* srcHi:srcLo = arg */
2900 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
2901 /* tmp1 = srcHi | srcLo */
2902 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo,
2903 MIPSRH_Reg(srcHi)));
2904 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2905
2906 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
2907 MIPSRH_Reg(tmp1)));
2908
2909 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
2910 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2,
2911 MIPSRH_Imm(False, 31)));
2912 *rHi = tmp2;
2913 *rLo = tmp2;
2914 return;
2915
2916 }
2917 case Iop_ReinterpF64asI64: {
2918 HReg tLo = newVRegI(env);
2919 HReg tHi = newVRegI(env);
2920 MIPSAMode *am_addr;
2921 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
2922
petarjb92a9542013-02-27 22:57:17 +00002923 sub_from_sp(env, 16); /* Move SP down 16 bytes */
sewardj362cf842012-06-07 08:59:53 +00002924 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2925
petarjb92a9542013-02-27 22:57:17 +00002926 /* store as F64 */
sewardj362cf842012-06-07 08:59:53 +00002927 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
2928 am_addr));
petarjb92a9542013-02-27 22:57:17 +00002929 /* load as 2xI32 */
petarj0c30de82013-04-19 12:35:00 +00002930#if defined (_MIPSEL)
sewardj362cf842012-06-07 08:59:53 +00002931 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2932 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2933 mode64));
petarj0c30de82013-04-19 12:35:00 +00002934#elif defined (_MIPSEB)
2935 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
2936 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
2937 mode64));
2938#endif
sewardj362cf842012-06-07 08:59:53 +00002939
petarjb92a9542013-02-27 22:57:17 +00002940 /* Reset SP */
2941 add_to_sp(env, 16);
sewardj362cf842012-06-07 08:59:53 +00002942
2943 *rHi = tHi;
2944 *rLo = tLo;
2945 return;
2946 }
petarjb92a9542013-02-27 22:57:17 +00002947
Elliott Hughesed398002017-06-21 14:41:24 -07002948 case Iop_Not64: {
2949 HReg tLo = newVRegI(env);
2950 HReg tHi = newVRegI(env);
2951 iselInt64Expr(&tHi, &tLo, env, e->Iex.Unop.arg);
2952 addInstr(env, MIPSInstr_Alu(Malu_NOR, tLo, tLo, MIPSRH_Reg(tLo)));
2953 addInstr(env, MIPSInstr_Alu(Malu_NOR, tHi, tHi, MIPSRH_Reg(tHi)));
2954
2955 *rHi = tHi;
2956 *rLo = tLo;
2957
2958 return;
2959 }
2960
sewardj362cf842012-06-07 08:59:53 +00002961 default:
2962 vex_printf("UNARY: No such op: ");
2963 ppIROp(e->Iex.Unop.op);
2964 vex_printf("\n");
2965 break;
2966 }
2967 }
2968
2969 vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag);
2970 ppIRExpr(e);
2971 vpanic("iselInt64Expr(mips)");
2972}
2973
2974/*---------------------------------------------------------*/
2975/*--- ISEL: Floating point expressions (32 bit) ---*/
2976/*---------------------------------------------------------*/
2977
2978/* Nothing interesting here; really just wrappers for
2979 64-bit stuff. */
sewardj362cf842012-06-07 08:59:53 +00002980static HReg iselFltExpr(ISelEnv * env, IRExpr * e)
2981{
2982 HReg r = iselFltExpr_wrk(env, e);
2983 vassert(hregIsVirtual(r));
2984 return r;
2985}
2986
2987/* DO NOT CALL THIS DIRECTLY */
2988static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
2989{
2990 IRType ty = typeOfIRExpr(env->type_env, e);
dejanj0e006f22014-02-19 11:56:29 +00002991 vassert(ty == Ity_F32 || (ty == Ity_F64 && fp_mode64));
sewardj362cf842012-06-07 08:59:53 +00002992
2993 if (e->tag == Iex_RdTmp) {
2994 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2995 }
2996
2997 if (e->tag == Iex_Load) {
sewardj362cf842012-06-07 08:59:53 +00002998 vassert(e->Iex.Load.ty == Ity_F32
dejanj0e006f22014-02-19 11:56:29 +00002999 || (e->Iex.Load.ty == Ity_F64 && fp_mode64));
3000 HReg r_dst;
3001 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
3002 if (e->Iex.Load.ty == Ity_F64) {
3003 r_dst = newVRegD(env);
petarjb92a9542013-02-27 22:57:17 +00003004 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003005 } else {
3006 r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003007 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003008 }
sewardj362cf842012-06-07 08:59:53 +00003009 return r_dst;
3010 }
3011
3012 if (e->tag == Iex_Get) {
sewardj362cf842012-06-07 08:59:53 +00003013 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
3014 GuestStatePointer(mode64));
dejanj0e006f22014-02-19 11:56:29 +00003015 HReg r_dst;
3016 if (e->Iex.Load.ty == Ity_F64) {
3017 r_dst = newVRegD(env);
petarjb92a9542013-02-27 22:57:17 +00003018 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003019 } else {
3020 r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003021 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003022 }
sewardj362cf842012-06-07 08:59:53 +00003023 return r_dst;
3024 }
3025
3026 if (e->tag == Iex_Unop) {
3027 switch (e->Iex.Unop.op) {
3028 case Iop_ReinterpI32asF32: {
sewardj362cf842012-06-07 08:59:53 +00003029 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3030 HReg r_dst = newVRegF(env);
3031
petarjb92a9542013-02-27 22:57:17 +00003032 /* Move Word to Floating Point
3033 mtc1 r_dst, valS */
3034 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, fr_src));
sewardj362cf842012-06-07 08:59:53 +00003035
sewardj362cf842012-06-07 08:59:53 +00003036 return r_dst;
sewardj362cf842012-06-07 08:59:53 +00003037 }
3038 case Iop_F32toF64: {
dejanj0e006f22014-02-19 11:56:29 +00003039 vassert(fp_mode64);
dejanja759d172013-09-19 13:35:45 +00003040 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3041 HReg dst = newVRegD(env);
sewardj362cf842012-06-07 08:59:53 +00003042
dejanja759d172013-09-19 13:35:45 +00003043 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
3044 return dst;
petarjb92a9542013-02-27 22:57:17 +00003045 }
3046 case Iop_ReinterpI64asF64: {
dejanj0e006f22014-02-19 11:56:29 +00003047 HReg r_dst;
3048 if (mode64) {
3049 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3050 r_dst = newVRegF(env);
3051 /* Move Doubleword to Floating Point
3052 dmtc1 r_dst, fr_src */
3053 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src));
3054 } else {
3055 HReg Hi, Lo;
3056 r_dst = newVRegD(env);
3057 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
3058 r_dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
3059 }
dejanja759d172013-09-19 13:35:45 +00003060 return r_dst;
3061 }
petarjb92a9542013-02-27 22:57:17 +00003062 case Iop_I32StoF64: {
dejanj0e006f22014-02-19 11:56:29 +00003063 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003064 HReg dst = newVRegF(env);
dejanja759d172013-09-19 13:35:45 +00003065 HReg tmp = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003066 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
petarjb92a9542013-02-27 22:57:17 +00003067
3068 /* Move Word to Floating Point
dejanj0e006f22014-02-19 11:56:29 +00003069 mtc1 tmp, r_src */
dejanja759d172013-09-19 13:35:45 +00003070 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
petarjb92a9542013-02-27 22:57:17 +00003071
3072 /* and do convert */
dejanja759d172013-09-19 13:35:45 +00003073 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
petarjb92a9542013-02-27 22:57:17 +00003074
3075 return dst;
3076 }
sewardj362cf842012-06-07 08:59:53 +00003077 case Iop_AbsF32:
3078 case Iop_AbsF64: {
3079 Bool sz32 = e->Iex.Unop.op == Iop_AbsF32;
3080 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3081 HReg dst = newVRegF(env);
3082 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src));
3083 return dst;
3084 }
3085 case Iop_NegF32:
3086 case Iop_NegF64: {
3087 Bool sz32 = e->Iex.Unop.op == Iop_NegF32;
3088 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3089 HReg dst = newVRegF(env);
3090 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src));
3091 return dst;
3092 }
petarjb92a9542013-02-27 22:57:17 +00003093 case Iop_RoundF64toF64_ZERO: {
3094 vassert(mode64);
3095 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3096 HReg dst = newVRegF(env);
3097 addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, dst, src));
3098 return dst;
3099 }
dejanj3bc88cc2013-10-07 10:28:56 +00003100 case Iop_RoundF64toF64_NEAREST: {
3101 vassert(mode64);
3102 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3103 HReg dst = newVRegF(env);
3104 addInstr(env, MIPSInstr_FpConvert(Mfp_ROUNDLD, dst, src));
3105 return dst;
3106 }
3107 case Iop_RoundF64toF64_NegINF: {
3108 vassert(mode64);
3109 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3110 HReg dst = newVRegF(env);
3111 addInstr(env, MIPSInstr_FpConvert(Mfp_FLOORLD, dst, src));
3112 return dst;
3113 }
3114 case Iop_RoundF64toF64_PosINF: {
3115 vassert(mode64);
3116 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3117 HReg dst = newVRegF(env);
3118 addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, dst, src));
3119 return dst;
3120 }
3121
sewardj362cf842012-06-07 08:59:53 +00003122 default:
3123 break;
3124 }
3125 }
3126
3127 if (e->tag == Iex_Triop) {
3128 switch (e->Iex.Triop.details->op) {
3129 case Iop_DivF32:
3130 case Iop_DivF64:
3131 case Iop_MulF32:
3132 case Iop_MulF64:
3133 case Iop_AddF32:
3134 case Iop_AddF64:
3135 case Iop_SubF32:
3136 case Iop_SubF64: {
3137 MIPSFpOp op = 0;
dejanja759d172013-09-19 13:35:45 +00003138 HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2);
sewardj362cf842012-06-07 08:59:53 +00003139 HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3);
3140 HReg dst = newVRegF(env);
3141 switch (e->Iex.Triop.details->op) {
3142 case Iop_DivF32:
3143 op = Mfp_DIVS;
3144 break;
petarjb92a9542013-02-27 22:57:17 +00003145 case Iop_DivF64:
dejanj0e006f22014-02-19 11:56:29 +00003146 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003147 op = Mfp_DIVD;
3148 break;
sewardj362cf842012-06-07 08:59:53 +00003149 case Iop_MulF32:
3150 op = Mfp_MULS;
3151 break;
petarjb92a9542013-02-27 22:57:17 +00003152 case Iop_MulF64:
dejanj0e006f22014-02-19 11:56:29 +00003153 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003154 op = Mfp_MULD;
3155 break;
sewardj362cf842012-06-07 08:59:53 +00003156 case Iop_AddF32:
3157 op = Mfp_ADDS;
3158 break;
petarjb92a9542013-02-27 22:57:17 +00003159 case Iop_AddF64:
dejanj0e006f22014-02-19 11:56:29 +00003160 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003161 op = Mfp_ADDD;
3162 break;
sewardj362cf842012-06-07 08:59:53 +00003163 case Iop_SubF32:
3164 op = Mfp_SUBS;
3165 break;
petarjb92a9542013-02-27 22:57:17 +00003166 case Iop_SubF64:
dejanj0e006f22014-02-19 11:56:29 +00003167 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003168 op = Mfp_SUBD;
3169 break;
sewardj362cf842012-06-07 08:59:53 +00003170 default:
3171 vassert(0);
3172 }
petarjb92a9542013-02-27 22:57:17 +00003173 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
sewardj362cf842012-06-07 08:59:53 +00003174 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
petarjb92a9542013-02-27 22:57:17 +00003175 set_MIPS_rounding_default(env);
sewardj362cf842012-06-07 08:59:53 +00003176 return dst;
3177 }
3178 default:
3179 break;
3180 }
3181 }
3182
3183 if (e->tag == Iex_Binop) {
3184 switch (e->Iex.Binop.op) {
3185 case Iop_F64toF32: {
petarjb92a9542013-02-27 22:57:17 +00003186 HReg valD;
3187 if (mode64)
3188 valD = iselFltExpr(env, e->Iex.Binop.arg2);
3189 else
3190 valD = iselDblExpr(env, e->Iex.Binop.arg2);
sewardj362cf842012-06-07 08:59:53 +00003191 HReg valS = newVRegF(env);
3192
3193 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3194 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD));
3195 set_MIPS_rounding_default(env);
3196 return valS;
3197 }
3198
3199 case Iop_RoundF32toInt: {
3200 HReg valS = newVRegF(env);
3201 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
3202
3203 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3204 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
sewardj362cf842012-06-07 08:59:53 +00003205 set_MIPS_rounding_default(env);
3206 return valS;
3207 }
3208
petarjb92a9542013-02-27 22:57:17 +00003209 case Iop_RoundF64toInt: {
3210 HReg valS = newVRegF(env);
3211 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
3212
3213 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3214 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, valS, valF));
3215 set_MIPS_rounding_default(env);
3216 return valS;
3217 }
3218
sewardj362cf842012-06-07 08:59:53 +00003219 case Iop_I32StoF32: {
3220 HReg r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003221 HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3222 HReg tmp = newVRegF(env);
3223
3224 /* Move Word to Floating Point
3225 mtc1 tmp, fr_src */
3226 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, fr_src));
3227
3228 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3229 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp));
3230 set_MIPS_rounding_default(env);
3231
3232 return r_dst;
3233 }
3234
3235 case Iop_I64StoF64: {
3236 HReg r_dst = newVRegF(env);
sewardj362cf842012-06-07 08:59:53 +00003237 MIPSAMode *am_addr;
dejanj0e006f22014-02-19 11:56:29 +00003238 HReg tmp, fr_src;
3239 if (mode64) {
3240 tmp = newVRegF(env);
3241 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3242 /* Move SP down 8 bytes */
3243 sub_from_sp(env, 8);
3244 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
sewardj362cf842012-06-07 08:59:53 +00003245
dejanj0e006f22014-02-19 11:56:29 +00003246 /* store as I64 */
3247 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
sewardj362cf842012-06-07 08:59:53 +00003248
dejanj0e006f22014-02-19 11:56:29 +00003249 /* load as Ity_F64 */
3250 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
sewardj362cf842012-06-07 08:59:53 +00003251
dejanj0e006f22014-02-19 11:56:29 +00003252 /* Reset SP */
3253 add_to_sp(env, 8);
3254 } else {
3255 HReg Hi, Lo;
3256 tmp = newVRegD(env);
3257 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
3258 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
3259 }
sewardj362cf842012-06-07 08:59:53 +00003260
3261 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
petarjb92a9542013-02-27 22:57:17 +00003262 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
3263 set_MIPS_rounding_default(env);
3264
3265 return r_dst;
3266 }
3267
3268 case Iop_I64StoF32: {
3269 HReg r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003270 MIPSAMode *am_addr;
dejanj0e006f22014-02-19 11:56:29 +00003271 HReg fr_src, tmp;
3272 if (mode64) {
3273 tmp = newVRegF(env);
3274 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3275 /* Move SP down 8 bytes */
3276 sub_from_sp(env, 8);
3277 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
petarjb92a9542013-02-27 22:57:17 +00003278
dejanj0e006f22014-02-19 11:56:29 +00003279 /* store as I64 */
3280 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
petarjb92a9542013-02-27 22:57:17 +00003281
dejanj0e006f22014-02-19 11:56:29 +00003282 /* load as Ity_F64 */
3283 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
petarjb92a9542013-02-27 22:57:17 +00003284
dejanj0e006f22014-02-19 11:56:29 +00003285 /* Reset SP */
3286 add_to_sp(env, 8);
3287 } else {
3288 HReg Hi, Lo;
3289 tmp = newVRegD(env);
3290 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
3291 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
3292 }
petarjb92a9542013-02-27 22:57:17 +00003293
3294 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3295 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSL, r_dst, tmp));
sewardj362cf842012-06-07 08:59:53 +00003296 set_MIPS_rounding_default(env);
3297
3298 return r_dst;
3299 }
3300
3301 case Iop_SqrtF32:
3302 case Iop_SqrtF64: {
sewardj362cf842012-06-07 08:59:53 +00003303 Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32;
3304 HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
3305 HReg dst = newVRegF(env);
3306 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3307 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst,
3308 src));
3309 set_MIPS_rounding_default(env);
3310 return dst;
3311 }
petarjb92a9542013-02-27 22:57:17 +00003312
sewardj362cf842012-06-07 08:59:53 +00003313 default:
3314 break;
3315 }
3316 }
3317
petarjb92a9542013-02-27 22:57:17 +00003318 if (e->tag == Iex_Qop) {
3319 switch (e->Iex.Qop.details->op) {
3320 case Iop_MAddF32:
3321 case Iop_MAddF64:
3322 case Iop_MSubF32:
3323 case Iop_MSubF64: {
3324 MIPSFpOp op = 0;
3325 switch (e->Iex.Qop.details->op) {
3326 case Iop_MAddF32:
3327 op = Mfp_MADDS;
3328 break;
3329 case Iop_MAddF64:
3330 op = Mfp_MADDD;
3331 break;
3332 case Iop_MSubF32:
3333 op = Mfp_MSUBS;
3334 break;
3335 case Iop_MSubF64:
3336 op = Mfp_MSUBD;
3337 break;
3338 default:
3339 vassert(0);
3340 }
3341 HReg dst = newVRegF(env);
3342 HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2);
3343 HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3);
3344 HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4);
3345 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
3346 addInstr(env, MIPSInstr_FpTernary(op, dst,
3347 src1, src2, src3));
3348 set_MIPS_rounding_default(env);
3349 return dst;
3350 }
3351
3352 default:
3353 break;
3354 }
3355 }
3356
sewardj362cf842012-06-07 08:59:53 +00003357 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3358 /* This is quite subtle. The only way to do the relevant
3359 truncation is to do a single-precision store and then a
3360 double precision load to get it back into a register. The
3361 problem is, if the data is then written to memory a second
3362 time, as in
3363
3364 STbe(...) = TruncF64asF32(...)
3365
3366 then will the second truncation further alter the value? The
3367 answer is no: flds (as generated here) followed by fsts
3368 (generated for the STbe) is the identity function on 32-bit
3369 floats, so we are safe.
3370
3371 Another upshot of this is that if iselStmt can see the
3372 entirety of
3373
3374 STbe(...) = TruncF64asF32(arg)
3375
3376 then it can short circuit having to deal with TruncF64asF32
3377 individually; instead just compute arg into a 64-bit FP
3378 register and do 'fsts' (since that itself does the
3379 truncation).
3380
3381 We generate pretty poor code here (should be ok both for
3382 32-bit and 64-bit mode); but it is expected that for the most
3383 part the latter optimisation will apply and hence this code
3384 will not often be used.
3385 */
3386 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
3387 HReg fdst = newVRegF(env);
3388 MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64));
3389
3390 sub_from_sp(env, 16);
petarjb92a9542013-02-27 22:57:17 +00003391 /* store as F32, hence truncating */
sewardj362cf842012-06-07 08:59:53 +00003392 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1));
petarjb92a9542013-02-27 22:57:17 +00003393 /* and reload. Good huh?! (sigh) */
sewardj362cf842012-06-07 08:59:53 +00003394 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1));
3395 add_to_sp(env, 16);
3396 return fdst;
3397 }
3398
petarjb92a9542013-02-27 22:57:17 +00003399 /* --------- ITE --------- */
3400 if (e->tag == Iex_ITE) {
Elliott Hughesed398002017-06-21 14:41:24 -07003401 vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1);
3402 HReg r0 = iselFltExpr(env, e->Iex.ITE.iffalse);
3403 HReg r1 = iselFltExpr(env, e->Iex.ITE.iftrue);
3404 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
3405 HReg r_dst = newVRegF(env);
3406 addInstr(env, MIPSInstr_FpUnary((ty == Ity_F64) ? Mfp_MOVD : Mfp_MOVS,
3407 r_dst, r0));
3408 addInstr(env, MIPSInstr_MoveCond((ty == Ity_F64) ? MFpMoveCond_movnd :
3409 MFpMoveCond_movns,
3410 r_dst, r1, r_cond));
3411 return r_dst;
petarjb92a9542013-02-27 22:57:17 +00003412 }
3413
sewardj362cf842012-06-07 08:59:53 +00003414 vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag);
3415 ppIRExpr(e);
3416 vpanic("iselFltExpr_wrk(mips)");
3417}
3418
3419static HReg iselDblExpr(ISelEnv * env, IRExpr * e)
3420{
3421 HReg r = iselDblExpr_wrk(env, e);
3422 vassert(hregClass(r) == HRcFlt64);
3423 vassert(hregIsVirtual(r));
3424 return r;
3425}
3426
3427/* DO NOT CALL THIS DIRECTLY */
3428static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e)
3429{
3430 IRType ty = typeOfIRExpr(env->type_env, e);
3431 vassert(e);
3432 vassert(ty == Ity_F64);
3433
3434 if (e->tag == Iex_RdTmp) {
3435 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3436 }
3437
3438 /* --------- LOAD --------- */
petarjbe927ba2012-09-09 01:10:59 +00003439 if (e->tag == Iex_Load) {
sewardj362cf842012-06-07 08:59:53 +00003440 HReg r_dst = newVRegD(env);
3441 MIPSAMode *am_addr;
3442 vassert(e->Iex.Load.ty == Ity_F64);
3443 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
3444 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
3445 return r_dst;
3446 }
3447
3448 /* --------- GET --------- */
3449 if (e->tag == Iex_Get) {
3450
3451 HReg r_dst = newVRegD(env);
3452 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
3453 GuestStatePointer(mode64));
3454 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
3455 return r_dst;
3456 }
3457
3458 if (e->tag == Iex_Unop) {
3459 MIPSFpOp fpop = Mfp_INVALID;
3460 switch (e->Iex.Unop.op) {
3461 case Iop_NegF64:
3462 fpop = Mfp_NEGD;
3463 break;
3464 case Iop_AbsF64:
3465 fpop = Mfp_ABSD;
3466 break;
3467 case Iop_F32toF64: {
petarjb92a9542013-02-27 22:57:17 +00003468 vassert(!mode64);
sewardj362cf842012-06-07 08:59:53 +00003469 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3470 HReg dst = newVRegD(env);
3471
petarjb92a9542013-02-27 22:57:17 +00003472 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
sewardj362cf842012-06-07 08:59:53 +00003473 return dst;
3474 }
3475 case Iop_ReinterpI64asF64: {
dejanja759d172013-09-19 13:35:45 +00003476 HReg Hi, Lo;
sewardj362cf842012-06-07 08:59:53 +00003477 HReg dst = newVRegD(env);
3478
3479 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
3480
petarjb92a9542013-02-27 22:57:17 +00003481 dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
sewardj362cf842012-06-07 08:59:53 +00003482 return dst;
3483 }
3484 case Iop_I32StoF64: {
petarjb92a9542013-02-27 22:57:17 +00003485 vassert(!mode64);
sewardj362cf842012-06-07 08:59:53 +00003486 HReg dst = newVRegD(env);
dejanja759d172013-09-19 13:35:45 +00003487 HReg tmp = newVRegF(env);
sewardj362cf842012-06-07 08:59:53 +00003488 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
sewardj362cf842012-06-07 08:59:53 +00003489
petarjb92a9542013-02-27 22:57:17 +00003490 /* Move Word to Floating Point
dejanja759d172013-09-19 13:35:45 +00003491 mtc1 tmp, r_src */
3492 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
sewardj362cf842012-06-07 08:59:53 +00003493
petarjb92a9542013-02-27 22:57:17 +00003494 /* and do convert */
dejanja759d172013-09-19 13:35:45 +00003495 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
sewardj362cf842012-06-07 08:59:53 +00003496
3497 return dst;
3498 }
3499 default:
3500 break;
3501 }
3502
3503 if (fpop != Mfp_INVALID) {
3504 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
3505 HReg dst = newVRegD(env);
3506 addInstr(env, MIPSInstr_FpUnary(fpop, dst, src));
3507 return dst;
3508 }
3509 }
3510
3511 if (e->tag == Iex_Binop) {
3512 switch (e->Iex.Binop.op) {
3513 case Iop_RoundF64toInt: {
dejanj0e006f22014-02-19 11:56:29 +00003514 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3515 HReg dst = newVRegD(env);
sewardj362cf842012-06-07 08:59:53 +00003516
dejanj0e006f22014-02-19 11:56:29 +00003517 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3518 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src));
3519 set_MIPS_rounding_default(env);
3520
3521 return dst;
sewardj362cf842012-06-07 08:59:53 +00003522 }
3523
dejanj3bc88cc2013-10-07 10:28:56 +00003524 case Iop_SqrtF64: {
sewardj362cf842012-06-07 08:59:53 +00003525 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3526 HReg dst = newVRegD(env);
dejanj41833222013-11-14 15:44:42 +00003527 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
sewardj362cf842012-06-07 08:59:53 +00003528 addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src));
dejanj41833222013-11-14 15:44:42 +00003529 set_MIPS_rounding_default(env);
sewardj362cf842012-06-07 08:59:53 +00003530 return dst;
3531 }
3532
3533 default:
3534 break;
3535
3536 }
3537 }
3538
3539 if (e->tag == Iex_Triop) {
3540 switch (e->Iex.Triop.details->op) {
3541 case Iop_DivF64:
3542 case Iop_DivF32:
3543 case Iop_MulF64:
3544 case Iop_AddF64:
3545 case Iop_SubF64: {
3546 MIPSFpOp op = 0;
dejanja759d172013-09-19 13:35:45 +00003547 HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2);
sewardj362cf842012-06-07 08:59:53 +00003548 HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3);
3549 HReg dst = newVRegD(env);
3550 switch (e->Iex.Triop.details->op) {
3551 case Iop_DivF64:
3552 op = Mfp_DIVD;
3553 break;
dejanj41833222013-11-14 15:44:42 +00003554 case Iop_DivF32:
3555 op = Mfp_DIVS;
3556 break;
sewardj362cf842012-06-07 08:59:53 +00003557 case Iop_MulF64:
3558 op = Mfp_MULD;
3559 break;
3560 case Iop_AddF64:
3561 op = Mfp_ADDD;
3562 break;
3563 case Iop_SubF64:
3564 op = Mfp_SUBD;
3565 break;
3566 default:
3567 vassert(0);
3568 }
dejanj41833222013-11-14 15:44:42 +00003569 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
sewardj362cf842012-06-07 08:59:53 +00003570 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
dejanj41833222013-11-14 15:44:42 +00003571 set_MIPS_rounding_default(env);
sewardj362cf842012-06-07 08:59:53 +00003572 return dst;
3573 }
3574 default:
3575 break;
3576 }
3577 }
3578
petarjb92a9542013-02-27 22:57:17 +00003579 if (e->tag == Iex_Qop) {
3580 switch (e->Iex.Qop.details->op) {
3581 case Iop_MAddF32:
3582 case Iop_MAddF64:
3583 case Iop_MSubF32:
3584 case Iop_MSubF64: {
3585 MIPSFpOp op = 0;
3586 switch (e->Iex.Qop.details->op) {
3587 case Iop_MAddF32:
3588 op = Mfp_MADDS;
3589 break;
3590 case Iop_MAddF64:
3591 op = Mfp_MADDD;
3592 break;
3593 case Iop_MSubF32:
3594 op = Mfp_MSUBS;
3595 break;
3596 case Iop_MSubF64:
3597 op = Mfp_MSUBD;
3598 break;
3599 default:
3600 vassert(0);
3601 }
3602 HReg dst = newVRegD(env);
3603 HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2);
3604 HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3);
3605 HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4);
3606 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
3607 addInstr(env, MIPSInstr_FpTernary(op, dst,
3608 src1, src2, src3));
3609 set_MIPS_rounding_default(env);
3610 return dst;
3611 }
3612
3613 default:
3614 break;
3615 }
3616 }
3617
3618 /* --------- ITE --------- */
florian99dd03e2013-01-29 03:56:06 +00003619 if (e->tag == Iex_ITE) {
sewardj362cf842012-06-07 08:59:53 +00003620 if (ty == Ity_F64
petarjd4564182013-01-29 15:42:29 +00003621 && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
florian99dd03e2013-01-29 03:56:06 +00003622 HReg r0 = iselDblExpr(env, e->Iex.ITE.iffalse);
3623 HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue);
petarjb92a9542013-02-27 22:57:17 +00003624 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
sewardj362cf842012-06-07 08:59:53 +00003625 HReg r_dst = newVRegD(env);
sewardj362cf842012-06-07 08:59:53 +00003626
petarjb92a9542013-02-27 22:57:17 +00003627 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0));
3628 addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1,
3629 r_cond));
sewardj362cf842012-06-07 08:59:53 +00003630 return r_dst;
3631 }
3632 }
3633
3634 vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag);
3635 ppIRExpr(e);
3636 vpanic("iselDblExpr_wrk(mips)");
3637}
3638
3639/*---------------------------------------------------------*/
3640/*--- ISEL: Statements ---*/
3641/*---------------------------------------------------------*/
3642
3643static void iselStmt(ISelEnv * env, IRStmt * stmt)
3644{
3645 if (vex_traceflags & VEX_TRACE_VCODE) {
3646 vex_printf("\n-- ");
3647
3648 ppIRStmt(stmt);
3649 vex_printf("\n");
3650 }
3651
3652 switch (stmt->tag) {
3653 /* --------- STORE --------- */
3654 case Ist_Store: {
3655 MIPSAMode *am_addr;
3656 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3657
3658 /*constructs addressing mode from address provided */
3659 am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
3660
3661 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
3662 (mode64 && (tyd == Ity_I64))) {
3663 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
3664 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)),
3665 am_addr, r_src, mode64));
3666 return;
3667 }
3668 if (!mode64 && (tyd == Ity_I64)) {
3669 HReg vHi, vLo;
3670 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
3671
3672 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
3673
3674 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3675 MIPSAMode_IR(0, r_addr), vHi, mode64));
3676 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3677 MIPSAMode_IR(4, r_addr), vLo, mode64));
3678 return;
3679 }
3680 if (tyd == Ity_F32) {
3681 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3682 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
3683 am_addr));
3684 return;
3685 }
petarjb92a9542013-02-27 22:57:17 +00003686 if (tyd == Ity_F64 && mode64) {
3687 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3688 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3689 am_addr));
3690 return;
3691 }
petarj1ec43e02012-09-04 13:45:42 +00003692 if (!mode64 && (tyd == Ity_F64)) {
3693 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
3694 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3695 am_addr));
3696 return;
3697 }
3698
sewardj362cf842012-06-07 08:59:53 +00003699 break;
3700 }
3701
3702 /* --------- PUT --------- */
3703 case Ist_Put: {
3704 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
dejanjc3fee0d2013-07-25 09:08:03 +00003705
sewardj362cf842012-06-07 08:59:53 +00003706 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
3707 (ty == Ity_I64 && mode64)) {
3708 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
3709 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3710 GuestStatePointer(mode64));
3711 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)),
3712 am_addr, r_src, mode64));
3713 return;
3714 }
dejanjc3fee0d2013-07-25 09:08:03 +00003715
sewardj362cf842012-06-07 08:59:53 +00003716 if (ty == Ity_I64 && !mode64) {
3717 HReg vHi, vLo;
3718 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3719 GuestStatePointer(mode64));
3720 MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4,
3721 GuestStatePointer(mode64));
3722 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
3723 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3724 am_addr, vLo, mode64));
3725 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3726 am_addr4, vHi, mode64));
3727 return;
dejanjc3fee0d2013-07-25 09:08:03 +00003728
sewardj362cf842012-06-07 08:59:53 +00003729 }
dejanjc3fee0d2013-07-25 09:08:03 +00003730
sewardj362cf842012-06-07 08:59:53 +00003731 if (ty == Ity_F32) {
3732 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
3733 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3734 GuestStatePointer(mode64));
3735 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
3736 am_addr));
3737 return;
3738 }
dejanjc3fee0d2013-07-25 09:08:03 +00003739
sewardj362cf842012-06-07 08:59:53 +00003740 if (ty == Ity_F64) {
dejanja759d172013-09-19 13:35:45 +00003741 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
sewardj362cf842012-06-07 08:59:53 +00003742 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3743 GuestStatePointer(mode64));
3744 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3745 am_addr));
3746 return;
3747 }
3748 break;
3749 }
3750
3751 /* --------- TMP --------- */
3752 case Ist_WrTmp: {
3753 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3754 IRType ty = typeOfIRTemp(env->type_env, tmp);
3755
3756 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) {
3757 HReg r_dst = lookupIRTemp(env, tmp);
3758 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3759 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3760 return;
3761 }
3762
3763 if (ty == Ity_I64) {
petarjb92a9542013-02-27 22:57:17 +00003764 if (mode64) {
3765 HReg r_dst = lookupIRTemp(env, tmp);
3766 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3767 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3768 return;
3769 } else {
3770 HReg rHi, rLo, dstHi, dstLo;
3771 iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
3772 lookupIRTemp64(&dstHi, &dstLo, env, tmp);
3773 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3774 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3775 return;
3776 }
3777 }
3778
3779 if (mode64 && ty == Ity_I128) {
3780 HReg rHi, rLo, dstHi, dstLo;
3781 iselInt128Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
3782 lookupIRTempPair(&dstHi, &dstLo, env, tmp);
3783 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3784 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3785 return;
sewardj362cf842012-06-07 08:59:53 +00003786 }
3787
3788 if (ty == Ity_F32) {
3789 HReg fr_dst = lookupIRTemp(env, tmp);
3790 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
3791 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src));
3792 return;
3793 }
3794
3795 if (ty == Ity_F64) {
petarjb92a9542013-02-27 22:57:17 +00003796 if (mode64) {
3797 HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
3798 HReg dst = lookupIRTemp(env, tmp);
3799 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
3800 return;
3801 } else {
3802 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
3803 HReg dst = lookupIRTemp(env, tmp);
3804 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
3805 return;
3806 }
sewardj362cf842012-06-07 08:59:53 +00003807 }
3808 break;
3809 }
3810
3811 /* --------- Call to DIRTY helper --------- */
3812 case Ist_Dirty: {
sewardj362cf842012-06-07 08:59:53 +00003813 IRDirty *d = stmt->Ist.Dirty.details;
sewardj362cf842012-06-07 08:59:53 +00003814
sewardjcfe046e2013-01-17 14:23:53 +00003815 /* Figure out the return type, if any. */
3816 IRType retty = Ity_INVALID;
3817 if (d->tmp != IRTemp_INVALID)
3818 retty = typeOfIRTemp(env->type_env, d->tmp);
3819
sewardj74142b82013-08-08 10:28:59 +00003820 /* Throw out any return types we don't know about. */
3821 Bool retty_ok = False;
sewardjcfe046e2013-01-17 14:23:53 +00003822 switch (retty) {
sewardj74142b82013-08-08 10:28:59 +00003823 case Ity_INVALID: /* Function doesn't return anything. */
3824 case Ity_V128:
3825 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
3826 retty_ok = True; break;
sewardjcfe046e2013-01-17 14:23:53 +00003827 default:
3828 break;
3829 }
sewardj74142b82013-08-08 10:28:59 +00003830
3831 if (!retty_ok)
sewardjcfe046e2013-01-17 14:23:53 +00003832 break; /* will go to stmt_fail: */
3833
sewardj74142b82013-08-08 10:28:59 +00003834 /* Marshal args, do the call, clear stack, set the return value
3835 to 0x555..555 if this is a conditional call that returns a
3836 value and the call is skipped. */
3837 UInt addToSp = 0;
3838 RetLoc rloc = mk_RetLoc_INVALID();
3839 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
3840 vassert(is_sane_RetLoc(rloc));
sewardj362cf842012-06-07 08:59:53 +00003841
3842 /* Now figure out what to do with the returned value, if any. */
sewardj74142b82013-08-08 10:28:59 +00003843 switch (retty) {
3844 case Ity_INVALID: {
3845 /* No return value. Nothing to do. */
3846 vassert(d->tmp == IRTemp_INVALID);
3847 vassert(rloc.pri == RLPri_None);
3848 vassert(addToSp == 0);
3849 return;
3850 }
3851 case Ity_I32: case Ity_I16: case Ity_I8: {
3852 /* The returned value is in $v0. Park it in the register
3853 associated with tmp. */
3854 HReg r_dst = lookupIRTemp(env, d->tmp);
Elliott Hughesed398002017-06-21 14:41:24 -07003855 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_dst,
3856 hregMIPS_GPR2(mode64),
3857 MIPSRH_Imm(False, 0)));
sewardj74142b82013-08-08 10:28:59 +00003858 vassert(rloc.pri == RLPri_Int);
3859 vassert(addToSp == 0);
3860 return;
3861 }
3862 case Ity_I64: {
3863 if (mode64) {
3864 /* The returned value is in $v0. Park it in the register
3865 associated with tmp. */
3866 HReg r_dst = lookupIRTemp(env, d->tmp);
3867 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
3868 vassert(rloc.pri == RLPri_Int);
3869 vassert(addToSp == 0);
3870 return;
3871 } else {
3872 HReg rHi = newVRegI(env);
3873 HReg rLo = newVRegI(env);
3874 HReg dstHi, dstLo;
3875 addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64)));
3876 addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64)));
3877 lookupIRTemp64(&dstHi, &dstLo, env, d->tmp);
3878 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3879 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3880 return;
3881 }
3882 }
3883 case Ity_V128: {
3884 /* ATC. The code that this produces really
3885 needs to be looked at, to verify correctness.
3886 I don't think this can ever happen though, since the
3887 MIPS front end never produces 128-bit loads/stores. */
3888 vassert(0);
3889 vassert(rloc.pri == RLPri_V128SpRel);
3890 vassert(addToSp >= 16);
3891 HReg dst = lookupIRTemp(env, d->tmp);
3892 MIPSAMode* am = MIPSAMode_IR(rloc.spOff, StackPointer(mode64));
3893 addInstr(env, MIPSInstr_Load(mode64 ? 8 : 4, dst, am, mode64));
3894 add_to_sp(env, addToSp);
3895 return;
sewardj362cf842012-06-07 08:59:53 +00003896
sewardj74142b82013-08-08 10:28:59 +00003897 }
3898 default:
3899 /*NOTREACHED*/
3900 vassert(0);
sewardj362cf842012-06-07 08:59:53 +00003901 }
sewardj362cf842012-06-07 08:59:53 +00003902 }
3903
3904 /* --------- Load Linked or Store Conditional --------- */
3905 case Ist_LLSC: {
petarjb92a9542013-02-27 22:57:17 +00003906 /* Temporary solution; this need to be rewritten again for MIPS.
3907 On MIPS you can not read from address that is locked with LL
3908 before SC. If you read from address that is locked than SC will
3909 fall. */
sewardj362cf842012-06-07 08:59:53 +00003910 IRTemp res = stmt->Ist.LLSC.result;
3911 IRType tyRes = typeOfIRTemp(env->type_env, res);
3912 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
3913
3914 if (!mode64 && (tyAddr != Ity_I32))
3915 goto stmt_fail;
3916
3917 if (stmt->Ist.LLSC.storedata == NULL) {
3918 /* LL */
3919 MIPSAMode *r_addr;
petarjb92a9542013-02-27 22:57:17 +00003920 /* constructs addressing mode from address provided */
sewardj362cf842012-06-07 08:59:53 +00003921 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
3922
3923 HReg r_dst = lookupIRTemp(env, res);
3924 if (tyRes == Ity_I32) {
petarj1e994b92012-11-23 00:44:37 +00003925 addInstr(env, MIPSInstr_LoadL(4, r_dst, r_addr, mode64));
sewardj362cf842012-06-07 08:59:53 +00003926 return;
3927 } else if (tyRes == Ity_I64 && mode64) {
petarj1e994b92012-11-23 00:44:37 +00003928 addInstr(env, MIPSInstr_LoadL(8, r_dst, r_addr, mode64));
sewardj362cf842012-06-07 08:59:53 +00003929 return;
3930 }
sewardj362cf842012-06-07 08:59:53 +00003931 } else {
3932 /* SC */
3933 MIPSAMode *r_addr;
3934 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
3935 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
3936 HReg r_dst = lookupIRTemp(env, res);
dejanjc3fee0d2013-07-25 09:08:03 +00003937 IRType tyData = typeOfIRExpr(env->type_env,
sewardj362cf842012-06-07 08:59:53 +00003938 stmt->Ist.LLSC.storedata);
3939
3940 if (tyData == Ity_I32) {
petarj1e994b92012-11-23 00:44:37 +00003941 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3942 addInstr(env, MIPSInstr_StoreC(4, r_addr, r_dst, mode64));
sewardj362cf842012-06-07 08:59:53 +00003943 return;
3944 } else if (tyData == Ity_I64 && mode64) {
petarj1e994b92012-11-23 00:44:37 +00003945 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3946 addInstr(env, MIPSInstr_StoreC(8, r_addr, r_dst, mode64));
sewardj362cf842012-06-07 08:59:53 +00003947 return;
3948 }
sewardj362cf842012-06-07 08:59:53 +00003949 }
3950 goto stmt_fail;
petarjb92a9542013-02-27 22:57:17 +00003951 /* NOTREACHED */}
sewardj362cf842012-06-07 08:59:53 +00003952
dejanj6ced72b2014-06-04 11:28:07 +00003953 case Ist_CAS:
3954 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3955 IRCAS *cas = stmt->Ist.CAS.details;
3956 HReg old = lookupIRTemp(env, cas->oldLo);
3957 HReg addr = iselWordExpr_R(env, cas->addr);
3958 HReg expd = iselWordExpr_R(env, cas->expdLo);
3959 HReg data = iselWordExpr_R(env, cas->dataLo);
3960 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) {
3961 addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64));
3962 } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3963 addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64));
3964 }
3965 }
petarj67ec22c2014-10-09 01:19:34 +00003966 return;
dejanj6ced72b2014-06-04 11:28:07 +00003967
petarjb92a9542013-02-27 22:57:17 +00003968 /* --------- INSTR MARK --------- */
3969 /* Doesn't generate any executable code ... */
sewardj362cf842012-06-07 08:59:53 +00003970 case Ist_IMark:
3971 return;
3972
petarjb92a9542013-02-27 22:57:17 +00003973 /* --------- ABI HINT --------- */
3974 /* These have no meaning (denotation in the IR) and so we ignore
3975 them ... if any actually made it this far. */
sewardj362cf842012-06-07 08:59:53 +00003976 case Ist_AbiHint:
3977 return;
3978
petarjb92a9542013-02-27 22:57:17 +00003979 /* --------- NO-OP --------- */
3980 /* Fairly self-explanatory, wouldn't you say? */
sewardj362cf842012-06-07 08:59:53 +00003981 case Ist_NoOp:
3982 return;
3983
3984 /* --------- EXIT --------- */
3985 case Ist_Exit: {
3986 IRConst* dst = stmt->Ist.Exit.dst;
3987 if (!mode64 && dst->tag != Ico_U32)
3988 vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value");
3989 if (mode64 && dst->tag != Ico_U64)
3990 vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value");
3991
3992 MIPSCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
3993 MIPSAMode* amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP,
petarjb92a9542013-02-27 22:57:17 +00003994 GuestStatePointer(mode64));
sewardj362cf842012-06-07 08:59:53 +00003995
3996 /* Case: boring transfer to known address */
3997 if (stmt->Ist.Exit.jk == Ijk_Boring
3998 || stmt->Ist.Exit.jk == Ijk_Call
3999 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
4000 if (env->chainingAllowed) {
4001 /* .. almost always true .. */
4002 /* Skip the event check at the dst if this is a forwards
4003 edge. */
4004 Bool toFastEP
4005 = mode64
4006 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
4007 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
4008 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
4009 addInstr(env, MIPSInstr_XDirect(
4010 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
4011 : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
4012 amPC, cc, toFastEP));
4013 } else {
4014 /* .. very occasionally .. */
4015 /* We can't use chaining, so ask for an assisted transfer,
4016 as that's the only alternative that is allowable. */
4017 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4018 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring));
4019 }
4020 return;
4021 }
4022
4023 /* Case: assisted transfer to arbitrary address */
4024 switch (stmt->Ist.Exit.jk) {
4025 /* Keep this list in sync with that in iselNext below */
4026 case Ijk_ClientReq:
4027 case Ijk_EmFail:
4028 case Ijk_EmWarn:
4029 case Ijk_NoDecode:
4030 case Ijk_NoRedir:
4031 case Ijk_SigBUS:
dejanj6ced72b2014-06-04 11:28:07 +00004032 case Ijk_Yield:
sewardj362cf842012-06-07 08:59:53 +00004033 case Ijk_SigTRAP:
petarja6a19862012-10-19 14:55:58 +00004034 case Ijk_SigFPE_IntDiv:
4035 case Ijk_SigFPE_IntOvf:
sewardj362cf842012-06-07 08:59:53 +00004036 case Ijk_Sys_syscall:
sewardj05f5e012014-05-04 10:52:11 +00004037 case Ijk_InvalICache:
sewardj362cf842012-06-07 08:59:53 +00004038 {
4039 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4040 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc,
4041 stmt->Ist.Exit.jk));
4042 return;
4043 }
4044 default:
4045 break;
4046 }
4047
4048 /* Do we ever expect to see any other kind? */
4049 goto stmt_fail;
4050 }
4051
4052 default:
4053 break;
4054 }
4055
4056 stmt_fail:
4057 vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
4058 ppIRStmt(stmt);
4059 vpanic("iselStmt:\n");
4060}
4061
4062/*---------------------------------------------------------*/
4063/*--- ISEL: Basic block terminators (Nexts) ---*/
4064/*---------------------------------------------------------*/
4065
4066static void iselNext ( ISelEnv* env,
4067 IRExpr* next, IRJumpKind jk, Int offsIP )
4068{
4069 if (vex_traceflags & VEX_TRACE_VCODE) {
4070 vex_printf( "\n-- PUT(%d) = ", offsIP);
4071 ppIRExpr( next );
4072 vex_printf( "; exit-");
4073 ppIRJumpKind(jk);
4074 vex_printf( "\n");
4075 }
4076
4077 /* Case: boring transfer to known address */
4078 if (next->tag == Iex_Const) {
4079 IRConst* cdst = next->Iex.Const.con;
4080 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
4081 if (jk == Ijk_Boring || jk == Ijk_Call) {
4082 /* Boring transfer to known address */
petarjb92a9542013-02-27 22:57:17 +00004083 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
sewardj362cf842012-06-07 08:59:53 +00004084 if (env->chainingAllowed) {
4085 /* .. almost always true .. */
4086 /* Skip the event check at the dst if this is a forwards
4087 edge. */
4088 Bool toFastEP
4089 = env->mode64
4090 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
4091 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
4092 if (0) vex_printf("%s", toFastEP ? "X" : ".");
4093 addInstr(env, MIPSInstr_XDirect(
4094 env->mode64 ? (Addr64)cdst->Ico.U64
4095 : (Addr64)cdst->Ico.U32,
4096 amPC, MIPScc_AL, toFastEP));
4097 } else {
4098 /* .. very occasionally .. */
4099 /* We can't use chaining, so ask for an assisted transfer,
4100 as that's the only alternative that is allowable. */
4101 HReg r = iselWordExpr_R(env, next);
4102 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
4103 Ijk_Boring));
4104 }
4105 return;
4106 }
4107 }
4108
4109 /* Case: call/return (==boring) transfer to any address */
4110 switch (jk) {
4111 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
sewardj362cf842012-06-07 08:59:53 +00004112 HReg r = iselWordExpr_R(env, next);
dejanja759d172013-09-19 13:35:45 +00004113 MIPSAMode* amPC = MIPSAMode_IR(offsIP,
4114 GuestStatePointer(env->mode64));
sewardj362cf842012-06-07 08:59:53 +00004115 if (env->chainingAllowed) {
4116 addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL));
4117 } else {
4118 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
dejanja759d172013-09-19 13:35:45 +00004119 Ijk_Boring));
sewardj362cf842012-06-07 08:59:53 +00004120 }
4121 return;
4122 }
4123 default:
4124 break;
4125 }
4126
4127 /* Case: assisted transfer to arbitrary address */
4128 switch (jk) {
4129 /* Keep this list in sync with that for Ist_Exit above */
4130 case Ijk_ClientReq:
4131 case Ijk_EmFail:
4132 case Ijk_EmWarn:
4133 case Ijk_NoDecode:
4134 case Ijk_NoRedir:
4135 case Ijk_SigBUS:
dejanj0e006f22014-02-19 11:56:29 +00004136 case Ijk_SigILL:
sewardj362cf842012-06-07 08:59:53 +00004137 case Ijk_SigTRAP:
petarja6a19862012-10-19 14:55:58 +00004138 case Ijk_SigFPE_IntDiv:
4139 case Ijk_SigFPE_IntOvf:
sewardj362cf842012-06-07 08:59:53 +00004140 case Ijk_Sys_syscall:
sewardj05f5e012014-05-04 10:52:11 +00004141 case Ijk_InvalICache: {
sewardj362cf842012-06-07 08:59:53 +00004142 HReg r = iselWordExpr_R(env, next);
petarjb92a9542013-02-27 22:57:17 +00004143 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
sewardj362cf842012-06-07 08:59:53 +00004144 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk));
4145 return;
4146 }
4147 default:
4148 break;
4149 }
4150
petarjb92a9542013-02-27 22:57:17 +00004151 vex_printf("\n-- PUT(%d) = ", offsIP);
4152 ppIRExpr(next );
4153 vex_printf("; exit-");
sewardj362cf842012-06-07 08:59:53 +00004154 ppIRJumpKind(jk);
petarjb92a9542013-02-27 22:57:17 +00004155 vex_printf("\n");
4156 vassert(0); /* are we expecting any other kind? */
sewardj362cf842012-06-07 08:59:53 +00004157}
4158
4159/*---------------------------------------------------------*/
4160/*--- Insn selector top-level ---*/
4161/*---------------------------------------------------------*/
4162
4163/* Translate an entire BB to mips code. */
floriancacba8e2014-12-15 18:58:07 +00004164HInstrArray *iselSB_MIPS ( const IRSB* bb,
sewardj362cf842012-06-07 08:59:53 +00004165 VexArch arch_host,
floriand8c64e02014-10-08 08:54:44 +00004166 const VexArchInfo* archinfo_host,
4167 const VexAbiInfo* vbi,
sewardj362cf842012-06-07 08:59:53 +00004168 Int offs_Host_EvC_Counter,
4169 Int offs_Host_EvC_FailAddr,
4170 Bool chainingAllowed,
4171 Bool addProfInc,
floriandcd6d232015-01-02 17:32:21 +00004172 Addr max_ga )
sewardj362cf842012-06-07 08:59:53 +00004173{
4174 Int i, j;
4175 HReg hreg, hregHI;
4176 ISelEnv* env;
4177 UInt hwcaps_host = archinfo_host->hwcaps;
4178 MIPSAMode *amCounter, *amFailAddr;
4179
4180 /* sanity ... */
petarjb92a9542013-02-27 22:57:17 +00004181 vassert(arch_host == VexArchMIPS32 || arch_host == VexArchMIPS64);
Elliott Hughesa0664b92017-04-18 17:46:52 -07004182 vassert(VEX_PRID_COMP_MIPS == VEX_MIPS_COMP_ID(hwcaps_host)
4183 || VEX_PRID_COMP_CAVIUM == VEX_MIPS_COMP_ID(hwcaps_host)
4184 || VEX_PRID_COMP_BROADCOM == VEX_MIPS_COMP_ID(hwcaps_host)
4185 || VEX_PRID_COMP_NETLOGIC == VEX_MIPS_COMP_ID(hwcaps_host)
4186 || VEX_PRID_COMP_INGENIC_E1 == VEX_MIPS_COMP_ID(hwcaps_host)
4187 || VEX_PRID_COMP_LEGACY == VEX_MIPS_COMP_ID(hwcaps_host));
sewardj362cf842012-06-07 08:59:53 +00004188
sewardj9b769162014-07-24 12:42:03 +00004189 /* Check that the host's endianness is as expected. */
4190 vassert(archinfo_host->endness == VexEndnessLE
4191 || archinfo_host->endness == VexEndnessBE);
4192
sewardj362cf842012-06-07 08:59:53 +00004193 mode64 = arch_host != VexArchMIPS32;
Elliott Hughesa0664b92017-04-18 17:46:52 -07004194 fp_mode64 = VEX_MIPS_HOST_FP_MODE(hwcaps_host);
sewardj362cf842012-06-07 08:59:53 +00004195
4196 /* Make up an initial environment to use. */
floriand8e3eca2015-03-13 12:46:49 +00004197 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
sewardj362cf842012-06-07 08:59:53 +00004198 env->vreg_ctr = 0;
4199 env->mode64 = mode64;
dejanj0e006f22014-02-19 11:56:29 +00004200 env->fp_mode64 = fp_mode64;
sewardj362cf842012-06-07 08:59:53 +00004201
4202 /* Set up output code array. */
4203 env->code = newHInstrArray();
4204
4205 /* Copy BB's type env. */
4206 env->type_env = bb->tyenv;
4207
4208 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4209 change as we go along. */
4210 env->n_vregmap = bb->tyenv->types_used;
floriand8e3eca2015-03-13 12:46:49 +00004211 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
4212 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
sewardj362cf842012-06-07 08:59:53 +00004213
4214 /* and finally ... */
4215 env->hwcaps = hwcaps_host;
4216 env->chainingAllowed = chainingAllowed;
4217 env->hwcaps = hwcaps_host;
4218 env->max_ga = max_ga;
4219
4220 /* For each IR temporary, allocate a suitably-kinded virtual
4221 register. */
4222 j = 0;
4223 for (i = 0; i < env->n_vregmap; i++) {
4224 hregHI = hreg = INVALID_HREG;
4225 switch (bb->tyenv->types[i]) {
4226 case Ity_I1:
4227 case Ity_I8:
4228 case Ity_I16:
petarjb92a9542013-02-27 22:57:17 +00004229 case Ity_I32:
4230 if (mode64) {
sewardja5b50222015-03-26 07:18:32 +00004231 hreg = mkHReg(True, HRcInt64, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004232 break;
4233 } else {
sewardja5b50222015-03-26 07:18:32 +00004234 hreg = mkHReg(True, HRcInt32, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004235 break;
4236 }
4237 case Ity_I64:
4238 if (mode64) {
sewardja5b50222015-03-26 07:18:32 +00004239 hreg = mkHReg(True, HRcInt64, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004240 break;
4241 } else {
sewardja5b50222015-03-26 07:18:32 +00004242 hreg = mkHReg(True, HRcInt32, 0, j++);
4243 hregHI = mkHReg(True, HRcInt32, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004244 break;
4245 }
sewardj362cf842012-06-07 08:59:53 +00004246 case Ity_I128:
4247 vassert(mode64);
sewardja5b50222015-03-26 07:18:32 +00004248 hreg = mkHReg(True, HRcInt64, 0, j++);
4249 hregHI = mkHReg(True, HRcInt64, 0, j++);
sewardj362cf842012-06-07 08:59:53 +00004250 break;
petarjb92a9542013-02-27 22:57:17 +00004251 case Ity_F32:
4252 if (mode64) {
sewardja5b50222015-03-26 07:18:32 +00004253 hreg = mkHReg(True, HRcFlt64, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004254 break;
4255 } else {
sewardja5b50222015-03-26 07:18:32 +00004256 hreg = mkHReg(True, HRcFlt32, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004257 break;
4258 }
sewardj362cf842012-06-07 08:59:53 +00004259 case Ity_F64:
sewardja5b50222015-03-26 07:18:32 +00004260 hreg = mkHReg(True, HRcFlt64, 0, j++);
sewardj362cf842012-06-07 08:59:53 +00004261 break;
4262 default:
4263 ppIRType(bb->tyenv->types[i]);
4264 vpanic("iselBB(mips): IRTemp type");
dejanj0e006f22014-02-19 11:56:29 +00004265 break;
sewardj362cf842012-06-07 08:59:53 +00004266 }
4267 env->vregmap[i] = hreg;
4268 env->vregmapHI[i] = hregHI;
4269 }
4270 env->vreg_ctr = j;
4271
4272 /* The very first instruction must be an event check. */
petarjb92a9542013-02-27 22:57:17 +00004273 amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, GuestStatePointer(mode64));
4274 amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, GuestStatePointer(mode64));
sewardj362cf842012-06-07 08:59:53 +00004275 addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr));
4276
4277 /* Possibly a block counter increment (for profiling). At this
4278 point we don't know the address of the counter, so just pretend
4279 it is zero. It will have to be patched later, but before this
4280 translation is used, by a call to LibVEX_patchProfCtr. */
4281 if (addProfInc) {
4282 addInstr(env, MIPSInstr_ProfInc());
4283 }
4284
4285 /* Ok, finally we can iterate over the statements. */
4286 for (i = 0; i < bb->stmts_used; i++)
4287 iselStmt(env, bb->stmts[i]);
4288
4289 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
4290
4291 /* record the number of vregs we used. */
4292 env->code->n_vregs = env->vreg_ctr;
4293 return env->code;
4294
4295}
4296
4297/*---------------------------------------------------------------*/
4298/*--- end host_mips_isel.c ---*/
4299/*---------------------------------------------------------------*/