blob: 848234a39f92918411dc3c6142bcd7a6d2784209 [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
sewardj785952d2015-08-21 11:29:16 +000010 Copyright (C) 2010-2015 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
petarjb92a9542013-02-27 22:57:17 +000064/* guest_COND offset */
sewardja5b50222015-03-26 07:18:32 +000065#define COND_OFFSET(_mode64) ((_mode64) ? 612 : 448)
petarjb92a9542013-02-27 22:57:17 +000066
sewardj362cf842012-06-07 08:59:53 +000067/*---------------------------------------------------------*/
68/*--- ISelEnv ---*/
69/*---------------------------------------------------------*/
70
71/* This carries around:
72
73 - A mapping from IRTemp to IRType, giving the type of any IRTemp we
74 might encounter. This is computed before insn selection starts,
75 and does not change.
76
77 - A mapping from IRTemp to HReg. This tells the insn selector
78 which virtual register(s) are associated with each IRTemp
79 temporary. This is computed before insn selection starts, and
80 does not change. We expect this mapping to map precisely the
81 same set of IRTemps as the type mapping does.
82
83 - vregmap holds the primary register for the IRTemp.
84 - vregmapHI is only used for 64-bit integer-typed
85 IRTemps. It holds the identity of a second
86 32-bit virtual HReg, which holds the high half
87 of the value.
88
89 - The code array, that is, the insns selected so far.
90
91 - A counter, for generating new virtual registers.
92
dejanjc3fee0d2013-07-25 09:08:03 +000093 - The host subarchitecture we are selecting insns for.
sewardj362cf842012-06-07 08:59:53 +000094 This is set at the start and does not change.
95
96 - A Bool for indicating whether we may generate chain-me
97 instructions for control flow transfers, or whether we must use
98 XAssisted.
99
100 - The maximum guest address of any guest insn in this block.
101 Actually, the address of the highest-addressed byte from any insn
102 in this block. Is set at the start and does not change. This is
103 used for detecting jumps which are definitely forward-edges from
104 this block, and therefore can be made (chained) to the fast entry
105 point of the destination, thereby avoiding the destination's
106 event check.
107
108 Note, this is all (well, mostly) host-independent.
109*/
110
111typedef
112 struct {
113 /* Constant -- are set at the start and do not change. */
114 IRTypeEnv* type_env;
115
116 HReg* vregmap;
117 HReg* vregmapHI;
118 Int n_vregmap;
119
120 UInt hwcaps;
121 Bool mode64;
dejanj0e006f22014-02-19 11:56:29 +0000122 Bool fp_mode64;
sewardj362cf842012-06-07 08:59:53 +0000123
124 Bool chainingAllowed;
125 Addr64 max_ga;
126
127 /* These are modified as we go along. */
128 HInstrArray* code;
129 Int vreg_ctr;
130 }
131 ISelEnv;
132
133static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp)
134{
135 vassert(tmp >= 0);
136 vassert(tmp < env->n_vregmap);
137 return env->vregmap[tmp];
138}
139
140static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
141{
142 vassert(tmp >= 0);
143 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000144 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj362cf842012-06-07 08:59:53 +0000145 *vrLO = env->vregmap[tmp];
146 *vrHI = env->vregmapHI[tmp];
147}
148
149static void
150lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
151{
152 vassert(env->mode64);
153 vassert(tmp >= 0);
154 vassert(tmp < env->n_vregmap);
florian79efdc62013-02-11 00:47:35 +0000155 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
sewardj362cf842012-06-07 08:59:53 +0000156 *vrLO = env->vregmap[tmp];
157 *vrHI = env->vregmapHI[tmp];
158}
159
160static void addInstr(ISelEnv * env, MIPSInstr * instr)
161{
162 addHInstr(env->code, instr);
163 if (vex_traceflags & VEX_TRACE_VCODE) {
164 ppMIPSInstr(instr, mode64);
165 vex_printf("\n");
166 }
167}
168
169static HReg newVRegI(ISelEnv * env)
170{
sewardja5b50222015-03-26 07:18:32 +0000171 HReg reg = mkHReg(True/*virtual reg*/,
172 HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
sewardj362cf842012-06-07 08:59:53 +0000173 env->vreg_ctr++;
174 return reg;
175}
176
177static HReg newVRegD(ISelEnv * env)
178{
sewardja5b50222015-03-26 07:18:32 +0000179 HReg reg = mkHReg(True/*virtual reg*/,
180 HRcFlt64, 0/*enc*/, env->vreg_ctr);
sewardj362cf842012-06-07 08:59:53 +0000181 env->vreg_ctr++;
182 return reg;
183}
184
185static HReg newVRegF(ISelEnv * env)
186{
sewardja5b50222015-03-26 07:18:32 +0000187 HReg reg = mkHReg(True/*virtual reg*/,
188 HRcFPR(env->mode64), 0/*enc*/, env->vreg_ctr);
sewardj362cf842012-06-07 08:59:53 +0000189 env->vreg_ctr++;
190 return reg;
191}
192
193static void add_to_sp(ISelEnv * env, UInt n)
194{
195 HReg sp = StackPointer(mode64);
196 vassert(n < 256 && (n % 8) == 0);
petarjb92a9542013-02-27 22:57:17 +0000197 if (mode64)
198 addInstr(env, MIPSInstr_Alu(Malu_DADD, sp, sp, MIPSRH_Imm(True,
199 toUShort(n))));
200 else
201 addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True,
202 toUShort(n))));
sewardj362cf842012-06-07 08:59:53 +0000203}
204
205static void sub_from_sp(ISelEnv * env, UInt n)
206{
207 HReg sp = StackPointer(mode64);
208 vassert(n < 256 && (n % 8) == 0);
petarjb92a9542013-02-27 22:57:17 +0000209 if (mode64)
210 addInstr(env, MIPSInstr_Alu(Malu_DSUB, sp, sp,
211 MIPSRH_Imm(True, toUShort(n))));
212 else
213 addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp,
214 MIPSRH_Imm(True, toUShort(n))));
sewardj362cf842012-06-07 08:59:53 +0000215}
216
217/*---------------------------------------------------------*/
218/*--- ISEL: Forward declarations ---*/
219/*---------------------------------------------------------*/
220
221/* These are organised as iselXXX and iselXXX_wrk pairs. The
222 iselXXX_wrk do the real work, but are not to be called directly.
223 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
224 checks that all returned registers are virtual. You should not
225 call the _wrk version directly.
226*/
227/* 32-bit mode: Compute an I8/I16/I32 into a RH
228 (reg-or-halfword-immediate).
229 It's important to specify whether the immediate is to be regarded
230 as signed or not. If yes, this will never return -32768 as an
231 immediate; this guaranteed that all signed immediates that are
dejanjc3fee0d2013-07-25 09:08:03 +0000232 return can have their sign inverted if need be.
sewardj362cf842012-06-07 08:59:53 +0000233*/
234static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
235static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
236
dejanj0e006f22014-02-19 11:56:29 +0000237/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an
238 immediate in the range 1 .. 31 inclusive. Used for doing shift amounts. */
sewardj362cf842012-06-07 08:59:53 +0000239static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
240static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
241
dejanj0e006f22014-02-19 11:56:29 +0000242/* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an
243 immediate in the range 1 .. 63 inclusive. Used for doing shift amounts. */
petarjb92a9542013-02-27 22:57:17 +0000244static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e);
245static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e);
246
sewardj362cf842012-06-07 08:59:53 +0000247/* compute an I8/I16/I32 into a GPR*/
248static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
249static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
250
251/* compute an I32 into an AMode. */
252static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
253 IRType xferTy);
254static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy);
255
256static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
257 IRExpr * e);
258static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
259
260/* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
261static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo,
262 ISelEnv * env, IRExpr * e);
263static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
264
265static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
266static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e);
267
268static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e);
269static HReg iselDblExpr(ISelEnv * env, IRExpr * e);
270
271static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e);
272static HReg iselFltExpr(ISelEnv * env, IRExpr * e);
273
274static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode)
275{
276 /*
277 rounding mode | MIPS | IR
278 ------------------------
279 to nearest | 00 | 00
280 to zero | 01 | 11
281 to +infinity | 10 | 10
282 to -infinity | 11 | 01
283 */
petarjb92a9542013-02-27 22:57:17 +0000284 /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 2 */
sewardj362cf842012-06-07 08:59:53 +0000285 HReg irrm = iselWordExpr_R(env, mode);
286 HReg tmp = newVRegI(env);
287 HReg fcsr_old = newVRegI(env);
288 MIPSAMode *am_addr;
289
290 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
291 MIPSRH_Imm(False, 1)));
292 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
293 addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, MIPSRH_Imm(False, 3)));
294 /* save old value of FCSR */
295 addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
petarjb92a9542013-02-27 22:57:17 +0000296 sub_from_sp(env, 8); /* Move SP down 8 bytes */
sewardj362cf842012-06-07 08:59:53 +0000297 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
298
petarjb92a9542013-02-27 22:57:17 +0000299 /* store old FCSR to stack */
sewardj362cf842012-06-07 08:59:53 +0000300 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
301
petarjb92a9542013-02-27 22:57:17 +0000302 /* set new value of FCSR */
sewardj362cf842012-06-07 08:59:53 +0000303 addInstr(env, MIPSInstr_MtFCSR(irrm));
304}
305
306static void set_MIPS_rounding_default(ISelEnv * env)
307{
308 HReg fcsr = newVRegI(env);
petarjb92a9542013-02-27 22:57:17 +0000309 /* load as float */
sewardj362cf842012-06-07 08:59:53 +0000310 MIPSAMode *am_addr;
311 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
312
313 addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64));
314
petarjb92a9542013-02-27 22:57:17 +0000315 add_to_sp(env, 8); /* Reset SP */
sewardj362cf842012-06-07 08:59:53 +0000316
petarjb92a9542013-02-27 22:57:17 +0000317 /* set new value of FCSR*/
sewardj362cf842012-06-07 08:59:53 +0000318 addInstr(env, MIPSInstr_MtFCSR(fcsr));
319}
320
321/*---------------------------------------------------------*/
322/*--- ISEL: Misc helpers ---*/
323/*---------------------------------------------------------*/
324
325/* Make an int reg-reg move. */
326static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src)
327{
328 vassert(hregClass(r_dst) == hregClass(r_src));
329 vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64);
330 return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src));
331}
332
333/*---------------------------------------------------------*/
334/*--- ISEL: Function call helpers ---*/
335/*---------------------------------------------------------*/
336
337/* Used only in doHelperCall. See big comment in doHelperCall re
338 handling of register-parameter args. This function figures out
339 whether evaluation of an expression might require use of a fixed
340 register. If in doubt return True (safe but suboptimal).
341*/
342static Bool mightRequireFixedRegs(IRExpr * e)
343{
344 switch (e->tag) {
345 case Iex_RdTmp:
346 case Iex_Const:
347 case Iex_Get:
348 return False;
349 default:
350 return True;
351 }
352}
353
354/* Load 2*I32 regs to fp reg */
355static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
356{
357 HReg fr_dst = newVRegD(env);
358 MIPSAMode *am_addr0, *am_addr1;
359
360 vassert(hregClass(r_srcHi) == HRcInt32);
361 vassert(hregClass(r_srcLo) == HRcInt32);
362
petarjb92a9542013-02-27 22:57:17 +0000363 sub_from_sp(env, 16); /* Move SP down 16 bytes */
sewardj362cf842012-06-07 08:59:53 +0000364 am_addr0 = MIPSAMode_IR(0, StackPointer(mode64));
petarj1ec43e02012-09-04 13:45:42 +0000365 am_addr1 = MIPSAMode_IR(4, StackPointer(mode64));
sewardj362cf842012-06-07 08:59:53 +0000366
petarjb92a9542013-02-27 22:57:17 +0000367 /* store hi,lo as Ity_I32's */
petarj0c30de82013-04-19 12:35:00 +0000368#if defined (_MIPSEL)
sewardj362cf842012-06-07 08:59:53 +0000369 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64));
370 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64));
petarj0c30de82013-04-19 12:35:00 +0000371#elif defined (_MIPSEB)
372 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcHi, mode64));
373 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcLo, mode64));
sewardjb40431f2013-05-08 08:56:45 +0000374#else
375 /* Stop gcc on other platforms complaining about am_addr1 being set
376 but not used. */
377 (void)am_addr1;
petarj0c30de82013-04-19 12:35:00 +0000378#endif
sewardj362cf842012-06-07 08:59:53 +0000379
petarjb92a9542013-02-27 22:57:17 +0000380 /* load as float */
sewardj362cf842012-06-07 08:59:53 +0000381 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0));
382
petarjb92a9542013-02-27 22:57:17 +0000383 add_to_sp(env, 16); /* Reset SP */
sewardj362cf842012-06-07 08:59:53 +0000384 return fr_dst;
385}
386
sewardj74142b82013-08-08 10:28:59 +0000387/* Do a complete function call. |guard| is a Ity_Bit expression
sewardj362cf842012-06-07 08:59:53 +0000388 indicating whether or not the call happens. If guard==NULL, the
sewardj74142b82013-08-08 10:28:59 +0000389 call is unconditional. |retloc| is set to indicate where the
390 return value is after the call. The caller (of this fn) must
391 generate code to add |stackAdjustAfterCall| to the stack pointer
392 after the call is done. */
sewardj362cf842012-06-07 08:59:53 +0000393
sewardj74142b82013-08-08 10:28:59 +0000394static void doHelperCall(/*OUT*/UInt* stackAdjustAfterCall,
395 /*OUT*/RetLoc* retloc,
396 ISelEnv* env,
397 IRExpr* guard,
398 IRCallee* cee, IRType retTy, IRExpr** args )
sewardj362cf842012-06-07 08:59:53 +0000399{
400 MIPSCondCode cc;
401 HReg argregs[MIPS_N_REGPARMS];
402 HReg tmpregs[MIPS_N_REGPARMS];
403 Bool go_fast;
404 Int n_args, i, argreg;
405 UInt argiregs;
petarja81d9be2013-01-30 18:06:26 +0000406 HReg src = INVALID_HREG;
sewardj362cf842012-06-07 08:59:53 +0000407
sewardj74142b82013-08-08 10:28:59 +0000408 /* Set default returns. We'll update them later if needed. */
409 *stackAdjustAfterCall = 0;
410 *retloc = mk_RetLoc_INVALID();
411
412 /* These are used for cross-checking that IR-level constraints on
florian90419562013-08-15 20:54:52 +0000413 the use of IRExpr_VECRET() and IRExpr_BBPTR() are observed. */
sewardj74142b82013-08-08 10:28:59 +0000414 UInt nVECRETs = 0;
415 UInt nBBPTRs = 0;
416
sewardj362cf842012-06-07 08:59:53 +0000417 /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
418 are allowed to be used for passing integer arguments. They correspond
dejanjc3fee0d2013-07-25 09:08:03 +0000419 to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
420 on MIPS host (since we only implement one calling convention) and so we
sewardj362cf842012-06-07 08:59:53 +0000421 always ignore it. */
422
423 /* MIPS 64 calling convention: up to four registers ($a0 ... $a7)
424 are allowed to be used for passing integer arguments. They correspond
dejanjc3fee0d2013-07-25 09:08:03 +0000425 to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
426 on MIPS host (since we only implement one calling convention) and so we
sewardj362cf842012-06-07 08:59:53 +0000427 always ignore it. */
sewardj362cf842012-06-07 08:59:53 +0000428
sewardj74142b82013-08-08 10:28:59 +0000429 /* The return type can be I{64,32,16,8} or V{128,256}. In the
430 latter two cases, it is expected that |args| will contain the
florian90419562013-08-15 20:54:52 +0000431 special node IRExpr_VECRET(), in which case this routine
sewardj74142b82013-08-08 10:28:59 +0000432 generates code to allocate space on the stack for the vector
433 return value. Since we are not passing any scalars on the
434 stack, it is enough to preallocate the return space before
435 marshalling any arguments, in this case.
436
florian90419562013-08-15 20:54:52 +0000437 |args| may also contain IRExpr_BBPTR(), in which case the value
sewardj74142b82013-08-08 10:28:59 +0000438 in the guest state pointer register is passed as the
439 corresponding argument. */
440
441 n_args = 0;
442 for (i = 0; args[i]; i++) {
443 IRExpr* arg = args[i];
florian90419562013-08-15 20:54:52 +0000444 if (UNLIKELY(arg->tag == Iex_VECRET)) {
sewardj74142b82013-08-08 10:28:59 +0000445 nVECRETs++;
florian90419562013-08-15 20:54:52 +0000446 } else if (UNLIKELY(arg->tag == Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000447 nBBPTRs++;
448 }
449 n_args++;
450 }
451
452 if (n_args > MIPS_N_REGPARMS) {
petarjb92a9542013-02-27 22:57:17 +0000453 vpanic("doHelperCall(MIPS): cannot currently handle > 4 or 8 args");
sewardj362cf842012-06-07 08:59:53 +0000454 }
petarjb92a9542013-02-27 22:57:17 +0000455 if (mode64) {
456 argregs[0] = hregMIPS_GPR4(mode64);
457 argregs[1] = hregMIPS_GPR5(mode64);
458 argregs[2] = hregMIPS_GPR6(mode64);
459 argregs[3] = hregMIPS_GPR7(mode64);
460 argregs[4] = hregMIPS_GPR8(mode64);
461 argregs[5] = hregMIPS_GPR9(mode64);
462 argregs[6] = hregMIPS_GPR10(mode64);
463 argregs[7] = hregMIPS_GPR11(mode64);
464 argiregs = 0;
sewardj74142b82013-08-08 10:28:59 +0000465 tmpregs[0] = tmpregs[1] = tmpregs[2] =
466 tmpregs[3] = tmpregs[4] = tmpregs[5] =
467 tmpregs[6] = tmpregs[7] = INVALID_HREG;
petarjb92a9542013-02-27 22:57:17 +0000468 } else {
469 argregs[0] = hregMIPS_GPR4(mode64);
470 argregs[1] = hregMIPS_GPR5(mode64);
471 argregs[2] = hregMIPS_GPR6(mode64);
472 argregs[3] = hregMIPS_GPR7(mode64);
473 argiregs = 0;
sewardj74142b82013-08-08 10:28:59 +0000474 tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
petarjb92a9542013-02-27 22:57:17 +0000475 }
sewardj362cf842012-06-07 08:59:53 +0000476
petarjb92a9542013-02-27 22:57:17 +0000477 /* First decide which scheme (slow or fast) is to be used. First assume the
478 fast scheme, and select slow if any contraindications (wow) appear. */
sewardj362cf842012-06-07 08:59:53 +0000479
480 go_fast = True;
481
sewardj74142b82013-08-08 10:28:59 +0000482 /* We'll need space on the stack for the return value. Avoid
483 possible complications with nested calls by using the slow
484 scheme. */
485 if (retTy == Ity_V128 || retTy == Ity_V256)
486 go_fast = False;
487
488 if (go_fast && guard) {
sewardj362cf842012-06-07 08:59:53 +0000489 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
490 && guard->Iex.Const.con->Ico.U1 == True) {
491 /* unconditional */
492 } else {
493 /* Not manifestly unconditional -- be conservative. */
494 go_fast = False;
495 }
496 }
497
498 if (go_fast) {
499 for (i = 0; i < n_args; i++) {
500 if (mightRequireFixedRegs(args[i])) {
501 go_fast = False;
502 break;
503 }
504 }
505 }
506
sewardj362cf842012-06-07 08:59:53 +0000507 /* At this point the scheme to use has been established. Generate
508 code to get the arg values into the argument rregs. */
509 if (go_fast) {
510 /* FAST SCHEME */
511 argreg = 0;
sewardj362cf842012-06-07 08:59:53 +0000512
513 for (i = 0; i < n_args; i++) {
sewardj74142b82013-08-08 10:28:59 +0000514 IRExpr* arg = args[i];
sewardj362cf842012-06-07 08:59:53 +0000515 vassert(argreg < MIPS_N_REGPARMS);
sewardj74142b82013-08-08 10:28:59 +0000516
517 IRType aTy = Ity_INVALID;
florian90419562013-08-15 20:54:52 +0000518 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +0000519 aTy = typeOfIRExpr(env->type_env, arg);
520
521 if (aTy == Ity_I32 || mode64) {
sewardj362cf842012-06-07 08:59:53 +0000522 argiregs |= (1 << (argreg + 4));
sewardj74142b82013-08-08 10:28:59 +0000523 addInstr(env, mk_iMOVds_RR(argregs[argreg],
524 iselWordExpr_R(env, arg)));
525 argreg++;
526 } else if (aTy == Ity_I64) { /* Ity_I64 */
petarj1ec43e02012-09-04 13:45:42 +0000527 if (argreg & 1) {
528 argreg++;
529 argiregs |= (1 << (argreg + 4));
530 }
531 HReg rHi, rLo;
sewardj74142b82013-08-08 10:28:59 +0000532 iselInt64Expr(&rHi, &rLo, env, arg);
sewardj362cf842012-06-07 08:59:53 +0000533 argiregs |= (1 << (argreg + 4));
petarj1ec43e02012-09-04 13:45:42 +0000534 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi ));
535 argiregs |= (1 << (argreg + 4));
536 addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo));
sewardj74142b82013-08-08 10:28:59 +0000537 argreg++;
florian90419562013-08-15 20:54:52 +0000538 } else if (arg->tag == Iex_BBPTR) {
sewardj74142b82013-08-08 10:28:59 +0000539 vassert(0); // ATC
540 addInstr(env, mk_iMOVds_RR(argregs[argreg],
541 GuestStatePointer(mode64)));
542 argreg++;
florian90419562013-08-15 20:54:52 +0000543 } else if (arg->tag == Iex_VECRET) {
sewardj74142b82013-08-08 10:28:59 +0000544 // If this happens, it denotes ill-formed IR.
545 vassert(0);
sewardj362cf842012-06-07 08:59:53 +0000546 }
sewardj362cf842012-06-07 08:59:53 +0000547 }
548 /* Fast scheme only applies for unconditional calls. Hence: */
549 cc = MIPScc_AL;
550 } else {
551 /* SLOW SCHEME; move via temporaries */
552 argreg = 0;
sewardj74142b82013-08-08 10:28:59 +0000553
sewardj362cf842012-06-07 08:59:53 +0000554 for (i = 0; i < n_args; i++) {
555 vassert(argreg < MIPS_N_REGPARMS);
sewardj74142b82013-08-08 10:28:59 +0000556 IRExpr* arg = args[i];
557
558 IRType aTy = Ity_INVALID;
florian90419562013-08-15 20:54:52 +0000559 if (LIKELY(!is_IRExpr_VECRET_or_BBPTR(arg)))
sewardj74142b82013-08-08 10:28:59 +0000560 aTy = typeOfIRExpr(env->type_env, arg);
561
dejanj8007ea62013-09-18 10:06:13 +0000562 if (aTy == Ity_I32 || (mode64 && arg->tag != Iex_BBPTR)) {
sewardj74142b82013-08-08 10:28:59 +0000563 tmpregs[argreg] = iselWordExpr_R(env, arg);
564 argreg++;
565 } else if (aTy == Ity_I64) { /* Ity_I64 */
petarj1ec43e02012-09-04 13:45:42 +0000566 if (argreg & 1)
567 argreg++;
568 if (argreg + 1 >= MIPS_N_REGPARMS)
569 vassert(0); /* out of argregs */
570 HReg raHi, raLo;
sewardj74142b82013-08-08 10:28:59 +0000571 iselInt64Expr(&raHi, &raLo, env, arg);
petarj1ec43e02012-09-04 13:45:42 +0000572 tmpregs[argreg] = raLo;
573 argreg++;
dejanjc3fee0d2013-07-25 09:08:03 +0000574 tmpregs[argreg] = raHi;
sewardj74142b82013-08-08 10:28:59 +0000575 argreg++;
florian90419562013-08-15 20:54:52 +0000576 } else if (arg->tag == Iex_BBPTR) {
sewardj74142b82013-08-08 10:28:59 +0000577 tmpregs[argreg] = GuestStatePointer(mode64);
578 argreg++;
sewardj362cf842012-06-07 08:59:53 +0000579 }
florian90419562013-08-15 20:54:52 +0000580 else if (arg->tag == Iex_VECRET) {
sewardj74142b82013-08-08 10:28:59 +0000581 // If this happens, it denotes ill-formed IR
582 vassert(0);
583 }
sewardj362cf842012-06-07 08:59:53 +0000584 }
585
586 /* Now we can compute the condition. We can't do it earlier
587 because the argument computations could trash the condition
588 codes. Be a bit clever to handle the common case where the
589 guard is 1:Bit. */
590 cc = MIPScc_AL;
591 if (guard) {
592 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
593 && guard->Iex.Const.con->Ico.U1 == True) {
594 /* unconditional -- do nothing */
595 } else {
596 cc = iselCondCode(env, guard);
597 src = iselWordExpr_R(env, guard);
598 }
599 }
600 /* Move the args to their final destinations. */
601 for (i = 0; i < argreg; i++) {
petarjb92a9542013-02-27 22:57:17 +0000602 if (hregIsInvalid(tmpregs[i])) /* Skip invalid regs */
sewardj362cf842012-06-07 08:59:53 +0000603 continue;
604 /* None of these insns, including any spill code that might
605 be generated, may alter the condition codes. */
606 argiregs |= (1 << (i + 4));
607 addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
608 }
609 }
610
sewardj74142b82013-08-08 10:28:59 +0000611 /* Do final checks, set the return values, and generate the call
612 instruction proper. */
613 vassert(nBBPTRs == 0 || nBBPTRs == 1);
614 vassert(nVECRETs == (retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0);
615 vassert(*stackAdjustAfterCall == 0);
616 vassert(is_RetLoc_INVALID(*retloc));
617 switch (retTy) {
618 case Ity_INVALID:
619 /* Function doesn't return a value. */
620 *retloc = mk_RetLoc_simple(RLPri_None);
621 break;
622 case Ity_I64:
623 *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
624 break;
625 case Ity_I32: case Ity_I16: case Ity_I8:
626 *retloc = mk_RetLoc_simple(RLPri_Int);
627 break;
628 case Ity_V128:
629 vassert(0); // ATC
630 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
631 *stackAdjustAfterCall = 16;
632 break;
633 case Ity_V256:
634 vassert(0); // ATC
635 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
636 *stackAdjustAfterCall = 32;
637 break;
638 default:
639 /* IR can denote other possible return types, but we don't
640 handle those here. */
641 vassert(0);
642 }
sewardj362cf842012-06-07 08:59:53 +0000643
florian93a09742015-01-07 20:14:48 +0000644 Addr64 target = mode64 ? (Addr)cee->addr :
645 toUInt((Addr)cee->addr);
sewardj74142b82013-08-08 10:28:59 +0000646
647 /* Finally, generate the call itself. This needs the *retloc value
648 set in the switch above, which is why it's at the end. */
petarjb92a9542013-02-27 22:57:17 +0000649 if (cc == MIPScc_AL)
florian93a09742015-01-07 20:14:48 +0000650 addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs,
sewardj74142b82013-08-08 10:28:59 +0000651 *retloc));
petarjb92a9542013-02-27 22:57:17 +0000652 else
florian93a09742015-01-07 20:14:48 +0000653 addInstr(env, MIPSInstr_Call(cc, target, argiregs, src, *retloc));
sewardj362cf842012-06-07 08:59:53 +0000654}
655
656/*---------------------------------------------------------*/
657/*--- ISEL: Integer expression auxiliaries ---*/
658/*---------------------------------------------------------*/
659
660/* --------------------- AMODEs --------------------- */
661
662/* Return an AMode which computes the value of the specified
663 expression, possibly also adding insns to the code list as a
664 result. The expression may only be a word-size one.
665*/
666
667static Bool uInt_fits_in_16_bits(UInt u)
668{
669 Int i = u & 0xFFFF;
670 i <<= 16;
671 i >>= 16;
672 return toBool(u == (UInt) i);
673}
674
petarjb92a9542013-02-27 22:57:17 +0000675static Bool uLong_fits_in_16_bits ( ULong u )
676{
677 Long i = u & 0xFFFFULL;
678 i <<= 48;
679 i >>= 48;
680 return toBool(u == (ULong) i);
681}
682
683static Bool uLong_is_4_aligned ( ULong u )
684{
685 return toBool((u & 3ULL) == 0);
686}
687
sewardj362cf842012-06-07 08:59:53 +0000688static Bool sane_AMode(ISelEnv * env, MIPSAMode * am)
689{
690 switch (am->tag) {
691 case Mam_IR:
692 return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) &&
693 hregIsVirtual(am->Mam.IR.base) &&
694 uInt_fits_in_16_bits(am->Mam.IR.index));
695 case Mam_RR:
696 return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) &&
697 hregIsVirtual(am->Mam.RR.base) &&
698 hregClass(am->Mam.RR.index) == HRcGPR(mode64) &&
petarja81d9be2013-01-30 18:06:26 +0000699 hregIsVirtual(am->Mam.RR.index));
sewardj362cf842012-06-07 08:59:53 +0000700 default:
701 vpanic("sane_AMode: unknown mips amode tag");
702 }
703}
704
705static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy)
706{
707 MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
708 vassert(sane_AMode(env, am));
709 return am;
710}
711
712/* DO NOT CALL THIS DIRECTLY ! */
713static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
petarjb92a9542013-02-27 22:57:17 +0000714 IRType xferTy)
sewardj362cf842012-06-07 08:59:53 +0000715{
716 IRType ty = typeOfIRExpr(env->type_env, e);
petarjb92a9542013-02-27 22:57:17 +0000717 if (env->mode64) {
718 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
719 vassert(ty == Ity_I64);
720
721 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
722 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64
723 && e->Iex.Binop.arg2->tag == Iex_Const
724 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
725 && (aligned4imm ?
726 uLong_is_4_aligned(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64) : True)
727 && uLong_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) {
728 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
729 iselWordExpr_R(env, e->Iex.Binop.arg1));
730 }
731
732 /* Add64(expr,expr) */
733 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64) {
734 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
735 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
736 return MIPSAMode_RR(r_idx, r_base);
737 }
738 } else {
sewardj362cf842012-06-07 08:59:53 +0000739 vassert(ty == Ity_I32);
740
741 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
742 if (e->tag == Iex_Binop
743 && e->Iex.Binop.op == Iop_Add32
744 && e->Iex.Binop.arg2->tag == Iex_Const
745 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
746 && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) {
747 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
748 iselWordExpr_R(env, e->Iex.Binop.arg1));
749 }
750
751 /* Add32(expr,expr) */
752 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) {
753 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
754 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
755
756 return MIPSAMode_RR(r_idx, r_base);
757 }
758 }
759
760 /* Doesn't match anything in particular. Generate it into
761 a register and use that. */
762 return MIPSAMode_IR(0, iselWordExpr_R(env, e));
763}
764
765/*---------------------------------------------------------*/
766/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
767/*---------------------------------------------------------*/
768
769/* Select insns for an integer-typed expression, and add them to the
770 code list. Return a reg holding the result. This reg will be a
771 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
772 want to modify it, ask for a new vreg, copy it in there, and modify
773 the copy. The register allocator will do its best to map both
774 vregs to the same real register, so the copies will often disappear
775 later in the game.
776
777 This should handle expressions of 64, 32, 16 and 8-bit type.
778 All results are returned in a (mode64 ? 64bit : 32bit) register.
779 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
780 are arbitrary, so you should mask or sign extend partial values
781 if necessary.
782*/
783static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e)
784{
785 HReg r = iselWordExpr_R_wrk(env, e);
786 /* sanity checks ... */
787
788 vassert(hregClass(r) == HRcGPR(env->mode64));
789 vassert(hregIsVirtual(r));
790 return r;
791}
792
793/* DO NOT CALL THIS DIRECTLY ! */
794static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
795{
dejanjc3fee0d2013-07-25 09:08:03 +0000796 UInt argiregs = 0;
sewardj362cf842012-06-07 08:59:53 +0000797 IRType ty = typeOfIRExpr(env->type_env, e);
798 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1
799 || ty == Ity_F32 || (ty == Ity_I64 && mode64)
800 || (ty == Ity_I128 && mode64));
801
802 switch (e->tag) {
803 /* --------- TEMP --------- */
804 case Iex_RdTmp:
805 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
806
807 /* --------- LOAD --------- */
808 case Iex_Load: {
809 HReg r_dst = newVRegI(env);
810 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
811
812 if (e->Iex.Load.end != Iend_LE
813 && e->Iex.Load.end != Iend_BE)
814 goto irreducible;
815
816 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)),
817 r_dst, am_addr, mode64));
818 return r_dst;
sewardj362cf842012-06-07 08:59:53 +0000819 }
sewardj86525cb2012-06-19 16:33:47 +0000820
sewardj362cf842012-06-07 08:59:53 +0000821 /* --------- BINARY OP --------- */
822 case Iex_Binop: {
823 MIPSAluOp aluOp;
824 MIPSShftOp shftOp;
825
826 /* Is it an addition or logical style op? */
827 switch (e->Iex.Binop.op) {
dejanjc3fee0d2013-07-25 09:08:03 +0000828 case Iop_Add8:
829 case Iop_Add16:
sewardj362cf842012-06-07 08:59:53 +0000830 case Iop_Add32:
831 aluOp = Malu_ADD;
832 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000833
sewardj362cf842012-06-07 08:59:53 +0000834 case Iop_Sub8:
835 case Iop_Sub16:
836 case Iop_Sub32:
837 aluOp = Malu_SUB;
838 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000839
petarjb92a9542013-02-27 22:57:17 +0000840 case Iop_Sub64:
841 aluOp = Malu_DSUB;
842 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000843
dejanj3bc88cc2013-10-07 10:28:56 +0000844 case Iop_And8:
845 case Iop_And16:
sewardj362cf842012-06-07 08:59:53 +0000846 case Iop_And32:
847 case Iop_And64:
848 aluOp = Malu_AND;
849 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000850
851 case Iop_Or8:
852 case Iop_Or16:
sewardj362cf842012-06-07 08:59:53 +0000853 case Iop_Or32:
854 case Iop_Or64:
855 aluOp = Malu_OR;
856 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000857
dejanj3bc88cc2013-10-07 10:28:56 +0000858 case Iop_Xor8:
859 case Iop_Xor16:
sewardj362cf842012-06-07 08:59:53 +0000860 case Iop_Xor32:
861 case Iop_Xor64:
862 aluOp = Malu_XOR;
863 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000864
petarjb92a9542013-02-27 22:57:17 +0000865 case Iop_Add64:
866 aluOp = Malu_DADD;
867 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000868
sewardj362cf842012-06-07 08:59:53 +0000869 default:
870 aluOp = Malu_INVALID;
871 break;
872 }
873
874 /* For commutative ops we assume any literal
875 values are on the second operand. */
876 if (aluOp != Malu_INVALID) {
877 HReg r_dst = newVRegI(env);
878 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
879 MIPSRH *ri_srcR = NULL;
880 /* get right arg into an RH, in the appropriate way */
881 switch (aluOp) {
882 case Malu_ADD:
883 case Malu_SUB:
petarjb92a9542013-02-27 22:57:17 +0000884 case Malu_DADD:
885 case Malu_DSUB:
sewardj362cf842012-06-07 08:59:53 +0000886 ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
887 e->Iex.Binop.arg2);
888 break;
889 case Malu_AND:
890 case Malu_OR:
891 case Malu_XOR:
892 ri_srcR = iselWordExpr_RH(env, False /*unsigned */,
893 e->Iex.Binop.arg2);
894 break;
895 default:
896 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
897 }
898 addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
899 return r_dst;
900 }
901
902 /* a shift? */
903 switch (e->Iex.Binop.op) {
904 case Iop_Shl32:
905 case Iop_Shl64:
906 shftOp = Mshft_SLL;
907 break;
908 case Iop_Shr32:
909 case Iop_Shr64:
910 shftOp = Mshft_SRL;
911 break;
912 case Iop_Sar32:
913 case Iop_Sar64:
914 shftOp = Mshft_SRA;
915 break;
916 default:
917 shftOp = Mshft_INVALID;
918 break;
919 }
920
921 /* we assume any literal values are on the second operand. */
922 if (shftOp != Mshft_INVALID) {
923 HReg r_dst = newVRegI(env);
924 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
dejanjc3fee0d2013-07-25 09:08:03 +0000925 MIPSRH *ri_srcR;
926 if (mode64)
927 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
928 else
929 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2);
930
931 if (ty == Ity_I8) {
932 vassert(0);
933 } else if (ty == Ity_I32) {
934 if (mode64 && (shftOp == Mshft_SRA || shftOp == Mshft_SRL)) {
935 HReg tmp = newVRegI(env);
936 HReg r_srcL_se = newVRegI(env);
937 /* SRA, SRAV, SRL, SRLV: On 64-bit processors, if GPR rt does
938 not contain a sign-extended 32-bit value (bits 63..31
939 equal), then the result of the operation is UNPREDICTABLE.
940 So we need to sign-extend r_srcL:
941 DSLLV tmp, r_srcL, 32
942 DSRAV r_srcL_se, tmp, 32
943 */
944 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tmp,
945 r_srcL, MIPSRH_Imm(False, 32)));
946 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, r_srcL_se,
947 tmp, MIPSRH_Imm(False, 32)));
948 /* And finally do the shift. */
949 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
950 r_dst, r_srcL_se, ri_srcR));
951 } else
952 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
953 r_dst, r_srcL, ri_srcR));
954 } else if (ty == Ity_I64) {
sewardj362cf842012-06-07 08:59:53 +0000955 vassert(mode64);
956 addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */,
957 r_dst, r_srcL, ri_srcR));
petarjb92a9542013-02-27 22:57:17 +0000958 } else
959 goto irreducible;
sewardj362cf842012-06-07 08:59:53 +0000960 return r_dst;
961 }
962
963 /* Cmp*32*(x,y) ? */
964 if (e->Iex.Binop.op == Iop_CmpEQ32
dejanjc3fee0d2013-07-25 09:08:03 +0000965 || e->Iex.Binop.op == Iop_CmpEQ16
sewardj362cf842012-06-07 08:59:53 +0000966 || e->Iex.Binop.op == Iop_CmpNE32
967 || e->Iex.Binop.op == Iop_CmpNE64
968 || e->Iex.Binop.op == Iop_CmpLT32S
969 || e->Iex.Binop.op == Iop_CmpLT32U
970 || e->Iex.Binop.op == Iop_CmpLT64U
dejanjc3fee0d2013-07-25 09:08:03 +0000971 || e->Iex.Binop.op == Iop_CmpLE32U
sewardj362cf842012-06-07 08:59:53 +0000972 || e->Iex.Binop.op == Iop_CmpLE32S
973 || e->Iex.Binop.op == Iop_CmpLE64S
974 || e->Iex.Binop.op == Iop_CmpLT64S
dejanj6ced72b2014-06-04 11:28:07 +0000975 || e->Iex.Binop.op == Iop_CmpEQ64
976 || e->Iex.Binop.op == Iop_CasCmpEQ32
977 || e->Iex.Binop.op == Iop_CasCmpEQ64) {
sewardj362cf842012-06-07 08:59:53 +0000978
979 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
980 || e->Iex.Binop.op == Iop_CmpLE32S
981 || e->Iex.Binop.op == Iop_CmpLT64S
982 || e->Iex.Binop.op == Iop_CmpLE64S);
983 Bool size32;
984 HReg dst = newVRegI(env);
985 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
986 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
987
988 MIPSCondCode cc;
989
990 switch (e->Iex.Binop.op) {
991 case Iop_CmpEQ32:
dejanj6ced72b2014-06-04 11:28:07 +0000992 case Iop_CasCmpEQ32:
sewardj362cf842012-06-07 08:59:53 +0000993 cc = MIPScc_EQ;
994 size32 = True;
995 break;
dejanjc3fee0d2013-07-25 09:08:03 +0000996 case Iop_CmpEQ16:
997 cc = MIPScc_EQ;
998 size32 = True;
999 break;
sewardj362cf842012-06-07 08:59:53 +00001000 case Iop_CmpNE32:
1001 cc = MIPScc_NE;
1002 size32 = True;
1003 break;
1004 case Iop_CmpNE64:
1005 cc = MIPScc_NE;
1006 size32 = True;
1007 break;
1008 case Iop_CmpLT32S:
1009 cc = MIPScc_LT;
1010 size32 = True;
1011 break;
1012 case Iop_CmpLT32U:
1013 cc = MIPScc_LO;
1014 size32 = True;
1015 break;
1016 case Iop_CmpLT64U:
1017 cc = MIPScc_LO;
1018 size32 = False;
1019 break;
dejanjc3fee0d2013-07-25 09:08:03 +00001020 case Iop_CmpLE32U:
1021 cc = MIPScc_LE;
1022 size32 = True;
1023 break;
sewardj362cf842012-06-07 08:59:53 +00001024 case Iop_CmpLE32S:
1025 cc = MIPScc_LE;
1026 size32 = True;
1027 break;
1028 case Iop_CmpLE64S:
1029 cc = MIPScc_LE;
1030 size32 = False;
1031 break;
1032 case Iop_CmpLT64S:
1033 cc = MIPScc_LT;
1034 size32 = False;
1035 break;
1036 case Iop_CmpEQ64:
dejanj6ced72b2014-06-04 11:28:07 +00001037 case Iop_CasCmpEQ64:
sewardj362cf842012-06-07 08:59:53 +00001038 cc = MIPScc_EQ;
1039 size32 = False;
1040 break;
1041 default:
petarjb92a9542013-02-27 22:57:17 +00001042 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
sewardj362cf842012-06-07 08:59:53 +00001043 }
1044
1045 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
1046 return dst;
sewardj362cf842012-06-07 08:59:53 +00001047 }
1048
1049 if (e->Iex.Binop.op == Iop_Max32U) {
sewardj362cf842012-06-07 08:59:53 +00001050 HReg tmp = newVRegI(env);
petarjb92a9542013-02-27 22:57:17 +00001051 HReg r_dst = newVRegI(env);
1052 HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1053 HReg argR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1054 MIPSRH *argRH = iselWordExpr_RH(env, False /*signed */ ,
1055 e->Iex.Binop.arg2);
1056 /* max (v0, s0)
1057 ------------
1058 slt v1, v0, s0
1059 movn v0, s0, v1 */
sewardj362cf842012-06-07 08:59:53 +00001060
petarjb92a9542013-02-27 22:57:17 +00001061 addInstr(env, MIPSInstr_Alu(Malu_SLT, tmp, argL, argRH));
1062 addInstr(env, mk_iMOVds_RR(r_dst, argL));
1063 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, argR, tmp));
1064 return r_dst;
sewardj362cf842012-06-07 08:59:53 +00001065 }
1066
1067 if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) {
1068 Bool sz32 = (e->Iex.Binop.op == Iop_Mul32);
1069 HReg r_dst = newVRegI(env);
1070 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1071 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1072 addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ ,
1073 False /*widen */ ,
1074 sz32 /*32bit or 64bit */,
1075 r_dst, r_srcL, r_srcR));
1076 return r_dst;
1077 }
1078
1079 if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) {
1080 HReg r_dst = newVRegI(env);
1081 HReg tHi = newVRegI(env);
1082 HReg tLo = newVRegI(env);
1083 HReg tLo_1 = newVRegI(env);
1084 HReg tHi_1 = newVRegI(env);
1085 HReg mask = newVRegI(env);
1086
1087 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
1088 Bool size = toBool(e->Iex.Binop.op == Iop_MullS32)
1089 || toBool(e->Iex.Binop.op == Iop_MullU32);
1090 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1091 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1092 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ ,
1093 True /*widen */ ,
1094 size /*32bit or 64bit mul */ ,
1095 r_dst, r_srcL, r_srcR));
1096
1097 addInstr(env, MIPSInstr_Mfhi(tHi));
1098 addInstr(env, MIPSInstr_Mflo(tLo));
1099
1100 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1,
1101 tHi, MIPSRH_Imm(False, 32)));
1102
1103 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1104 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1105 MIPSRH_Reg(mask)));
1106
1107 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1108 MIPSRH_Reg(tLo_1)));
1109
1110 return r_dst;
1111 }
1112
1113 if (e->Iex.Binop.op == Iop_CmpF64) {
1114 HReg r_srcL, r_srcR;
petarjb92a9542013-02-27 22:57:17 +00001115 if (mode64) {
1116 r_srcL = iselFltExpr(env, e->Iex.Binop.arg1);
1117 r_srcR = iselFltExpr(env, e->Iex.Binop.arg2);
1118 } else {
sewardj362cf842012-06-07 08:59:53 +00001119 r_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
1120 r_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
1121 }
1122 HReg tmp = newVRegI(env);
1123 HReg r_ccMIPS = newVRegI(env);
1124 HReg r_ccIR = newVRegI(env);
1125 HReg r_ccIR_b0 = newVRegI(env);
1126 HReg r_ccIR_b2 = newVRegI(env);
1127 HReg r_ccIR_b6 = newVRegI(env);
1128
1129 /* Create in dst, the IRCmpF64Result encoded result. */
petarjb92a9542013-02-27 22:57:17 +00001130 /* chech for EQ */
dejanjf37c0862014-02-25 15:25:49 +00001131 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmp, r_srcL, r_srcR));
1132 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccMIPS, tmp,
1133 MIPSRH_Imm(False, 1)));
petarjb92a9542013-02-27 22:57:17 +00001134 /* chech for UN */
dejanjf37c0862014-02-25 15:25:49 +00001135 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmp, r_srcL, r_srcR));
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 LT */
dejanjf37c0862014-02-25 15:25:49 +00001139 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmp, r_srcL, r_srcR));
1140 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp,
1141 tmp, MIPSRH_Imm(False, 2)));
sewardj362cf842012-06-07 08:59:53 +00001142 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1143 MIPSRH_Reg(tmp)));
petarjb92a9542013-02-27 22:57:17 +00001144 /* chech for GT */
dejanjf37c0862014-02-25 15:25:49 +00001145 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_NGT,
1146 tmp, r_srcL, r_srcR));
1147 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, tmp,
1148 MIPSRH_Imm(False, 3)));
sewardj362cf842012-06-07 08:59:53 +00001149
1150 addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp)));
1151 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1152 MIPSRH_Imm(False, 8)));
1153 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1154 MIPSRH_Reg(tmp)));
petarjb92a9542013-02-27 22:57:17 +00001155 /* Map compare result from MIPS to IR,
1156 conforming to CmpF64 definition.
sewardj362cf842012-06-07 08:59:53 +00001157 FP cmp result | MIPS | IR
1158 --------------------------
1159 UN | 0x1 | 0x45
1160 EQ | 0x2 | 0x40
1161 GT | 0x4 | 0x00
1162 LT | 0x8 | 0x01
1163 */
1164
petarjb92a9542013-02-27 22:57:17 +00001165 /* r_ccIR_b0 = r_ccMIPS[0] | r_ccMIPS[3] */
sewardj362cf842012-06-07 08:59:53 +00001166 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS,
1167 MIPSRH_Imm(False, 0x3)));
1168 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS,
1169 MIPSRH_Reg(r_ccIR_b0)));
1170 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0,
1171 MIPSRH_Imm(False, 0x1)));
1172
petarjb92a9542013-02-27 22:57:17 +00001173 /* r_ccIR_b2 = r_ccMIPS[0] */
sewardj362cf842012-06-07 08:59:53 +00001174 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS,
1175 MIPSRH_Imm(False, 0x2)));
1176 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2,
1177 MIPSRH_Imm(False, 0x4)));
1178
petarjb92a9542013-02-27 22:57:17 +00001179 /* r_ccIR_b6 = r_ccMIPS[0] | r_ccMIPS[1] */
sewardj362cf842012-06-07 08:59:53 +00001180 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6,
1181 r_ccMIPS, MIPSRH_Imm(False, 0x1)));
1182 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS,
1183 MIPSRH_Reg(r_ccIR_b6)));
1184 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6,
1185 MIPSRH_Imm(False, 0x6)));
1186 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6,
1187 MIPSRH_Imm(False, 0x40)));
1188
petarjb92a9542013-02-27 22:57:17 +00001189 /* r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 */
sewardj362cf842012-06-07 08:59:53 +00001190 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0,
1191 MIPSRH_Reg(r_ccIR_b2)));
1192 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR,
1193 MIPSRH_Reg(r_ccIR_b6)));
1194 return r_ccIR;
1195 }
1196
1197 if (e->Iex.Binop.op == Iop_DivModU64to32 ||
1198 e->Iex.Binop.op == Iop_DivModS64to32) {
1199 HReg tLo = newVRegI(env);
1200 HReg tHi = newVRegI(env);
1201 HReg mask = newVRegI(env);
1202 HReg tLo_1 = newVRegI(env);
1203 HReg tHi_1 = newVRegI(env);
1204 HReg r_dst = newVRegI(env);
1205 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32);
1206
1207 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1208 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1209
1210 addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
1211 addInstr(env, MIPSInstr_Mfhi(tHi));
1212 addInstr(env, MIPSInstr_Mflo(tLo));
1213
1214 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1215 MIPSRH_Imm(False, 32)));
1216
1217 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1218 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1219 MIPSRH_Reg(mask)));
1220
1221 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1222 MIPSRH_Reg(tLo_1)));
1223
1224 return r_dst;
1225 }
1226
dejanja759d172013-09-19 13:35:45 +00001227 if (e->Iex.Binop.op == Iop_8HLto16
1228 || e->Iex.Binop.op == Iop_16HLto32) {
1229 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1230 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00001231 HReg tLo_1 = newVRegI(env);
1232 HReg tHi_1 = newVRegI(env);
1233 HReg r_dst = newVRegI(env);
dejanja759d172013-09-19 13:35:45 +00001234 UInt shift = 0;
1235 UInt mask = 0;
1236 switch (e->Iex.Binop.op) {
1237 case Iop_8HLto16:
1238 shift = 8;
1239 mask = 0xff;
1240 break;
1241 case Iop_16HLto32:
1242 shift = 16;
1243 mask = 0xffff;
1244 break;
1245 default:
1246 break;
1247 }
dejanjc3fee0d2013-07-25 09:08:03 +00001248
dejanja759d172013-09-19 13:35:45 +00001249 /* sll tHi_1, tHi, shift
1250 and tLo_1, tLo, mask
1251 or r_dst, tHi_1, tLo_1 */
dejanjc3fee0d2013-07-25 09:08:03 +00001252 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi,
dejanja759d172013-09-19 13:35:45 +00001253 MIPSRH_Imm(False, shift)));
dejanjc3fee0d2013-07-25 09:08:03 +00001254 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
dejanja759d172013-09-19 13:35:45 +00001255 MIPSRH_Imm(False, mask)));
dejanjc3fee0d2013-07-25 09:08:03 +00001256 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1257 MIPSRH_Reg(tLo_1)));
dejanjc3fee0d2013-07-25 09:08:03 +00001258 return r_dst;
1259 }
1260
sewardj362cf842012-06-07 08:59:53 +00001261 if (e->Iex.Binop.op == Iop_32HLto64) {
1262 vassert(mode64);
1263 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1264 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1265 HReg tLo_1 = newVRegI(env);
1266 HReg tHi_1 = newVRegI(env);
1267 HReg r_dst = newVRegI(env);
1268 HReg mask = newVRegI(env);
1269
1270 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1271 MIPSRH_Imm(False, 32)));
1272
1273 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1274 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1275 MIPSRH_Reg(mask)));
1276 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1277 MIPSRH_Reg(tLo_1)));
1278
1279 return r_dst;
1280 }
petarjb1426ef2012-06-20 17:53:32 +00001281
petarjb92a9542013-02-27 22:57:17 +00001282 if (e->Iex.Binop.op == Iop_F32toI64S) {
1283 vassert(mode64);
1284 HReg valS = newVRegI(env);
1285 HReg tmpF = newVRegF(env);
1286 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1287
1288 /* CVTLS tmpF, valF */
1289 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1290 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpF, valF));
1291 set_MIPS_rounding_default(env);
1292
1293 /* Doubleword Move from Floating Point
1294 dmfc1 valS, tmpF */
1295 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF));
1296
1297 return valS;
1298 }
1299
petarjb1426ef2012-06-20 17:53:32 +00001300 if (e->Iex.Binop.op == Iop_F64toI32S) {
petarjb92a9542013-02-27 22:57:17 +00001301 HReg valD;
1302 if (mode64)
1303 valD = iselFltExpr(env, e->Iex.Binop.arg2);
1304 else
1305 valD = iselDblExpr(env, e->Iex.Binop.arg2);
petarjb1426ef2012-06-20 17:53:32 +00001306 HReg valS = newVRegF(env);
1307 HReg r_dst = newVRegI(env);
petarjb1426ef2012-06-20 17:53:32 +00001308
petarjb92a9542013-02-27 22:57:17 +00001309 /* CVTWD valS, valD */
petarjb1426ef2012-06-20 17:53:32 +00001310 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1311 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1312 set_MIPS_rounding_default(env);
1313
petarjb92a9542013-02-27 22:57:17 +00001314 /* Move Word From Floating Point
1315 mfc1 r_dst, valS */
1316 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
petarjb1426ef2012-06-20 17:53:32 +00001317
1318 return r_dst;
1319 }
1320
dejanjc3fee0d2013-07-25 09:08:03 +00001321 /* -------- DSP ASE -------- */
1322 /* All used cases involving host-side helper calls. */
1323 void* fn = NULL;
1324 switch (e->Iex.Binop.op) {
1325 case Iop_HAdd8Ux4:
1326 fn = &h_generic_calc_HAdd8Ux4; break;
1327 case Iop_HSub8Ux4:
1328 fn = &h_generic_calc_HSub8Ux4; break;
1329 case Iop_HSub16Sx2:
1330 fn = &h_generic_calc_HSub16Sx2; break;
1331 case Iop_QSub8Ux4:
1332 fn = &h_generic_calc_QSub8Ux4; break;
1333 default:
1334 break;
1335 }
1336
1337 /* What's the retloc? */
sewardj74142b82013-08-08 10:28:59 +00001338 RetLoc rloc = mk_RetLoc_INVALID();
dejanjc3fee0d2013-07-25 09:08:03 +00001339 if (ty == Ity_I32) {
sewardj74142b82013-08-08 10:28:59 +00001340 rloc = mk_RetLoc_simple(RLPri_Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001341 }
1342 else if (ty == Ity_I64) {
sewardj74142b82013-08-08 10:28:59 +00001343 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1344 mk_RetLoc_simple(RLPri_2Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001345 }
1346 else {
1347 goto irreducible;
1348 }
1349
1350 if (fn) {
1351 HReg regL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1352 HReg regR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1353 HReg res = newVRegI(env);
1354 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1355 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR5(env->mode64), regR));
1356 argiregs |= (1 << 4);
1357 argiregs |= (1 << 5);
1358 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
florian93a09742015-01-07 20:14:48 +00001359 (Addr)fn,
dejanjc3fee0d2013-07-25 09:08:03 +00001360 argiregs, rloc));
1361 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1362 return res;
1363 }
sewardj86525cb2012-06-19 16:33:47 +00001364 break;
petarjb1426ef2012-06-20 17:53:32 +00001365 }
sewardj362cf842012-06-07 08:59:53 +00001366
petarjb92a9542013-02-27 22:57:17 +00001367 /* --------- UNARY OP --------- */
sewardj362cf842012-06-07 08:59:53 +00001368 case Iex_Unop: {
1369 IROp op_unop = e->Iex.Unop.op;
1370
1371 switch (op_unop) {
dejanjc3fee0d2013-07-25 09:08:03 +00001372 case Iop_1Sto8:
1373 case Iop_1Sto16:
sewardj362cf842012-06-07 08:59:53 +00001374 case Iop_1Sto32:
dejanj3bc88cc2013-10-07 10:28:56 +00001375 case Iop_8Sto16:
sewardj362cf842012-06-07 08:59:53 +00001376 case Iop_8Sto32:
1377 case Iop_16Sto32:
1378 case Iop_16Sto64:
1379 case Iop_8Sto64:
1380 case Iop_1Sto64: {
1381 HReg r_dst = newVRegI(env);
1382 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1383 Bool sz32;
1384 UShort amt;
1385 switch (op_unop) {
dejanjc3fee0d2013-07-25 09:08:03 +00001386 case Iop_1Sto8:
1387 amt = 31;
1388 sz32 = True;
1389 break;
1390 case Iop_1Sto16:
1391 amt = 31;
1392 sz32 = True;
1393 break;
sewardj362cf842012-06-07 08:59:53 +00001394 case Iop_1Sto32:
1395 amt = 31;
1396 sz32 = True;
1397 break;
1398 case Iop_16Sto32:
1399 amt = 16;
1400 sz32 = True;
1401 break;
1402 case Iop_16Sto64:
1403 amt = 48;
1404 sz32 = False;
1405 break;
dejanj3bc88cc2013-10-07 10:28:56 +00001406 case Iop_8Sto16:
1407 amt = 24;
1408 sz32 = True;
1409 break;
sewardj362cf842012-06-07 08:59:53 +00001410 case Iop_8Sto32:
1411 amt = 24;
1412 sz32 = True;
1413 break;
1414 case Iop_8Sto64:
1415 amt = 56;
1416 sz32 = False;
1417 break;
1418 case Iop_1Sto64:
1419 amt = 63;
1420 sz32 = False;
1421 break;
1422 default:
1423 vassert(0);
1424 }
1425
1426 addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src,
1427 MIPSRH_Imm(False, amt)));
1428 addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst,
1429 MIPSRH_Imm(False, amt)));
1430 return r_dst;
1431 }
1432
petarjb92a9542013-02-27 22:57:17 +00001433 /* not(x) = nor(x,x) */
sewardj362cf842012-06-07 08:59:53 +00001434 case Iop_Not1: {
1435 HReg r_dst = newVRegI(env);
1436 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1437 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1438
1439 addInstr(env, MIPSInstr_LI(r_dst, 0x1));
1440 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
1441 return r_dst;
1442 }
1443
dejanjc3fee0d2013-07-25 09:08:03 +00001444 case Iop_Not8:
1445 case Iop_Not16:
sewardj362cf842012-06-07 08:59:53 +00001446 case Iop_Not32:
1447 case Iop_Not64: {
1448 HReg r_dst = newVRegI(env);
1449 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1450 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1451
1452 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR));
1453 return r_dst;
1454 }
1455
1456 case Iop_ReinterpF32asI32: {
sewardj362cf842012-06-07 08:59:53 +00001457 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1458 HReg r_dst = newVRegI(env);
1459
petarjb92a9542013-02-27 22:57:17 +00001460 /* Move Word From Floating Point
1461 mfc1 r_dst, fr_src */
1462 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, fr_src));
sewardj362cf842012-06-07 08:59:53 +00001463
sewardj362cf842012-06-07 08:59:53 +00001464 return r_dst;
1465 }
1466
1467 case Iop_ReinterpF64asI64: {
1468 vassert(mode64);
sewardj362cf842012-06-07 08:59:53 +00001469 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1470 HReg r_dst = newVRegI(env);
1471
petarjb92a9542013-02-27 22:57:17 +00001472 /* Doubleword Move from Floating Point
1473 mfc1 r_dst, fr_src */
1474 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, r_dst, fr_src));
sewardj362cf842012-06-07 08:59:53 +00001475
petarjb92a9542013-02-27 22:57:17 +00001476 return r_dst;
1477 }
sewardj362cf842012-06-07 08:59:53 +00001478
petarjb92a9542013-02-27 22:57:17 +00001479 case Iop_F64toI32S: {
1480 HReg valD;
1481 if (mode64)
1482 valD = iselFltExpr(env, e->Iex.Binop.arg2);
1483 else
1484 valD = iselDblExpr(env, e->Iex.Binop.arg2);
1485 HReg valS = newVRegF(env);
1486 HReg r_dst = newVRegI(env);
1487
1488 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1489 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1490 set_MIPS_rounding_default(env);
1491
1492 /* Move Word From Floating Point
1493 mfc1 r_dst, valS */
1494 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1495
sewardj362cf842012-06-07 08:59:53 +00001496 return r_dst;
1497 }
sewardj362cf842012-06-07 08:59:53 +00001498
dejanjc3fee0d2013-07-25 09:08:03 +00001499 case Iop_16to8:
dejanj3bc88cc2013-10-07 10:28:56 +00001500 case Iop_32to1:
sewardj362cf842012-06-07 08:59:53 +00001501 case Iop_32to8:
1502 case Iop_32to16:
1503 return iselWordExpr_R(env, e->Iex.Unop.arg);
dejanjc3fee0d2013-07-25 09:08:03 +00001504
1505 case Iop_32HIto16: {
1506 HReg r_dst = newVRegI(env);
1507 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1508 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1509 r_dst, r_src, MIPSRH_Imm(False, 16)));
1510 return r_dst;
1511 }
sewardj362cf842012-06-07 08:59:53 +00001512
dejanj3bc88cc2013-10-07 10:28:56 +00001513 case Iop_64to1:
sewardj362cf842012-06-07 08:59:53 +00001514 case Iop_64to8: {
1515 vassert(mode64);
1516 HReg r_src, r_dst;
dejanj3bc88cc2013-10-07 10:28:56 +00001517 UShort mask = (op_unop == Iop_64to1) ? 0x1 : 0xFF;
sewardj362cf842012-06-07 08:59:53 +00001518 r_dst = newVRegI(env);
1519 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1520 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
dejanj3bc88cc2013-10-07 10:28:56 +00001521 MIPSRH_Imm(False, mask)));
sewardj362cf842012-06-07 08:59:53 +00001522 return r_dst;
1523 }
petarja81d9be2013-01-30 18:06:26 +00001524
dejanjc3fee0d2013-07-25 09:08:03 +00001525 case Iop_16HIto8: {
1526 HReg r_dst = newVRegI(env);
1527 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1528 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1529 r_dst, r_src, MIPSRH_Imm(False, 8)));
1530 return r_dst;
1531 }
1532
dejanj3bc88cc2013-10-07 10:28:56 +00001533 case Iop_1Uto8:
petarja81d9be2013-01-30 18:06:26 +00001534 case Iop_1Uto32:
dejanja759d172013-09-19 13:35:45 +00001535 case Iop_1Uto64:
1536 case Iop_8Uto16:
sewardj362cf842012-06-07 08:59:53 +00001537 case Iop_8Uto32:
dejanja759d172013-09-19 13:35:45 +00001538 case Iop_8Uto64:
1539 case Iop_16Uto32:
1540 case Iop_16Uto64: {
sewardj362cf842012-06-07 08:59:53 +00001541 HReg r_dst = newVRegI(env);
1542 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001543 UShort mask = 0;
sewardj362cf842012-06-07 08:59:53 +00001544 switch (op_unop) {
dejanja759d172013-09-19 13:35:45 +00001545 case Iop_1Uto64:
1546 vassert(mode64);
dejanj3bc88cc2013-10-07 10:28:56 +00001547 case Iop_1Uto8:
sewardj362cf842012-06-07 08:59:53 +00001548 case Iop_1Uto32:
dejanja759d172013-09-19 13:35:45 +00001549 mask = toUShort(0x1);
sewardj362cf842012-06-07 08:59:53 +00001550 break;
dejanja759d172013-09-19 13:35:45 +00001551 case Iop_8Uto64:
1552 vassert(mode64);
1553 case Iop_8Uto16:
petarja81d9be2013-01-30 18:06:26 +00001554 case Iop_8Uto32:
dejanja759d172013-09-19 13:35:45 +00001555 mask = toUShort(0xFF);
petarja81d9be2013-01-30 18:06:26 +00001556 break;
dejanja759d172013-09-19 13:35:45 +00001557 case Iop_16Uto64:
1558 vassert(mode64);
sewardj362cf842012-06-07 08:59:53 +00001559 case Iop_16Uto32:
dejanja759d172013-09-19 13:35:45 +00001560 mask = toUShort(0xFFFF);
sewardj362cf842012-06-07 08:59:53 +00001561 break;
sewardj362cf842012-06-07 08:59:53 +00001562 default:
petarja81d9be2013-01-30 18:06:26 +00001563 vassert(0);
sewardj362cf842012-06-07 08:59:53 +00001564 break;
1565 }
sewardj362cf842012-06-07 08:59:53 +00001566 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1567 MIPSRH_Imm(False, mask)));
1568 return r_dst;
1569 }
1570
1571 case Iop_32Uto64: {
1572 HReg r_dst = newVRegI(env);
1573 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1574 vassert(mode64);
petarjb92a9542013-02-27 22:57:17 +00001575 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False /*!32bit shift */,
sewardj362cf842012-06-07 08:59:53 +00001576 r_dst, r_src, MIPSRH_Imm(False, 32)));
petarjb92a9542013-02-27 22:57:17 +00001577 addInstr(env, MIPSInstr_Shft(Mshft_SRL, False /*!32bit shift */,
sewardj362cf842012-06-07 08:59:53 +00001578 r_dst, r_dst, MIPSRH_Imm(False, 32)));
1579 return r_dst;
1580 }
1581
sewardj362cf842012-06-07 08:59:53 +00001582 case Iop_64HIto32: {
petarjb92a9542013-02-27 22:57:17 +00001583 if (env->mode64) {
1584 HReg r_dst = newVRegI(env);
1585 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1586 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False /*64bit shift */,
1587 r_dst, r_src, MIPSRH_Imm(True, 32)));
1588 return r_dst;
1589 } else {
1590 HReg rHi, rLo;
1591 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1592 return rHi;
1593 }
sewardj362cf842012-06-07 08:59:53 +00001594 }
1595
1596 case Iop_64to32: {
petarjb92a9542013-02-27 22:57:17 +00001597 if (env->mode64) {
1598 HReg r_dst = newVRegI(env);
1599 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1600 return r_dst;
1601 } else {
1602 HReg rHi, rLo;
1603 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
1604 return rLo;
1605 }
sewardj362cf842012-06-07 08:59:53 +00001606 }
petarjb92a9542013-02-27 22:57:17 +00001607
sewardj362cf842012-06-07 08:59:53 +00001608 case Iop_64to16: {
1609 vassert(env->mode64);
1610 HReg r_dst = newVRegI(env);
1611 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
1612 return r_dst;
1613 }
petarjb92a9542013-02-27 22:57:17 +00001614
sewardj362cf842012-06-07 08:59:53 +00001615 case Iop_32Sto64: {
1616 HReg r_dst = newVRegI(env);
1617 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1618 vassert(mode64);
petarjb92a9542013-02-27 22:57:17 +00001619 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*!32bit shift */,
sewardj362cf842012-06-07 08:59:53 +00001620 r_dst, r_src, MIPSRH_Imm(True, 0)));
1621 return r_dst;
1622 }
petarjb92a9542013-02-27 22:57:17 +00001623
dejanja759d172013-09-19 13:35:45 +00001624 case Iop_CmpNEZ8:
dejanjc3fee0d2013-07-25 09:08:03 +00001625 case Iop_CmpNEZ16: {
1626 HReg r_dst = newVRegI(env);
1627 HReg tmp = newVRegI(env);
1628 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001629 UShort mask = (op_unop == Iop_CmpNEZ8) ? 0xFF : 0xFFFF;
dejanjc3fee0d2013-07-25 09:08:03 +00001630
dejanjc3fee0d2013-07-25 09:08:03 +00001631 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src,
dejanja759d172013-09-19 13:35:45 +00001632 MIPSRH_Imm(False, mask)));
dejanjc3fee0d2013-07-25 09:08:03 +00001633 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp,
dejanja759d172013-09-19 13:35:45 +00001634 hregMIPS_GPR0(mode64), MIPScc_NE));
dejanjc3fee0d2013-07-25 09:08:03 +00001635 return r_dst;
1636 }
1637
sewardj362cf842012-06-07 08:59:53 +00001638 case Iop_CmpNEZ32: {
1639 HReg r_dst = newVRegI(env);
1640 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1641
sewardj362cf842012-06-07 08:59:53 +00001642 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src,
dejanja759d172013-09-19 13:35:45 +00001643 hregMIPS_GPR0(mode64), MIPScc_NE));
sewardj362cf842012-06-07 08:59:53 +00001644 return r_dst;
1645 }
1646
1647 case Iop_CmpwNEZ32: {
1648 HReg r_dst = newVRegI(env);
1649 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1650
1651 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
1652 MIPSRH_Reg(r_src)));
1653
1654 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1655 MIPSRH_Reg(r_src)));
1656 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst,
1657 MIPSRH_Imm(False, 31)));
1658 return r_dst;
1659 }
1660
1661 case Iop_Left8:
dejanjc3fee0d2013-07-25 09:08:03 +00001662 case Iop_Left16:
sewardj362cf842012-06-07 08:59:53 +00001663 case Iop_Left32:
1664 case Iop_Left64: {
1665 if (op_unop == Iop_Left64 && !mode64)
1666 goto irreducible;
1667 HReg r_dst = newVRegI(env);
1668 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001669 MIPSAluOp op = (op_unop == Iop_Left64) ? Malu_DSUB : Malu_SUB;
1670 addInstr(env, MIPSInstr_Alu(op, r_dst,
1671 hregMIPS_GPR0(mode64),
1672 MIPSRH_Reg(r_src)));
sewardj362cf842012-06-07 08:59:53 +00001673 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1674 MIPSRH_Reg(r_src)));
1675 return r_dst;
1676 }
1677
dejanja759d172013-09-19 13:35:45 +00001678 case Iop_Clz64:
1679 vassert(mode64);
sewardj362cf842012-06-07 08:59:53 +00001680 case Iop_Clz32: {
1681 HReg r_dst = newVRegI(env);
1682 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
dejanja759d172013-09-19 13:35:45 +00001683 MIPSUnaryOp op = (op_unop == Iop_Clz64) ? Mun_DCLZ : Mun_CLZ;
1684 addInstr(env, MIPSInstr_Unary(op, r_dst, r_src));
petarjb92a9542013-02-27 22:57:17 +00001685 return r_dst;
1686 }
1687
sewardj362cf842012-06-07 08:59:53 +00001688 case Iop_CmpNEZ64: {
1689 HReg hi, lo;
1690 HReg r_dst = newVRegI(env);
1691 HReg r_src;
petarjb92a9542013-02-27 22:57:17 +00001692 if (env->mode64) {
1693 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1694 } else {
1695 r_src = newVRegI(env);
1696 iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg);
1697 addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi)));
1698 }
sewardj362cf842012-06-07 08:59:53 +00001699 addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src,
dejanja759d172013-09-19 13:35:45 +00001700 hregMIPS_GPR0(mode64), MIPScc_NE));
sewardj362cf842012-06-07 08:59:53 +00001701 return r_dst;
1702 }
1703
1704 case Iop_CmpwNEZ64: {
1705 HReg tmp1;
1706 HReg tmp2 = newVRegI(env);
1707 vassert(env->mode64);
1708 tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
1709
dejanj81d4ff22013-09-11 15:34:37 +00001710 addInstr(env, MIPSInstr_Alu(Malu_DSUB, tmp2, hregMIPS_GPR0(mode64),
sewardj362cf842012-06-07 08:59:53 +00001711 MIPSRH_Reg(tmp1)));
1712
1713 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
1714 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2,
1715 MIPSRH_Imm (False, 63)));
1716 return tmp2;
1717 }
1718
1719 case Iop_128HIto64: {
1720 vassert(mode64);
1721 HReg rHi, rLo;
1722 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
petarjb92a9542013-02-27 22:57:17 +00001723 return rHi; /* and abandon rLo .. poor wee thing :-) */
sewardj362cf842012-06-07 08:59:53 +00001724 }
1725
1726 case Iop_128to64: {
1727 vassert(mode64);
1728 HReg rHi, rLo;
1729 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
petarjb92a9542013-02-27 22:57:17 +00001730 return rLo; /* and abandon rLo .. poor wee thing :-) */
sewardj362cf842012-06-07 08:59:53 +00001731 }
1732
1733 default:
1734 break;
1735 }
dejanjc3fee0d2013-07-25 09:08:03 +00001736
1737 /* -------- DSP ASE -------- */
1738 /* All Unop cases involving host-side helper calls. */
1739 void* fn = NULL;
1740 switch (e->Iex.Unop.op) {
1741 case Iop_CmpNEZ16x2:
1742 fn = &h_generic_calc_CmpNEZ16x2; break;
1743 case Iop_CmpNEZ8x4:
1744 fn = &h_generic_calc_CmpNEZ8x4; break;
1745 default:
1746 break;
1747 }
1748
sewardj74142b82013-08-08 10:28:59 +00001749 RetLoc rloc = mk_RetLoc_INVALID();
dejanjc3fee0d2013-07-25 09:08:03 +00001750 if (ty == Ity_I32) {
sewardj74142b82013-08-08 10:28:59 +00001751 rloc = mk_RetLoc_simple(RLPri_Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001752 }
1753 else if (ty == Ity_I64) {
sewardj74142b82013-08-08 10:28:59 +00001754 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1755 mk_RetLoc_simple(RLPri_2Int);
dejanjc3fee0d2013-07-25 09:08:03 +00001756 }
1757 else {
1758 goto irreducible;
1759 }
1760
1761 if (fn) {
1762 HReg regL = iselWordExpr_R(env, e->Iex.Unop.arg);
1763 HReg res = newVRegI(env);
1764 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1765 argiregs |= (1 << 4);
1766 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
florian93a09742015-01-07 20:14:48 +00001767 (Addr)fn,
dejanjc3fee0d2013-07-25 09:08:03 +00001768 argiregs, rloc));
1769 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1770 return res;
1771 }
1772
sewardj362cf842012-06-07 08:59:53 +00001773 break;
1774 }
1775
petarjb92a9542013-02-27 22:57:17 +00001776 /* --------- GET --------- */
sewardj362cf842012-06-07 08:59:53 +00001777 case Iex_Get: {
1778 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
1779 || ((ty == Ity_I64) && mode64)) {
1780 HReg r_dst = newVRegI(env);
1781
1782 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
1783 GuestStatePointer(mode64));
1784 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr,
1785 mode64));
1786 return r_dst;
1787 }
sewardj86525cb2012-06-19 16:33:47 +00001788 break;
sewardj362cf842012-06-07 08:59:53 +00001789 }
1790
petarjb92a9542013-02-27 22:57:17 +00001791 /* --------- ITE --------- */
florian99dd03e2013-01-29 03:56:06 +00001792 case Iex_ITE: {
sewardj362cf842012-06-07 08:59:53 +00001793 if ((ty == Ity_I8 || ty == Ity_I16 ||
1794 ty == Ity_I32 || ((ty == Ity_I64))) &&
petarjd4564182013-01-29 15:42:29 +00001795 typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
dejanj781f1bd2013-10-23 14:05:15 +00001796 HReg r_dst = iselWordExpr_R(env, e->Iex.ITE.iffalse);
1797 HReg r1 = iselWordExpr_R(env, e->Iex.ITE.iftrue);
1798 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
sewardj362cf842012-06-07 08:59:53 +00001799 /*
dejanj781f1bd2013-10-23 14:05:15 +00001800 * r_dst = r0
1801 * movn r_dst, r1, r_cond
sewardj362cf842012-06-07 08:59:53 +00001802 */
dejanj781f1bd2013-10-23 14:05:15 +00001803 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, r1, r_cond));
sewardj362cf842012-06-07 08:59:53 +00001804 return r_dst;
1805 }
sewardj86525cb2012-06-19 16:33:47 +00001806 break;
sewardj362cf842012-06-07 08:59:53 +00001807 }
1808
petarjb92a9542013-02-27 22:57:17 +00001809 /* --------- LITERAL --------- */
1810 /* 32/16/8-bit literals */
sewardj362cf842012-06-07 08:59:53 +00001811 case Iex_Const: {
1812 Long l;
1813 HReg r_dst = newVRegI(env);
1814 IRConst *con = e->Iex.Const.con;
1815 switch (con->tag) {
1816 case Ico_U64:
1817 if (!mode64)
1818 goto irreducible;
1819 l = (Long) con->Ico.U64;
1820 break;
1821 case Ico_U32:
1822 l = (Long) (Int) con->Ico.U32;
1823 break;
1824 case Ico_U16:
1825 l = (Long) (Int) (Short) con->Ico.U16;
1826 break;
1827 case Ico_U8:
1828 l = (Long) (Int) (Char) con->Ico.U8;
1829 break;
1830 default:
1831 vpanic("iselIntExpr_R.const(mips)");
1832 }
1833 addInstr(env, MIPSInstr_LI(r_dst, (ULong) l));
1834 return r_dst;
1835 }
1836
petarjb92a9542013-02-27 22:57:17 +00001837 /* --------- CCALL --------- */
sewardj362cf842012-06-07 08:59:53 +00001838 case Iex_CCall: {
1839 HReg r_dst = newVRegI(env);
1840 vassert(ty == e->Iex.CCall.retty);
1841
sewardjcfe046e2013-01-17 14:23:53 +00001842 /* be very restrictive for now. Only 32/64-bit ints allowed for
dejanjd69cd9a2013-08-16 12:11:20 +00001843 args, and 64 and 32 bits for return type. Don't forget to change
sewardjcfe046e2013-01-17 14:23:53 +00001844 the RetLoc if more return types are allowed in future. */
dejanjd69cd9a2013-08-16 12:11:20 +00001845 if (e->Iex.CCall.retty != Ity_I64 && e->Iex.CCall.retty != Ity_I32)
sewardj362cf842012-06-07 08:59:53 +00001846 goto irreducible;
1847
1848 /* Marshal args, do the call, clear stack. */
sewardj74142b82013-08-08 10:28:59 +00001849 UInt addToSp = 0;
1850 RetLoc rloc = mk_RetLoc_INVALID();
1851 doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
1852 e->Iex.CCall.retty, e->Iex.CCall.args );
1853
1854 vassert(is_sane_RetLoc(rloc));
1855 vassert(rloc.pri == RLPri_Int);
1856 vassert(addToSp == 0);
sewardj362cf842012-06-07 08:59:53 +00001857 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
1858 return r_dst;
1859 }
1860
1861 default:
1862 break;
petarjb92a9542013-02-27 22:57:17 +00001863 } /* end switch(e->tag) */
sewardj362cf842012-06-07 08:59:53 +00001864
1865 /* We get here if no pattern matched. */
1866 irreducible:
1867 vex_printf("--------------->\n");
1868 if (e->tag == Iex_RdTmp)
1869 vex_printf("Iex_RdTmp \n");
1870 ppIRExpr(e);
1871
1872 vpanic("iselWordExpr_R(mips): cannot reduce tree");
1873}
1874
1875/* --------------------- RH --------------------- */
1876
1877/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
1878 (reg-or-halfword-immediate). It's important to specify whether the
1879 immediate is to be regarded as signed or not. If yes, this will
1880 never return -32768 as an immediate; this guaranteed that all
1881 signed immediates that are return can have their sign inverted if
1882 need be. */
1883
1884static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e)
1885{
1886 MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e);
1887 /* sanity checks ... */
1888 switch (ri->tag) {
1889 case Mrh_Imm:
1890 vassert(ri->Mrh.Imm.syned == syned);
1891 if (syned)
1892 vassert(ri->Mrh.Imm.imm16 != 0x8000);
1893 return ri;
1894 case Mrh_Reg:
1895 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
1896 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1897 return ri;
1898 default:
1899 vpanic("iselIntExpr_RH: unknown mips RH tag");
1900 }
1901}
1902
1903/* DO NOT CALL THIS DIRECTLY ! */
1904static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e)
1905{
1906 ULong u;
1907 Long l;
1908 IRType ty = typeOfIRExpr(env->type_env, e);
1909 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
1910 ((ty == Ity_I64) && env->mode64));
1911
1912 /* special case: immediate */
1913 if (e->tag == Iex_Const) {
1914 IRConst *con = e->Iex.Const.con;
1915 /* What value are we aiming to generate? */
1916 switch (con->tag) {
1917 /* Note: Not sign-extending - we carry 'syned' around */
1918 case Ico_U64:
1919 vassert(env->mode64);
1920 u = con->Ico.U64;
1921 break;
1922 case Ico_U32:
1923 u = 0xFFFFFFFF & con->Ico.U32;
1924 break;
1925 case Ico_U16:
1926 u = 0x0000FFFF & con->Ico.U16;
1927 break;
1928 case Ico_U8:
1929 u = 0x000000FF & con->Ico.U8;
1930 break;
1931 default:
1932 vpanic("iselIntExpr_RH.Iex_Const(mips)");
1933 }
1934 l = (Long) u;
1935 /* Now figure out if it's representable. */
1936 if (!syned && u <= 65535) {
1937 return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
1938 }
1939 if (syned && l >= -32767 && l <= 32767) {
1940 return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
1941 }
1942 /* no luck; use the Slow Way. */
1943 }
1944 /* default case: calculate into a register and return that */
1945 return MIPSRH_Reg(iselWordExpr_R(env, e));
1946}
1947
1948/* --------------------- RH5u --------------------- */
1949
1950/* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
1951 being an immediate in the range 1 .. 31 inclusive. Used for doing
1952 shift amounts. */
1953
1954static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e)
1955{
1956 MIPSRH *ri;
1957 ri = iselWordExpr_RH5u_wrk(env, e);
1958 /* sanity checks ... */
1959 switch (ri->tag) {
1960 case Mrh_Imm:
1961 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31);
1962 vassert(!ri->Mrh.Imm.syned);
1963 return ri;
1964 case Mrh_Reg:
1965 vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32);
1966 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
1967 return ri;
1968 default:
1969 vpanic("iselIntExpr_RH5u: unknown mips RH tag");
1970 }
1971}
1972
1973/* DO NOT CALL THIS DIRECTLY ! */
1974static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e)
1975{
1976 IRType ty = typeOfIRExpr(env->type_env, e);
1977 vassert(ty == Ity_I8);
1978
1979 /* special case: immediate */
1980 if (e->tag == Iex_Const
1981 && e->Iex.Const.con->tag == Ico_U8
1982 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) {
1983 return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
1984 }
1985
1986 /* default case: calculate into a register and return that */
1987 return MIPSRH_Reg(iselWordExpr_R(env, e));
1988}
1989
petarjb92a9542013-02-27 22:57:17 +00001990/* --------------------- RH6u --------------------- */
1991
1992/* Only used in 64-bit mode. */
1993static MIPSRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e )
1994{
1995 MIPSRH *ri;
petarjb92a9542013-02-27 22:57:17 +00001996 ri = iselWordExpr_RH6u_wrk(env, e);
1997 /* sanity checks ... */
1998 switch (ri->tag) {
1999 case Mrh_Imm:
2000 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 63);
2001 vassert(!ri->Mrh.Imm.syned);
2002 return ri;
2003 case Mrh_Reg:
2004 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
2005 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2006 return ri;
2007 default:
2008 vpanic("iselIntExpr_RH6u: unknown mips64 RI tag");
2009 }
2010}
2011
2012/* DO NOT CALL THIS DIRECTLY ! */
2013static MIPSRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e )
2014{
2015 IRType ty = typeOfIRExpr(env->type_env, e);
2016 vassert(ty == Ity_I8);
2017
2018 /* special case: immediate */
2019 if (e->tag == Iex_Const
2020 && e->Iex.Const.con->tag == Ico_U8
2021 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 63)
2022 {
2023 return MIPSRH_Imm(False /*unsigned */ ,
2024 e->Iex.Const.con->Ico.U8);
2025 }
2026
2027 /* default case: calculate into a register and return that */
2028 return MIPSRH_Reg(iselWordExpr_R(env, e));
2029}
2030
sewardj362cf842012-06-07 08:59:53 +00002031/* --------------------- CONDCODE --------------------- */
2032
2033/* Generate code to evaluated a bit-typed expression, returning the
2034 condition code which would correspond when the expression would
2035 notionally have returned 1. */
2036
2037static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e)
2038{
2039 MIPSCondCode cc = iselCondCode_wrk(env,e);
2040 vassert(cc != MIPScc_NV);
2041 return cc;
2042}
2043
2044/* DO NOT CALL THIS DIRECTLY ! */
2045static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
2046{
2047 vassert(e);
2048 vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
2049 /* Cmp*32*(x,y) ? */
2050 if (e->Iex.Binop.op == Iop_CmpEQ32
2051 || e->Iex.Binop.op == Iop_CmpNE32
2052 || e->Iex.Binop.op == Iop_CmpNE64
2053 || e->Iex.Binop.op == Iop_CmpLT32S
2054 || e->Iex.Binop.op == Iop_CmpLT32U
2055 || e->Iex.Binop.op == Iop_CmpLT64U
2056 || e->Iex.Binop.op == Iop_CmpLE32S
2057 || e->Iex.Binop.op == Iop_CmpLE64S
2058 || e->Iex.Binop.op == Iop_CmpLT64S
dejanj6ced72b2014-06-04 11:28:07 +00002059 || e->Iex.Binop.op == Iop_CmpEQ64
2060 || e->Iex.Binop.op == Iop_CasCmpEQ32
2061 || e->Iex.Binop.op == Iop_CasCmpEQ64) {
sewardj362cf842012-06-07 08:59:53 +00002062
2063 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
2064 || e->Iex.Binop.op == Iop_CmpLE32S
2065 || e->Iex.Binop.op == Iop_CmpLT64S
2066 || e->Iex.Binop.op == Iop_CmpLE64S);
2067 Bool size32;
2068 HReg dst = newVRegI(env);
2069 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2070 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
2071
2072 MIPSCondCode cc;
2073
2074 switch (e->Iex.Binop.op) {
2075 case Iop_CmpEQ32:
dejanj6ced72b2014-06-04 11:28:07 +00002076 case Iop_CasCmpEQ32:
sewardj362cf842012-06-07 08:59:53 +00002077 cc = MIPScc_EQ;
2078 size32 = True;
2079 break;
2080 case Iop_CmpNE32:
2081 cc = MIPScc_NE;
2082 size32 = True;
2083 break;
2084 case Iop_CmpNE64:
2085 cc = MIPScc_NE;
2086 size32 = True;
2087 break;
2088 case Iop_CmpLT32S:
2089 cc = MIPScc_LT;
2090 size32 = True;
2091 break;
2092 case Iop_CmpLT32U:
2093 cc = MIPScc_LO;
2094 size32 = True;
2095 break;
2096 case Iop_CmpLT64U:
2097 cc = MIPScc_LO;
2098 size32 = False;
2099 break;
2100 case Iop_CmpLE32S:
2101 cc = MIPScc_LE;
2102 size32 = True;
2103 break;
2104 case Iop_CmpLE64S:
2105 cc = MIPScc_LE;
2106 size32 = False;
2107 break;
2108 case Iop_CmpLT64S:
2109 cc = MIPScc_LT;
2110 size32 = False;
2111 break;
2112 case Iop_CmpEQ64:
dejanj6ced72b2014-06-04 11:28:07 +00002113 case Iop_CasCmpEQ64:
sewardj362cf842012-06-07 08:59:53 +00002114 cc = MIPScc_EQ;
2115 size32 = False;
2116 break;
2117 default:
dejanja759d172013-09-19 13:35:45 +00002118 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
2119 break;
sewardj362cf842012-06-07 08:59:53 +00002120 }
2121
2122 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
petarjb92a9542013-02-27 22:57:17 +00002123 /* Store result to guest_COND */
sewardj362cf842012-06-07 08:59:53 +00002124 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2125
2126 addInstr(env, MIPSInstr_Store(4,
petarjb92a9542013-02-27 22:57:17 +00002127 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2128 am_addr->Mam.IR.base),
sewardj362cf842012-06-07 08:59:53 +00002129 dst, mode64));
2130 return cc;
2131 }
2132 if (e->Iex.Binop.op == Iop_Not1) {
2133 HReg r_dst = newVRegI(env);
2134 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
2135 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
2136
2137 addInstr(env, MIPSInstr_LI(r_dst, 0x1));
2138 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
petarjb92a9542013-02-27 22:57:17 +00002139 /* Store result to guest_COND */
sewardj362cf842012-06-07 08:59:53 +00002140 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2141
2142 addInstr(env, MIPSInstr_Store(4,
petarjb92a9542013-02-27 22:57:17 +00002143 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2144 am_addr->Mam.IR.base),
sewardj362cf842012-06-07 08:59:53 +00002145 r_dst, mode64));
2146 return MIPScc_NE;
2147 }
2148 if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) {
2149 HReg r_dst = iselWordExpr_R_wrk(env, e);
petarjb92a9542013-02-27 22:57:17 +00002150 /* Store result to guest_COND */
sewardj362cf842012-06-07 08:59:53 +00002151 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2152
2153 addInstr(env, MIPSInstr_Store(4,
petarjb92a9542013-02-27 22:57:17 +00002154 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2155 am_addr->Mam.IR.base),
sewardj362cf842012-06-07 08:59:53 +00002156 r_dst, mode64));
2157 return MIPScc_EQ;
2158 }
2159
2160 vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag);
2161 ppIRExpr(e);
2162 vpanic("iselCondCode(mips)");
2163}
2164
2165/*---------------------------------------------------------*/
2166/*--- ISEL: Integer expressions (128 bit) ---*/
2167/*---------------------------------------------------------*/
2168
2169/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
2170 which is returned as the first two parameters. As with
2171 iselWordExpr_R, these may be either real or virtual regs; in any
2172 case they must not be changed by subsequent code emitted by the
2173 caller. */
2174
2175static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2176{
2177 vassert(env->mode64);
2178 iselInt128Expr_wrk(rHi, rLo, env, e);
sewardj362cf842012-06-07 08:59:53 +00002179 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
2180 vassert(hregIsVirtual(*rHi));
2181 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
2182 vassert(hregIsVirtual(*rLo));
2183}
2184
2185/* DO NOT CALL THIS DIRECTLY ! */
2186static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
2187 IRExpr * e)
2188{
2189 vassert(e);
2190 vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
2191
2192 /* read 128-bit IRTemp */
2193 if (e->tag == Iex_RdTmp) {
2194 lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
2195 return;
2196 }
2197
2198 /* --------- BINARY ops --------- */
2199 if (e->tag == Iex_Binop) {
2200 switch (e->Iex.Binop.op) {
2201 /* 64 x 64 -> 128 multiply */
2202 case Iop_MullU64:
dejanj3bc88cc2013-10-07 10:28:56 +00002203 case Iop_MullS64: {
2204 HReg tLo = newVRegI(env);
2205 HReg tHi = newVRegI(env);
2206 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
2207 HReg r_dst = newVRegI(env);
2208 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2209 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2210 addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ ,
2211 r_dst, r_srcL, r_srcR));
2212 addInstr(env, MIPSInstr_Mfhi(tHi));
2213 addInstr(env, MIPSInstr_Mflo(tLo));
2214 *rHi = tHi;
2215 *rLo = tLo;
2216 return;
2217 }
dejanjc3fee0d2013-07-25 09:08:03 +00002218
sewardj362cf842012-06-07 08:59:53 +00002219 /* 64HLto128(e1,e2) */
2220 case Iop_64HLto128:
2221 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2222 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2223 return;
dejanjc3fee0d2013-07-25 09:08:03 +00002224
sewardj362cf842012-06-07 08:59:53 +00002225 case Iop_DivModS64to64: {
2226 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2227 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2228 HReg tLo = newVRegI(env);
2229 HReg tHi = newVRegI(env);
2230 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
2231
2232 addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
2233 addInstr(env, MIPSInstr_Mfhi(tHi));
2234 addInstr(env, MIPSInstr_Mflo(tLo));
2235 *rHi = tHi;
2236 *rLo = tLo;
2237 return;
2238 }
dejanjc3fee0d2013-07-25 09:08:03 +00002239
dejanj3bc88cc2013-10-07 10:28:56 +00002240 case Iop_DivModU128to64:
2241 case Iop_DivModS128to64: {
sewardj362cf842012-06-07 08:59:53 +00002242 vassert(mode64);
2243 HReg rHi1, rLo1;
2244 iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1);
2245
2246 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2247 HReg tLo = newVRegI(env);
2248 HReg tHi = newVRegI(env);
2249 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64);
2250
2251 addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR));
2252 addInstr(env, MIPSInstr_Mfhi(tHi));
2253 addInstr(env, MIPSInstr_Mflo(tLo));
2254 *rHi = tHi;
2255 *rLo = tLo;
2256 return;
2257 }
dejanjc3fee0d2013-07-25 09:08:03 +00002258
sewardj362cf842012-06-07 08:59:53 +00002259 default:
2260 break;
2261 }
2262 }
2263 vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag);
2264 ppIRExpr(e);
2265 vpanic("iselInt128Expr(mips64)");
2266}
2267
2268/*---------------------------------------------------------*/
2269/*--- ISEL: Integer expressions (64 bit) ---*/
2270/*---------------------------------------------------------*/
2271
dejanjc3fee0d2013-07-25 09:08:03 +00002272/* 32-bit mode ONLY. Compute a 64-bit value into the register
sewardj362cf842012-06-07 08:59:53 +00002273 * pair HI, LO. HI and LO must not be changed by subsequent
2274 * code emitted by the caller. */
2275
2276static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2277{
2278 vassert(!env->mode64);
2279 iselInt64Expr_wrk(rHi, rLo, env, e);
2280 vassert(hregClass(*rHi) == HRcInt32);
2281 vassert(hregIsVirtual(*rHi));
2282 vassert(hregClass(*rLo) == HRcInt32);
2283 vassert(hregIsVirtual(*rLo));
2284}
2285
2286/* DO NOT CALL THIS DIRECTLY ! */
2287static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
2288{
2289 vassert(e);
2290 vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
2291
2292 /* read 64-bit IRTemp */
2293 if (e->tag == Iex_RdTmp) {
2294 lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp);
2295 return;
2296 }
2297 /* 64-bit load */
2298 if (e->tag == Iex_Load) {
2299 HReg tLo = newVRegI(env);
2300 HReg tHi = newVRegI(env);
2301 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
2302 addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64));
2303 addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64));
2304 *rHi = tHi;
2305 *rLo = tLo;
2306 return;
2307 }
2308
2309 /* 64-bit literal */
2310 if (e->tag == Iex_Const) {
2311 ULong w64 = e->Iex.Const.con->Ico.U64;
2312 UInt wHi = toUInt(w64 >> 32);
2313 UInt wLo = toUInt(w64);
2314 HReg tLo = newVRegI(env);
2315 HReg tHi = newVRegI(env);
2316 vassert(e->Iex.Const.con->tag == Ico_U64);
2317
2318 if (wLo == wHi) {
2319 /* Save a precious Int register in this special case. */
2320 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
2321 *rHi = tLo;
2322 *rLo = tLo;
2323 } else {
2324 addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi));
2325 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
2326 *rHi = tHi;
2327 *rLo = tLo;
2328 }
2329
2330 return;
2331 }
2332
2333 /* 64-bit GET */
2334 if (e->tag == Iex_Get) {
2335 HReg tLo = newVRegI(env);
2336 HReg tHi = newVRegI(env);
2337
2338 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
2339 GuestStatePointer(mode64));
2340 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2341 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64));
2342 *rHi = tHi;
2343 *rLo = tLo;
2344 return;
2345 }
2346
florian99dd03e2013-01-29 03:56:06 +00002347 /* 64-bit ITE */
2348 if (e->tag == Iex_ITE) {
petarjd4564182013-01-29 15:42:29 +00002349 vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1);
sewardj362cf842012-06-07 08:59:53 +00002350 HReg expr0Lo, expr0Hi;
florian99dd03e2013-01-29 03:56:06 +00002351 HReg expr1Lo, expr1Hi;
dejanja759d172013-09-19 13:35:45 +00002352 HReg desLo = newVRegI(env);
2353 HReg desHi = newVRegI(env);
2354 HReg cond = iselWordExpr_R(env, e->Iex.ITE.cond);
petarjd4564182013-01-29 15:42:29 +00002355
florian99dd03e2013-01-29 03:56:06 +00002356 /* expr0Hi:expr0Lo = iffalse */
2357 /* expr1Hi:expr1Lo = iftrue */
2358 iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.ITE.iffalse);
2359 iselInt64Expr(&expr1Hi, &expr1Lo, env, e->Iex.ITE.iftrue);
sewardj362cf842012-06-07 08:59:53 +00002360
dejanja759d172013-09-19 13:35:45 +00002361 /* move desLo, expr0Lo
2362 * move desHi, expr0Hi
2363 * movn desLo, expr1Lo, cond
2364 * movn desHi, expr1Hi, cond */
2365 addInstr(env, mk_iMOVds_RR(desLo, expr0Lo));
2366 addInstr(env, mk_iMOVds_RR(desHi, expr0Hi));
2367 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desLo, expr1Lo, cond));
2368 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desHi, expr1Hi, cond));
dejanjc3fee0d2013-07-25 09:08:03 +00002369
sewardj362cf842012-06-07 08:59:53 +00002370 *rHi = desHi;
2371 *rLo = desLo;
2372 return;
2373 }
2374
2375 /* --------- BINARY ops --------- */
2376 if (e->tag == Iex_Binop) {
2377 IROp op_binop = e->Iex.Binop.op;
2378 switch (op_binop) {
2379 /* 32 x 32 -> 64 multiply */
2380 /* Add64 */
2381 case Iop_Add64: {
dejanjc3fee0d2013-07-25 09:08:03 +00002382 HReg xLo, xHi, yLo, yHi, carryBit;
2383
sewardj362cf842012-06-07 08:59:53 +00002384 HReg tHi = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002385 HReg tHi1 = newVRegI(env);
sewardj362cf842012-06-07 08:59:53 +00002386 HReg tLo = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002387
2388 carryBit = newVRegI(env);
2389
2390 Bool size32 = True;
2391 MIPSCondCode cc = MIPScc_LO;
2392
sewardj362cf842012-06-07 08:59:53 +00002393 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2394 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
sewardj362cf842012-06-07 08:59:53 +00002395 addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo)));
dejanjc3fee0d2013-07-25 09:08:03 +00002396
2397 /* Check carry. */
2398 addInstr(env, MIPSInstr_Cmp(False, size32, carryBit, tLo, xLo, cc));
2399
2400 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi1, xHi, MIPSRH_Reg(yHi)));
2401 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, tHi1,
2402 MIPSRH_Reg(carryBit)));
2403
2404 *rHi = tHi;
2405 *rLo = tLo;
2406 return;
2407 }
2408 case Iop_Sub64: {
2409 HReg xLo, xHi, yLo, yHi, borrow;
2410 Bool size32 = True;
2411 MIPSCondCode cc = MIPScc_LO;
2412
2413 HReg tHi = newVRegI(env);
2414 HReg tLo = newVRegI(env);
2415
2416 borrow = newVRegI(env);
2417
2418 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2419 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2420
2421 addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, xLo, MIPSRH_Reg(yLo)));
2422
2423 /* Check if borrow is nedded. */
2424 addInstr(env, MIPSInstr_Cmp(False, size32, borrow, xLo, yLo, cc));
2425
dejanj781f1bd2013-10-23 14:05:15 +00002426 addInstr(env, MIPSInstr_Alu(Malu_ADD, yHi, yHi,
2427 MIPSRH_Reg(borrow)));
dejanjc3fee0d2013-07-25 09:08:03 +00002428 addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, xHi, MIPSRH_Reg(yHi)));
2429
sewardj362cf842012-06-07 08:59:53 +00002430 *rHi = tHi;
2431 *rLo = tLo;
2432 return;
2433 }
2434 case Iop_MullU32:
2435 case Iop_MullS32: {
2436 HReg tLo = newVRegI(env);
2437 HReg tHi = newVRegI(env);
2438 HReg r_dst = newVRegI(env);
2439 Bool syned = toBool(op_binop == Iop_MullS32);
2440 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2441 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2442
petarjb92a9542013-02-27 22:57:17 +00002443 addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */,
sewardj362cf842012-06-07 08:59:53 +00002444 True /*widen */ , True,
2445 r_dst, r_srcL, r_srcR));
2446 addInstr(env, MIPSInstr_Mfhi(tHi));
2447 addInstr(env, MIPSInstr_Mflo(tLo));
2448 *rHi = tHi;
2449 *rLo = tLo;
2450
2451 return;
2452 }
2453 case Iop_DivModS64to32:
2454 case Iop_DivModU64to32: {
2455 HReg r_sHi, r_sLo;
2456 HReg tLo = newVRegI(env);
2457 HReg tHi = newVRegI(env);
2458 Bool syned = toBool(op_binop == Iop_DivModS64to32);
2459 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2460
2461 iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1);
2462 addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR));
2463 addInstr(env, MIPSInstr_Mfhi(tHi));
2464 addInstr(env, MIPSInstr_Mflo(tLo));
2465 *rHi = tHi;
2466 *rLo = tLo;
2467
2468 return;
2469 }
2470
petarjb92a9542013-02-27 22:57:17 +00002471 /* 32HLto64(e1,e2) */
sewardj362cf842012-06-07 08:59:53 +00002472 case Iop_32HLto64:
2473 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
2474 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
2475
2476 return;
petarjb92a9542013-02-27 22:57:17 +00002477 /* Or64/And64/Xor64 */
sewardj362cf842012-06-07 08:59:53 +00002478 case Iop_Or64:
2479 case Iop_And64:
2480 case Iop_Xor64: {
2481 HReg xLo, xHi, yLo, yHi;
2482 HReg tLo = newVRegI(env);
2483 HReg tHi = newVRegI(env);
2484 MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR :
2485 (op_binop == Iop_And64) ? Malu_AND : Malu_XOR;
2486 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
2487 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
2488 addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi)));
2489 addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo)));
2490 *rHi = tHi;
2491 *rLo = tLo;
2492 return;
2493 }
2494
dejanjc3fee0d2013-07-25 09:08:03 +00002495 case Iop_Shr64: {
dejanj781f1bd2013-10-23 14:05:15 +00002496#if defined (_MIPSEL)
2497 /* 64-bit logical shift right based on what gcc generates:
2498 <shift>:
2499 nor v0, zero, a2
2500 sll a3, a1, 0x1
2501 sllv a3, a3, v0
2502 srlv v0, a0, a2
2503 srlv v1, a1, a2
2504 andi a0, a2, 0x20
2505 or v0, a3, v0
2506 movn v0, v1, a0
2507 jr ra
2508 movn v1, zero, a0
2509 */
2510 HReg a0, a1;
2511 HReg a0tmp = newVRegI(env);
2512 HReg a2 = newVRegI(env);
2513 HReg a3 = newVRegI(env);
2514 HReg v0 = newVRegI(env);
2515 HReg v1 = newVRegI(env);
2516 HReg zero = newVRegI(env);
2517 MIPSRH *sa = NULL;
dejanjc3fee0d2013-07-25 09:08:03 +00002518
dejanj781f1bd2013-10-23 14:05:15 +00002519 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2520 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00002521
dejanj781f1bd2013-10-23 14:05:15 +00002522 if (sa->tag == Mrh_Imm) {
2523 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2524 }
2525 else {
2526 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2527 MIPSRH_Imm(False, 0x3f)));
2528 }
dejanjc3fee0d2013-07-25 09:08:03 +00002529
dejanj781f1bd2013-10-23 14:05:15 +00002530 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2531 /* nor v0, zero, a2 */
2532 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2533 /* sll a3, a1, 0x1 */
2534 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2535 a3, a1, MIPSRH_Imm(False, 0x1)));
2536 /* sllv a3, a3, v0 */
2537 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2538 a3, a3, MIPSRH_Reg(v0)));
2539 /* srlv v0, a0, a2 */
2540 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2541 v0, a0, MIPSRH_Reg(a2)));
2542 /* srlv v1, a1, a2 */
2543 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2544 v1, a1, MIPSRH_Reg(a2)));
2545 /* andi a0, a2, 0x20 */
2546 addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2,
2547 MIPSRH_Imm(False, 0x20)));
2548 /* or v0, a3, v0 */
2549 addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0)));
dejanjc3fee0d2013-07-25 09:08:03 +00002550
dejanj781f1bd2013-10-23 14:05:15 +00002551 /* movn v0, v1, a0 */
2552 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp));
2553 /* movn v1, zero, a0 */
2554 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, zero, a0tmp));
dejanjc3fee0d2013-07-25 09:08:03 +00002555
dejanj781f1bd2013-10-23 14:05:15 +00002556 *rHi = v1;
2557 *rLo = v0;
dejanjc3fee0d2013-07-25 09:08:03 +00002558 return;
dejanj781f1bd2013-10-23 14:05:15 +00002559#elif defined (_MIPSEB)
2560 /* 64-bit logical shift right based on what gcc generates:
2561 <shift>:
2562 nor v0, zero, a2
2563 sll a3, a0, 0x1
2564 sllv a3, a3, v0
2565 srlv v1, a1, a2
2566 andi v0, a2, 0x20
2567 or v1, a3, v1
2568 srlv a2, a0, a2
2569 movn v1, a2, v0
2570 movn a2, zero, v0
2571 jr ra
2572 move v0, a2
2573 */
2574 HReg a0, a1;
2575 HReg a2 = newVRegI(env);
2576 HReg a2tmp = newVRegI(env);
2577 HReg a3 = newVRegI(env);
2578 HReg v0 = newVRegI(env);
2579 HReg v1 = newVRegI(env);
2580 HReg zero = newVRegI(env);
2581 MIPSRH *sa = NULL;
2582
2583 iselInt64Expr(&a0, &a1, env, e->Iex.Binop.arg1);
2584 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
2585
2586 if (sa->tag == Mrh_Imm) {
2587 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2588 }
2589 else {
2590 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2591 MIPSRH_Imm(False, 0x3f)));
2592 }
2593
2594 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2595 /* nor v0, zero, a2 */
2596 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2597 /* sll a3, a0, 0x1 */
2598 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2599 a3, a0, MIPSRH_Imm(False, 0x1)));
2600 /* sllv a3, a3, v0 */
2601 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2602 a3, a3, MIPSRH_Reg(v0)));
2603 /* srlv v1, a1, a2 */
2604 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2605 v1, a1, MIPSRH_Reg(a2)));
2606 /* andi v0, a2, 0x20 */
2607 addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2,
2608 MIPSRH_Imm(False, 0x20)));
2609 /* or v1, a3, v1 */
2610 addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1)));
2611 /* srlv a2, a0, a2 */
2612 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2613 a2tmp, a0, MIPSRH_Reg(a2)));
2614
2615 /* movn v1, a2, v0 */
2616 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2tmp, v0));
2617 /* movn a2, zero, v0 */
2618 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2tmp, zero, v0));
2619 /* move v0, a2 */
2620 addInstr(env, mk_iMOVds_RR(v0, a2tmp));
2621
2622 *rHi = v0;
2623 *rLo = v1;
2624 return;
2625#endif
dejanjc3fee0d2013-07-25 09:08:03 +00002626 }
dejanj781f1bd2013-10-23 14:05:15 +00002627
dejanjc3fee0d2013-07-25 09:08:03 +00002628 case Iop_Shl64: {
dejanj781f1bd2013-10-23 14:05:15 +00002629 /* 64-bit shift left based on what gcc generates:
2630 <shift>:
2631 nor v0,zero,a2
2632 srl a3,a0,0x1
2633 srlv a3,a3,v0
2634 sllv v1,a1,a2
2635 andi v0,a2,0x20
2636 or v1,a3,v1
2637 sllv a2,a0,a2
2638 movn v1,a2,v0
2639 movn a2,zero,v0
2640 jr ra
2641 move v0,a2
2642 */
2643 HReg a0, a1;
2644 HReg a2 = newVRegI(env);
2645 HReg a3 = newVRegI(env);
2646 HReg v0 = newVRegI(env);
2647 HReg v1 = newVRegI(env);
2648 HReg zero = newVRegI(env);
2649 MIPSRH *sa = NULL;
dejanjc3fee0d2013-07-25 09:08:03 +00002650
dejanj781f1bd2013-10-23 14:05:15 +00002651 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2652 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00002653
dejanj781f1bd2013-10-23 14:05:15 +00002654 if (sa->tag == Mrh_Imm) {
2655 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2656 }
2657 else {
2658 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2659 MIPSRH_Imm(False, 0x3f)));
2660 }
dejanjc3fee0d2013-07-25 09:08:03 +00002661
dejanj781f1bd2013-10-23 14:05:15 +00002662 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2663 /* nor v0, zero, a2 */
2664 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2665 /* srl a3, a0, 0x1 */
2666 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2667 a3, a0, MIPSRH_Imm(False, 0x1)));
2668 /* srlv a3, a3, v0 */
2669 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2670 a3, a3, MIPSRH_Reg(v0)));
2671 /* sllv v1, a1, a2 */
2672 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2673 v1, a1, MIPSRH_Reg(a2)));
2674 /* andi v0, a2, 0x20 */
2675 addInstr(env, MIPSInstr_Alu(Malu_AND, v0, a2,
2676 MIPSRH_Imm(False, 0x20)));
2677 /* or v1, a3, v1 */
2678 addInstr(env, MIPSInstr_Alu(Malu_OR, v1, a3, MIPSRH_Reg(v1)));
2679 /* sllv a2, a0, a2 */
2680 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2681 a2, a0, MIPSRH_Reg(a2)));
dejanjc3fee0d2013-07-25 09:08:03 +00002682
dejanj781f1bd2013-10-23 14:05:15 +00002683 /* movn v1, a2, v0 */
2684 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a2, v0));
2685 /* movn a2, zero, v0 */
2686 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, a2, zero, v0));
2687 addInstr(env, mk_iMOVds_RR(v0, a2));
dejanjc3fee0d2013-07-25 09:08:03 +00002688
dejanj781f1bd2013-10-23 14:05:15 +00002689 *rHi = v1;
2690 *rLo = v0;
dejanjc3fee0d2013-07-25 09:08:03 +00002691 return;
2692 }
dejanj781f1bd2013-10-23 14:05:15 +00002693
dejanjc3fee0d2013-07-25 09:08:03 +00002694 case Iop_Sar64: {
dejanj781f1bd2013-10-23 14:05:15 +00002695 /* 64-bit arithmetic shift right based on what gcc generates:
2696 <shift>:
2697 nor v0, zero, a2
2698 sll a3, a1, 0x1
2699 sllv a3, a3, v0
2700 srlv v0, a0, a2
2701 srav v1, a1, a2
2702 andi a0, a2, 0x20
2703 sra a1, a1, 0x1f
2704 or v0, a3, v0
2705 movn v0, v1, a0
2706 jr ra
2707 movn v1, a1, a0
2708 */
2709 HReg a0, a1;
2710 HReg a0tmp = newVRegI(env);
2711 HReg a1tmp = newVRegI(env);
2712 HReg a2 = newVRegI(env);
2713 HReg a3 = newVRegI(env);
2714 HReg v0 = newVRegI(env);
2715 HReg v1 = newVRegI(env);
2716 HReg zero = newVRegI(env);
2717 MIPSRH *sa = NULL;
dejanjc3fee0d2013-07-25 09:08:03 +00002718
dejanj781f1bd2013-10-23 14:05:15 +00002719 iselInt64Expr(&a1, &a0, env, e->Iex.Binop.arg1);
2720 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
dejanjc3fee0d2013-07-25 09:08:03 +00002721
dejanj781f1bd2013-10-23 14:05:15 +00002722 if (sa->tag == Mrh_Imm) {
2723 addInstr(env, MIPSInstr_LI(a2, sa->Mrh.Imm.imm16));
2724 }
2725 else {
2726 addInstr(env, MIPSInstr_Alu(Malu_AND, a2, sa->Mrh.Reg.reg,
2727 MIPSRH_Imm(False, 0x3f)));
2728 }
dejanjc3fee0d2013-07-25 09:08:03 +00002729
dejanj781f1bd2013-10-23 14:05:15 +00002730 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2731 /* nor v0, zero, a2 */
2732 addInstr(env, MIPSInstr_Alu(Malu_NOR, v0, zero, MIPSRH_Reg(a2)));
2733 /* sll a3, a1, 0x1 */
2734 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2735 a3, a1, MIPSRH_Imm(False, 0x1)));
2736 /* sllv a3, a3, v0 */
2737 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
2738 a3, a3, MIPSRH_Reg(v0)));
2739 /* srlv v0, a0, a2 */
2740 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2741 v0, a0, MIPSRH_Reg(a2)));
2742 /* srav v1, a1, a2 */
2743 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
2744 v1, a1, MIPSRH_Reg(a2)));
2745 /* andi a0, a2, 0x20 */
2746 addInstr(env, MIPSInstr_Alu(Malu_AND, a0tmp, a2,
2747 MIPSRH_Imm(False, 0x20)));
2748 /* sra a1, a1, 0x1f */
2749 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
2750 a1tmp, a1, MIPSRH_Imm(False, 0x1f)));
2751 /* or v0, a3, v0 */
2752 addInstr(env, MIPSInstr_Alu(Malu_OR, v0, a3, MIPSRH_Reg(v0)));
dejanjc3fee0d2013-07-25 09:08:03 +00002753
dejanj781f1bd2013-10-23 14:05:15 +00002754 /* movn v0, v1, a0 */
2755 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v0, v1, a0tmp));
2756 /* movn v1, a1, a0 */
2757 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, v1, a1tmp, a0tmp));
dejanjc3fee0d2013-07-25 09:08:03 +00002758
dejanj781f1bd2013-10-23 14:05:15 +00002759 *rHi = v1;
2760 *rLo = v0;
dejanjc3fee0d2013-07-25 09:08:03 +00002761 return;
2762 }
2763
dejanj0e006f22014-02-19 11:56:29 +00002764 case Iop_F32toI64S: {
2765 HReg tmpD = newVRegD(env);
2766 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
2767 HReg tLo = newVRegI(env);
2768 HReg tHi = newVRegI(env);
2769 MIPSAMode *am_addr;
2770
2771 /* CVTLS tmpD, valF */
2772 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
2773 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
2774 set_MIPS_rounding_default(env);
2775
2776 sub_from_sp(env, 16); /* Move SP down 16 bytes */
2777 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2778
2779 /* store as F64 */
2780 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
2781 am_addr));
2782 /* load as 2xI32 */
2783#if defined (_MIPSEL)
2784 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2785 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2786 mode64));
2787#elif defined (_MIPSEB)
2788 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
2789 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
2790 mode64));
2791#endif
2792
2793 /* Reset SP */
2794 add_to_sp(env, 16);
2795
2796 *rHi = tHi;
2797 *rLo = tLo;
2798
2799 return;
2800 }
2801
sewardj362cf842012-06-07 08:59:53 +00002802 default:
2803 break;
2804 }
2805 }
2806
2807 /* --------- UNARY ops --------- */
2808 if (e->tag == Iex_Unop) {
sewardj362cf842012-06-07 08:59:53 +00002809 switch (e->Iex.Unop.op) {
2810 case Iop_1Sto64: {
2811 HReg tLo = newVRegI(env);
2812 HReg tHi = newVRegI(env);
2813 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2814 HReg tmp = newVRegI(env);
2815
2816 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src,
2817 MIPSRH_Imm(False, 31)));
dejanj781f1bd2013-10-23 14:05:15 +00002818 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
sewardj362cf842012-06-07 08:59:53 +00002819 MIPSRH_Imm(False, 31)));
2820
2821 addInstr(env, mk_iMOVds_RR(tHi, tmp));
2822 addInstr(env, mk_iMOVds_RR(tLo, tmp));
2823
2824 *rHi = tHi;
2825 *rLo = tLo;
2826 return;
2827 }
2828
2829 /* 32Sto64(e) */
2830 case Iop_32Sto64: {
2831 HReg tLo = newVRegI(env);
2832 HReg tHi = newVRegI(env);
2833 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2834 addInstr(env, mk_iMOVds_RR(tHi, src));
2835 addInstr(env, mk_iMOVds_RR(tLo, src));
2836 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi,
2837 MIPSRH_Imm(False, 31)));
2838 *rHi = tHi;
2839 *rLo = tLo;
2840 return;
2841 }
2842
petarja8e327d2013-07-04 00:39:37 +00002843 /* 8Uto64(e) */
2844 case Iop_8Uto64: {
2845 HReg tLo = newVRegI(env);
2846 HReg tHi = newVRegI(env);
2847 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2848 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo, src,
2849 MIPSRH_Imm(False, 0xFF)));
2850 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2851 MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2852 *rHi = tHi;
2853 *rLo = tLo;
2854 return;
2855 }
2856
sewardj362cf842012-06-07 08:59:53 +00002857 /* 32Uto64(e) */
2858 case Iop_32Uto64: {
2859 HReg tLo = newVRegI(env);
2860 HReg tHi = newVRegI(env);
2861 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
2862 addInstr(env, mk_iMOVds_RR(tLo, src));
2863 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
2864 MIPSRH_Reg(hregMIPS_GPR0(mode64))));
2865 *rHi = tHi;
2866 *rLo = tLo;
2867 return;
2868 }
dejanjc3fee0d2013-07-25 09:08:03 +00002869
2870 case Iop_Left64: {
dejanj781f1bd2013-10-23 14:05:15 +00002871 HReg yHi, yLo;
dejanjc3fee0d2013-07-25 09:08:03 +00002872 HReg tHi = newVRegI(env);
2873 HReg tLo = newVRegI(env);
dejanj781f1bd2013-10-23 14:05:15 +00002874 HReg tmp = newVRegI(env);
2875 HReg tmp1 = newVRegI(env);
2876 HReg tmp2 = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002877 HReg zero = newVRegI(env);
dejanjc3fee0d2013-07-25 09:08:03 +00002878 MIPSCondCode cc = MIPScc_LO;
2879
dejanjc3fee0d2013-07-25 09:08:03 +00002880 /* yHi:yLo = arg */
2881 iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
2882 /* zero = 0 */
2883 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
2884
dejanj781f1bd2013-10-23 14:05:15 +00002885 /* tmp2:tmp1 = 0 - (yHi:yLo)*/
2886 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, zero, MIPSRH_Reg(yLo)));
2887 addInstr(env, MIPSInstr_Cmp(False, True, tmp1, zero, tmp2, cc));
2888 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, zero, MIPSRH_Reg(yHi)));
2889 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp1, tmp, MIPSRH_Reg(tmp1)));
dejanjc3fee0d2013-07-25 09:08:03 +00002890
dejanj781f1bd2013-10-23 14:05:15 +00002891 /* So now we have tmp2:tmp1 = -arg. To finish off, or 'arg'
dejanjc3fee0d2013-07-25 09:08:03 +00002892 back in, so as to give the final result
2893 tHi:tLo = arg | -arg. */
dejanj781f1bd2013-10-23 14:05:15 +00002894 addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, yHi, MIPSRH_Reg(tmp1)));
2895 addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, yLo, MIPSRH_Reg(tmp2)));
dejanjc3fee0d2013-07-25 09:08:03 +00002896 *rHi = tHi;
2897 *rLo = tLo;
2898 return;
2899 }
2900
sewardj362cf842012-06-07 08:59:53 +00002901 case Iop_CmpwNEZ64: {
2902 HReg srcLo, srcHi;
2903 HReg tmp1 = newVRegI(env);
2904 HReg tmp2 = newVRegI(env);
2905 /* srcHi:srcLo = arg */
2906 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
2907 /* tmp1 = srcHi | srcLo */
2908 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo,
2909 MIPSRH_Reg(srcHi)));
2910 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
2911
2912 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
2913 MIPSRH_Reg(tmp1)));
2914
2915 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
2916 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2,
2917 MIPSRH_Imm(False, 31)));
2918 *rHi = tmp2;
2919 *rLo = tmp2;
2920 return;
2921
2922 }
2923 case Iop_ReinterpF64asI64: {
2924 HReg tLo = newVRegI(env);
2925 HReg tHi = newVRegI(env);
2926 MIPSAMode *am_addr;
2927 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
2928
petarjb92a9542013-02-27 22:57:17 +00002929 sub_from_sp(env, 16); /* Move SP down 16 bytes */
sewardj362cf842012-06-07 08:59:53 +00002930 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
2931
petarjb92a9542013-02-27 22:57:17 +00002932 /* store as F64 */
sewardj362cf842012-06-07 08:59:53 +00002933 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
2934 am_addr));
petarjb92a9542013-02-27 22:57:17 +00002935 /* load as 2xI32 */
petarj0c30de82013-04-19 12:35:00 +00002936#if defined (_MIPSEL)
sewardj362cf842012-06-07 08:59:53 +00002937 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
2938 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
2939 mode64));
petarj0c30de82013-04-19 12:35:00 +00002940#elif defined (_MIPSEB)
2941 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
2942 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
2943 mode64));
2944#endif
sewardj362cf842012-06-07 08:59:53 +00002945
petarjb92a9542013-02-27 22:57:17 +00002946 /* Reset SP */
2947 add_to_sp(env, 16);
sewardj362cf842012-06-07 08:59:53 +00002948
2949 *rHi = tHi;
2950 *rLo = tLo;
2951 return;
2952 }
petarjb92a9542013-02-27 22:57:17 +00002953
sewardj362cf842012-06-07 08:59:53 +00002954 default:
2955 vex_printf("UNARY: No such op: ");
2956 ppIROp(e->Iex.Unop.op);
2957 vex_printf("\n");
2958 break;
2959 }
2960 }
2961
2962 vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag);
2963 ppIRExpr(e);
2964 vpanic("iselInt64Expr(mips)");
2965}
2966
2967/*---------------------------------------------------------*/
2968/*--- ISEL: Floating point expressions (32 bit) ---*/
2969/*---------------------------------------------------------*/
2970
2971/* Nothing interesting here; really just wrappers for
2972 64-bit stuff. */
sewardj362cf842012-06-07 08:59:53 +00002973static HReg iselFltExpr(ISelEnv * env, IRExpr * e)
2974{
2975 HReg r = iselFltExpr_wrk(env, e);
2976 vassert(hregIsVirtual(r));
2977 return r;
2978}
2979
2980/* DO NOT CALL THIS DIRECTLY */
2981static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
2982{
2983 IRType ty = typeOfIRExpr(env->type_env, e);
dejanj0e006f22014-02-19 11:56:29 +00002984 vassert(ty == Ity_F32 || (ty == Ity_F64 && fp_mode64));
sewardj362cf842012-06-07 08:59:53 +00002985
2986 if (e->tag == Iex_RdTmp) {
2987 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2988 }
2989
2990 if (e->tag == Iex_Load) {
sewardj362cf842012-06-07 08:59:53 +00002991 vassert(e->Iex.Load.ty == Ity_F32
dejanj0e006f22014-02-19 11:56:29 +00002992 || (e->Iex.Load.ty == Ity_F64 && fp_mode64));
2993 HReg r_dst;
2994 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
2995 if (e->Iex.Load.ty == Ity_F64) {
2996 r_dst = newVRegD(env);
petarjb92a9542013-02-27 22:57:17 +00002997 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00002998 } else {
2999 r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003000 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003001 }
sewardj362cf842012-06-07 08:59:53 +00003002 return r_dst;
3003 }
3004
3005 if (e->tag == Iex_Get) {
sewardj362cf842012-06-07 08:59:53 +00003006 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
3007 GuestStatePointer(mode64));
dejanj0e006f22014-02-19 11:56:29 +00003008 HReg r_dst;
3009 if (e->Iex.Load.ty == Ity_F64) {
3010 r_dst = newVRegD(env);
petarjb92a9542013-02-27 22:57:17 +00003011 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003012 } else {
3013 r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003014 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
dejanj0e006f22014-02-19 11:56:29 +00003015 }
sewardj362cf842012-06-07 08:59:53 +00003016 return r_dst;
3017 }
3018
3019 if (e->tag == Iex_Unop) {
3020 switch (e->Iex.Unop.op) {
3021 case Iop_ReinterpI32asF32: {
sewardj362cf842012-06-07 08:59:53 +00003022 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3023 HReg r_dst = newVRegF(env);
3024
petarjb92a9542013-02-27 22:57:17 +00003025 /* Move Word to Floating Point
3026 mtc1 r_dst, valS */
3027 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, fr_src));
sewardj362cf842012-06-07 08:59:53 +00003028
sewardj362cf842012-06-07 08:59:53 +00003029 return r_dst;
sewardj362cf842012-06-07 08:59:53 +00003030 }
3031 case Iop_F32toF64: {
dejanj0e006f22014-02-19 11:56:29 +00003032 vassert(fp_mode64);
dejanja759d172013-09-19 13:35:45 +00003033 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3034 HReg dst = newVRegD(env);
sewardj362cf842012-06-07 08:59:53 +00003035
dejanja759d172013-09-19 13:35:45 +00003036 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
3037 return dst;
petarjb92a9542013-02-27 22:57:17 +00003038 }
3039 case Iop_ReinterpI64asF64: {
dejanj0e006f22014-02-19 11:56:29 +00003040 HReg r_dst;
3041 if (mode64) {
3042 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3043 r_dst = newVRegF(env);
3044 /* Move Doubleword to Floating Point
3045 dmtc1 r_dst, fr_src */
3046 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src));
3047 } else {
3048 HReg Hi, Lo;
3049 r_dst = newVRegD(env);
3050 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
3051 r_dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
3052 }
dejanja759d172013-09-19 13:35:45 +00003053 return r_dst;
3054 }
petarjb92a9542013-02-27 22:57:17 +00003055 case Iop_I32StoF64: {
dejanj0e006f22014-02-19 11:56:29 +00003056 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003057 HReg dst = newVRegF(env);
dejanja759d172013-09-19 13:35:45 +00003058 HReg tmp = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003059 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
petarjb92a9542013-02-27 22:57:17 +00003060
3061 /* Move Word to Floating Point
dejanj0e006f22014-02-19 11:56:29 +00003062 mtc1 tmp, r_src */
dejanja759d172013-09-19 13:35:45 +00003063 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
petarjb92a9542013-02-27 22:57:17 +00003064
3065 /* and do convert */
dejanja759d172013-09-19 13:35:45 +00003066 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
petarjb92a9542013-02-27 22:57:17 +00003067
3068 return dst;
3069 }
sewardj362cf842012-06-07 08:59:53 +00003070 case Iop_AbsF32:
3071 case Iop_AbsF64: {
3072 Bool sz32 = e->Iex.Unop.op == Iop_AbsF32;
3073 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3074 HReg dst = newVRegF(env);
3075 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src));
3076 return dst;
3077 }
3078 case Iop_NegF32:
3079 case Iop_NegF64: {
3080 Bool sz32 = e->Iex.Unop.op == Iop_NegF32;
3081 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3082 HReg dst = newVRegF(env);
3083 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src));
3084 return dst;
3085 }
petarjb92a9542013-02-27 22:57:17 +00003086 case Iop_RoundF64toF64_ZERO: {
3087 vassert(mode64);
3088 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3089 HReg dst = newVRegF(env);
3090 addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, dst, src));
3091 return dst;
3092 }
dejanj3bc88cc2013-10-07 10:28:56 +00003093 case Iop_RoundF64toF64_NEAREST: {
3094 vassert(mode64);
3095 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3096 HReg dst = newVRegF(env);
3097 addInstr(env, MIPSInstr_FpConvert(Mfp_ROUNDLD, dst, src));
3098 return dst;
3099 }
3100 case Iop_RoundF64toF64_NegINF: {
3101 vassert(mode64);
3102 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3103 HReg dst = newVRegF(env);
3104 addInstr(env, MIPSInstr_FpConvert(Mfp_FLOORLD, dst, src));
3105 return dst;
3106 }
3107 case Iop_RoundF64toF64_PosINF: {
3108 vassert(mode64);
3109 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3110 HReg dst = newVRegF(env);
3111 addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, dst, src));
3112 return dst;
3113 }
3114
sewardj362cf842012-06-07 08:59:53 +00003115 default:
3116 break;
3117 }
3118 }
3119
3120 if (e->tag == Iex_Triop) {
3121 switch (e->Iex.Triop.details->op) {
3122 case Iop_DivF32:
3123 case Iop_DivF64:
3124 case Iop_MulF32:
3125 case Iop_MulF64:
3126 case Iop_AddF32:
3127 case Iop_AddF64:
3128 case Iop_SubF32:
3129 case Iop_SubF64: {
3130 MIPSFpOp op = 0;
dejanja759d172013-09-19 13:35:45 +00003131 HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2);
sewardj362cf842012-06-07 08:59:53 +00003132 HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3);
3133 HReg dst = newVRegF(env);
3134 switch (e->Iex.Triop.details->op) {
3135 case Iop_DivF32:
3136 op = Mfp_DIVS;
3137 break;
petarjb92a9542013-02-27 22:57:17 +00003138 case Iop_DivF64:
dejanj0e006f22014-02-19 11:56:29 +00003139 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003140 op = Mfp_DIVD;
3141 break;
sewardj362cf842012-06-07 08:59:53 +00003142 case Iop_MulF32:
3143 op = Mfp_MULS;
3144 break;
petarjb92a9542013-02-27 22:57:17 +00003145 case Iop_MulF64:
dejanj0e006f22014-02-19 11:56:29 +00003146 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003147 op = Mfp_MULD;
3148 break;
sewardj362cf842012-06-07 08:59:53 +00003149 case Iop_AddF32:
3150 op = Mfp_ADDS;
3151 break;
petarjb92a9542013-02-27 22:57:17 +00003152 case Iop_AddF64:
dejanj0e006f22014-02-19 11:56:29 +00003153 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003154 op = Mfp_ADDD;
3155 break;
sewardj362cf842012-06-07 08:59:53 +00003156 case Iop_SubF32:
3157 op = Mfp_SUBS;
3158 break;
petarjb92a9542013-02-27 22:57:17 +00003159 case Iop_SubF64:
dejanj0e006f22014-02-19 11:56:29 +00003160 vassert(fp_mode64);
petarjb92a9542013-02-27 22:57:17 +00003161 op = Mfp_SUBD;
3162 break;
sewardj362cf842012-06-07 08:59:53 +00003163 default:
3164 vassert(0);
3165 }
petarjb92a9542013-02-27 22:57:17 +00003166 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
sewardj362cf842012-06-07 08:59:53 +00003167 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
petarjb92a9542013-02-27 22:57:17 +00003168 set_MIPS_rounding_default(env);
sewardj362cf842012-06-07 08:59:53 +00003169 return dst;
3170 }
3171 default:
3172 break;
3173 }
3174 }
3175
3176 if (e->tag == Iex_Binop) {
3177 switch (e->Iex.Binop.op) {
3178 case Iop_F64toF32: {
petarjb92a9542013-02-27 22:57:17 +00003179 HReg valD;
3180 if (mode64)
3181 valD = iselFltExpr(env, e->Iex.Binop.arg2);
3182 else
3183 valD = iselDblExpr(env, e->Iex.Binop.arg2);
sewardj362cf842012-06-07 08:59:53 +00003184 HReg valS = newVRegF(env);
3185
3186 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3187 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD));
3188 set_MIPS_rounding_default(env);
3189 return valS;
3190 }
3191
3192 case Iop_RoundF32toInt: {
3193 HReg valS = newVRegF(env);
3194 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
3195
3196 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3197 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
sewardj362cf842012-06-07 08:59:53 +00003198 set_MIPS_rounding_default(env);
3199 return valS;
3200 }
3201
petarjb92a9542013-02-27 22:57:17 +00003202 case Iop_RoundF64toInt: {
3203 HReg valS = newVRegF(env);
3204 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
3205
3206 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3207 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, valS, valF));
3208 set_MIPS_rounding_default(env);
3209 return valS;
3210 }
3211
sewardj362cf842012-06-07 08:59:53 +00003212 case Iop_I32StoF32: {
3213 HReg r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003214 HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3215 HReg tmp = newVRegF(env);
3216
3217 /* Move Word to Floating Point
3218 mtc1 tmp, fr_src */
3219 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, fr_src));
3220
3221 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3222 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp));
3223 set_MIPS_rounding_default(env);
3224
3225 return r_dst;
3226 }
3227
3228 case Iop_I64StoF64: {
3229 HReg r_dst = newVRegF(env);
sewardj362cf842012-06-07 08:59:53 +00003230 MIPSAMode *am_addr;
dejanj0e006f22014-02-19 11:56:29 +00003231 HReg tmp, fr_src;
3232 if (mode64) {
3233 tmp = newVRegF(env);
3234 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3235 /* Move SP down 8 bytes */
3236 sub_from_sp(env, 8);
3237 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
sewardj362cf842012-06-07 08:59:53 +00003238
dejanj0e006f22014-02-19 11:56:29 +00003239 /* store as I64 */
3240 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
sewardj362cf842012-06-07 08:59:53 +00003241
dejanj0e006f22014-02-19 11:56:29 +00003242 /* load as Ity_F64 */
3243 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
sewardj362cf842012-06-07 08:59:53 +00003244
dejanj0e006f22014-02-19 11:56:29 +00003245 /* Reset SP */
3246 add_to_sp(env, 8);
3247 } else {
3248 HReg Hi, Lo;
3249 tmp = newVRegD(env);
3250 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
3251 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
3252 }
sewardj362cf842012-06-07 08:59:53 +00003253
3254 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
petarjb92a9542013-02-27 22:57:17 +00003255 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
3256 set_MIPS_rounding_default(env);
3257
3258 return r_dst;
3259 }
3260
3261 case Iop_I64StoF32: {
3262 HReg r_dst = newVRegF(env);
petarjb92a9542013-02-27 22:57:17 +00003263 MIPSAMode *am_addr;
dejanj0e006f22014-02-19 11:56:29 +00003264 HReg fr_src, tmp;
3265 if (mode64) {
3266 tmp = newVRegF(env);
3267 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
3268 /* Move SP down 8 bytes */
3269 sub_from_sp(env, 8);
3270 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
petarjb92a9542013-02-27 22:57:17 +00003271
dejanj0e006f22014-02-19 11:56:29 +00003272 /* store as I64 */
3273 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
petarjb92a9542013-02-27 22:57:17 +00003274
dejanj0e006f22014-02-19 11:56:29 +00003275 /* load as Ity_F64 */
3276 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
petarjb92a9542013-02-27 22:57:17 +00003277
dejanj0e006f22014-02-19 11:56:29 +00003278 /* Reset SP */
3279 add_to_sp(env, 8);
3280 } else {
3281 HReg Hi, Lo;
3282 tmp = newVRegD(env);
3283 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
3284 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
3285 }
petarjb92a9542013-02-27 22:57:17 +00003286
3287 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3288 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSL, r_dst, tmp));
sewardj362cf842012-06-07 08:59:53 +00003289 set_MIPS_rounding_default(env);
3290
3291 return r_dst;
3292 }
3293
3294 case Iop_SqrtF32:
3295 case Iop_SqrtF64: {
sewardj362cf842012-06-07 08:59:53 +00003296 Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32;
3297 HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
3298 HReg dst = newVRegF(env);
3299 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3300 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst,
3301 src));
3302 set_MIPS_rounding_default(env);
3303 return dst;
3304 }
petarjb92a9542013-02-27 22:57:17 +00003305
sewardj362cf842012-06-07 08:59:53 +00003306 default:
3307 break;
3308 }
3309 }
3310
petarjb92a9542013-02-27 22:57:17 +00003311 if (e->tag == Iex_Qop) {
3312 switch (e->Iex.Qop.details->op) {
3313 case Iop_MAddF32:
3314 case Iop_MAddF64:
3315 case Iop_MSubF32:
3316 case Iop_MSubF64: {
3317 MIPSFpOp op = 0;
3318 switch (e->Iex.Qop.details->op) {
3319 case Iop_MAddF32:
3320 op = Mfp_MADDS;
3321 break;
3322 case Iop_MAddF64:
3323 op = Mfp_MADDD;
3324 break;
3325 case Iop_MSubF32:
3326 op = Mfp_MSUBS;
3327 break;
3328 case Iop_MSubF64:
3329 op = Mfp_MSUBD;
3330 break;
3331 default:
3332 vassert(0);
3333 }
3334 HReg dst = newVRegF(env);
3335 HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2);
3336 HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3);
3337 HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4);
3338 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
3339 addInstr(env, MIPSInstr_FpTernary(op, dst,
3340 src1, src2, src3));
3341 set_MIPS_rounding_default(env);
3342 return dst;
3343 }
3344
3345 default:
3346 break;
3347 }
3348 }
3349
sewardj362cf842012-06-07 08:59:53 +00003350 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
3351 /* This is quite subtle. The only way to do the relevant
3352 truncation is to do a single-precision store and then a
3353 double precision load to get it back into a register. The
3354 problem is, if the data is then written to memory a second
3355 time, as in
3356
3357 STbe(...) = TruncF64asF32(...)
3358
3359 then will the second truncation further alter the value? The
3360 answer is no: flds (as generated here) followed by fsts
3361 (generated for the STbe) is the identity function on 32-bit
3362 floats, so we are safe.
3363
3364 Another upshot of this is that if iselStmt can see the
3365 entirety of
3366
3367 STbe(...) = TruncF64asF32(arg)
3368
3369 then it can short circuit having to deal with TruncF64asF32
3370 individually; instead just compute arg into a 64-bit FP
3371 register and do 'fsts' (since that itself does the
3372 truncation).
3373
3374 We generate pretty poor code here (should be ok both for
3375 32-bit and 64-bit mode); but it is expected that for the most
3376 part the latter optimisation will apply and hence this code
3377 will not often be used.
3378 */
3379 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
3380 HReg fdst = newVRegF(env);
3381 MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64));
3382
3383 sub_from_sp(env, 16);
petarjb92a9542013-02-27 22:57:17 +00003384 /* store as F32, hence truncating */
sewardj362cf842012-06-07 08:59:53 +00003385 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1));
petarjb92a9542013-02-27 22:57:17 +00003386 /* and reload. Good huh?! (sigh) */
sewardj362cf842012-06-07 08:59:53 +00003387 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1));
3388 add_to_sp(env, 16);
3389 return fdst;
3390 }
3391
petarjb92a9542013-02-27 22:57:17 +00003392 /* --------- ITE --------- */
3393 if (e->tag == Iex_ITE) {
3394 if (ty == Ity_F64
3395 && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
3396 vassert(mode64);
3397 HReg r0 = iselFltExpr(env, e->Iex.ITE.iffalse);
3398 HReg r1 = iselFltExpr(env, e->Iex.ITE.iftrue);
3399 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
3400 HReg r_dst = newVRegF(env);
3401 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0));
3402 addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1,
3403 r_cond));
3404 return r_dst;
3405 }
3406 }
3407
sewardj362cf842012-06-07 08:59:53 +00003408 vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag);
3409 ppIRExpr(e);
3410 vpanic("iselFltExpr_wrk(mips)");
3411}
3412
3413static HReg iselDblExpr(ISelEnv * env, IRExpr * e)
3414{
3415 HReg r = iselDblExpr_wrk(env, e);
3416 vassert(hregClass(r) == HRcFlt64);
3417 vassert(hregIsVirtual(r));
3418 return r;
3419}
3420
3421/* DO NOT CALL THIS DIRECTLY */
3422static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e)
3423{
3424 IRType ty = typeOfIRExpr(env->type_env, e);
3425 vassert(e);
3426 vassert(ty == Ity_F64);
3427
3428 if (e->tag == Iex_RdTmp) {
3429 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
3430 }
3431
3432 /* --------- LOAD --------- */
petarjbe927ba2012-09-09 01:10:59 +00003433 if (e->tag == Iex_Load) {
sewardj362cf842012-06-07 08:59:53 +00003434 HReg r_dst = newVRegD(env);
3435 MIPSAMode *am_addr;
3436 vassert(e->Iex.Load.ty == Ity_F64);
3437 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
3438 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
3439 return r_dst;
3440 }
3441
3442 /* --------- GET --------- */
3443 if (e->tag == Iex_Get) {
3444
3445 HReg r_dst = newVRegD(env);
3446 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
3447 GuestStatePointer(mode64));
3448 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
3449 return r_dst;
3450 }
3451
3452 if (e->tag == Iex_Unop) {
3453 MIPSFpOp fpop = Mfp_INVALID;
3454 switch (e->Iex.Unop.op) {
3455 case Iop_NegF64:
3456 fpop = Mfp_NEGD;
3457 break;
3458 case Iop_AbsF64:
3459 fpop = Mfp_ABSD;
3460 break;
3461 case Iop_F32toF64: {
petarjb92a9542013-02-27 22:57:17 +00003462 vassert(!mode64);
sewardj362cf842012-06-07 08:59:53 +00003463 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
3464 HReg dst = newVRegD(env);
3465
petarjb92a9542013-02-27 22:57:17 +00003466 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
sewardj362cf842012-06-07 08:59:53 +00003467 return dst;
3468 }
3469 case Iop_ReinterpI64asF64: {
dejanja759d172013-09-19 13:35:45 +00003470 HReg Hi, Lo;
sewardj362cf842012-06-07 08:59:53 +00003471 HReg dst = newVRegD(env);
3472
3473 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
3474
petarjb92a9542013-02-27 22:57:17 +00003475 dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
sewardj362cf842012-06-07 08:59:53 +00003476 return dst;
3477 }
3478 case Iop_I32StoF64: {
petarjb92a9542013-02-27 22:57:17 +00003479 vassert(!mode64);
sewardj362cf842012-06-07 08:59:53 +00003480 HReg dst = newVRegD(env);
dejanja759d172013-09-19 13:35:45 +00003481 HReg tmp = newVRegF(env);
sewardj362cf842012-06-07 08:59:53 +00003482 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
sewardj362cf842012-06-07 08:59:53 +00003483
petarjb92a9542013-02-27 22:57:17 +00003484 /* Move Word to Floating Point
dejanja759d172013-09-19 13:35:45 +00003485 mtc1 tmp, r_src */
3486 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
sewardj362cf842012-06-07 08:59:53 +00003487
petarjb92a9542013-02-27 22:57:17 +00003488 /* and do convert */
dejanja759d172013-09-19 13:35:45 +00003489 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
sewardj362cf842012-06-07 08:59:53 +00003490
3491 return dst;
3492 }
3493 default:
3494 break;
3495 }
3496
3497 if (fpop != Mfp_INVALID) {
3498 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
3499 HReg dst = newVRegD(env);
3500 addInstr(env, MIPSInstr_FpUnary(fpop, dst, src));
3501 return dst;
3502 }
3503 }
3504
3505 if (e->tag == Iex_Binop) {
3506 switch (e->Iex.Binop.op) {
3507 case Iop_RoundF64toInt: {
dejanj0e006f22014-02-19 11:56:29 +00003508 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3509 HReg dst = newVRegD(env);
sewardj362cf842012-06-07 08:59:53 +00003510
dejanj0e006f22014-02-19 11:56:29 +00003511 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
3512 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src));
3513 set_MIPS_rounding_default(env);
3514
3515 return dst;
sewardj362cf842012-06-07 08:59:53 +00003516 }
3517
dejanj3bc88cc2013-10-07 10:28:56 +00003518 case Iop_SqrtF64: {
sewardj362cf842012-06-07 08:59:53 +00003519 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
3520 HReg dst = newVRegD(env);
dejanj41833222013-11-14 15:44:42 +00003521 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
sewardj362cf842012-06-07 08:59:53 +00003522 addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src));
dejanj41833222013-11-14 15:44:42 +00003523 set_MIPS_rounding_default(env);
sewardj362cf842012-06-07 08:59:53 +00003524 return dst;
3525 }
3526
3527 default:
3528 break;
3529
3530 }
3531 }
3532
3533 if (e->tag == Iex_Triop) {
3534 switch (e->Iex.Triop.details->op) {
3535 case Iop_DivF64:
3536 case Iop_DivF32:
3537 case Iop_MulF64:
3538 case Iop_AddF64:
3539 case Iop_SubF64: {
3540 MIPSFpOp op = 0;
dejanja759d172013-09-19 13:35:45 +00003541 HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2);
sewardj362cf842012-06-07 08:59:53 +00003542 HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3);
3543 HReg dst = newVRegD(env);
3544 switch (e->Iex.Triop.details->op) {
3545 case Iop_DivF64:
3546 op = Mfp_DIVD;
3547 break;
dejanj41833222013-11-14 15:44:42 +00003548 case Iop_DivF32:
3549 op = Mfp_DIVS;
3550 break;
sewardj362cf842012-06-07 08:59:53 +00003551 case Iop_MulF64:
3552 op = Mfp_MULD;
3553 break;
3554 case Iop_AddF64:
3555 op = Mfp_ADDD;
3556 break;
3557 case Iop_SubF64:
3558 op = Mfp_SUBD;
3559 break;
3560 default:
3561 vassert(0);
3562 }
dejanj41833222013-11-14 15:44:42 +00003563 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
sewardj362cf842012-06-07 08:59:53 +00003564 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
dejanj41833222013-11-14 15:44:42 +00003565 set_MIPS_rounding_default(env);
sewardj362cf842012-06-07 08:59:53 +00003566 return dst;
3567 }
3568 default:
3569 break;
3570 }
3571 }
3572
petarjb92a9542013-02-27 22:57:17 +00003573 if (e->tag == Iex_Qop) {
3574 switch (e->Iex.Qop.details->op) {
3575 case Iop_MAddF32:
3576 case Iop_MAddF64:
3577 case Iop_MSubF32:
3578 case Iop_MSubF64: {
3579 MIPSFpOp op = 0;
3580 switch (e->Iex.Qop.details->op) {
3581 case Iop_MAddF32:
3582 op = Mfp_MADDS;
3583 break;
3584 case Iop_MAddF64:
3585 op = Mfp_MADDD;
3586 break;
3587 case Iop_MSubF32:
3588 op = Mfp_MSUBS;
3589 break;
3590 case Iop_MSubF64:
3591 op = Mfp_MSUBD;
3592 break;
3593 default:
3594 vassert(0);
3595 }
3596 HReg dst = newVRegD(env);
3597 HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2);
3598 HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3);
3599 HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4);
3600 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
3601 addInstr(env, MIPSInstr_FpTernary(op, dst,
3602 src1, src2, src3));
3603 set_MIPS_rounding_default(env);
3604 return dst;
3605 }
3606
3607 default:
3608 break;
3609 }
3610 }
3611
3612 /* --------- ITE --------- */
florian99dd03e2013-01-29 03:56:06 +00003613 if (e->tag == Iex_ITE) {
sewardj362cf842012-06-07 08:59:53 +00003614 if (ty == Ity_F64
petarjd4564182013-01-29 15:42:29 +00003615 && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
florian99dd03e2013-01-29 03:56:06 +00003616 HReg r0 = iselDblExpr(env, e->Iex.ITE.iffalse);
3617 HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue);
petarjb92a9542013-02-27 22:57:17 +00003618 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
sewardj362cf842012-06-07 08:59:53 +00003619 HReg r_dst = newVRegD(env);
sewardj362cf842012-06-07 08:59:53 +00003620
petarjb92a9542013-02-27 22:57:17 +00003621 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0));
3622 addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1,
3623 r_cond));
sewardj362cf842012-06-07 08:59:53 +00003624 return r_dst;
3625 }
3626 }
3627
3628 vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag);
3629 ppIRExpr(e);
3630 vpanic("iselDblExpr_wrk(mips)");
3631}
3632
3633/*---------------------------------------------------------*/
3634/*--- ISEL: Statements ---*/
3635/*---------------------------------------------------------*/
3636
3637static void iselStmt(ISelEnv * env, IRStmt * stmt)
3638{
3639 if (vex_traceflags & VEX_TRACE_VCODE) {
3640 vex_printf("\n-- ");
3641
3642 ppIRStmt(stmt);
3643 vex_printf("\n");
3644 }
3645
3646 switch (stmt->tag) {
3647 /* --------- STORE --------- */
3648 case Ist_Store: {
3649 MIPSAMode *am_addr;
3650 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
3651
3652 /*constructs addressing mode from address provided */
3653 am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
3654
3655 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
3656 (mode64 && (tyd == Ity_I64))) {
3657 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
3658 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)),
3659 am_addr, r_src, mode64));
3660 return;
3661 }
3662 if (!mode64 && (tyd == Ity_I64)) {
3663 HReg vHi, vLo;
3664 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
3665
3666 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
3667
3668 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3669 MIPSAMode_IR(0, r_addr), vHi, mode64));
3670 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3671 MIPSAMode_IR(4, r_addr), vLo, mode64));
3672 return;
3673 }
3674 if (tyd == Ity_F32) {
3675 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3676 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
3677 am_addr));
3678 return;
3679 }
petarjb92a9542013-02-27 22:57:17 +00003680 if (tyd == Ity_F64 && mode64) {
3681 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
3682 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3683 am_addr));
3684 return;
3685 }
petarj1ec43e02012-09-04 13:45:42 +00003686 if (!mode64 && (tyd == Ity_F64)) {
3687 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
3688 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3689 am_addr));
3690 return;
3691 }
3692
sewardj362cf842012-06-07 08:59:53 +00003693 break;
3694 }
3695
3696 /* --------- PUT --------- */
3697 case Ist_Put: {
3698 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
dejanjc3fee0d2013-07-25 09:08:03 +00003699
sewardj362cf842012-06-07 08:59:53 +00003700 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
3701 (ty == Ity_I64 && mode64)) {
3702 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
3703 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3704 GuestStatePointer(mode64));
3705 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)),
3706 am_addr, r_src, mode64));
3707 return;
3708 }
dejanjc3fee0d2013-07-25 09:08:03 +00003709
sewardj362cf842012-06-07 08:59:53 +00003710 if (ty == Ity_I64 && !mode64) {
3711 HReg vHi, vLo;
3712 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3713 GuestStatePointer(mode64));
3714 MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4,
3715 GuestStatePointer(mode64));
3716 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
3717 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3718 am_addr, vLo, mode64));
3719 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
3720 am_addr4, vHi, mode64));
3721 return;
dejanjc3fee0d2013-07-25 09:08:03 +00003722
sewardj362cf842012-06-07 08:59:53 +00003723 }
dejanjc3fee0d2013-07-25 09:08:03 +00003724
sewardj362cf842012-06-07 08:59:53 +00003725 if (ty == Ity_F32) {
3726 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
3727 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3728 GuestStatePointer(mode64));
3729 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
3730 am_addr));
3731 return;
3732 }
dejanjc3fee0d2013-07-25 09:08:03 +00003733
sewardj362cf842012-06-07 08:59:53 +00003734 if (ty == Ity_F64) {
dejanja759d172013-09-19 13:35:45 +00003735 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
sewardj362cf842012-06-07 08:59:53 +00003736 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
3737 GuestStatePointer(mode64));
3738 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
3739 am_addr));
3740 return;
3741 }
3742 break;
3743 }
3744
3745 /* --------- TMP --------- */
3746 case Ist_WrTmp: {
3747 IRTemp tmp = stmt->Ist.WrTmp.tmp;
3748 IRType ty = typeOfIRTemp(env->type_env, tmp);
3749
3750 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) {
3751 HReg r_dst = lookupIRTemp(env, tmp);
3752 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3753 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3754 return;
3755 }
3756
3757 if (ty == Ity_I64) {
petarjb92a9542013-02-27 22:57:17 +00003758 if (mode64) {
3759 HReg r_dst = lookupIRTemp(env, tmp);
3760 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
3761 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3762 return;
3763 } else {
3764 HReg rHi, rLo, dstHi, dstLo;
3765 iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
3766 lookupIRTemp64(&dstHi, &dstLo, env, tmp);
3767 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3768 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3769 return;
3770 }
3771 }
3772
3773 if (mode64 && ty == Ity_I128) {
3774 HReg rHi, rLo, dstHi, dstLo;
3775 iselInt128Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
3776 lookupIRTempPair(&dstHi, &dstLo, env, tmp);
3777 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3778 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3779 return;
sewardj362cf842012-06-07 08:59:53 +00003780 }
3781
3782 if (ty == Ity_F32) {
3783 HReg fr_dst = lookupIRTemp(env, tmp);
3784 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
3785 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src));
3786 return;
3787 }
3788
3789 if (ty == Ity_F64) {
petarjb92a9542013-02-27 22:57:17 +00003790 if (mode64) {
3791 HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
3792 HReg dst = lookupIRTemp(env, tmp);
3793 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
3794 return;
3795 } else {
3796 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
3797 HReg dst = lookupIRTemp(env, tmp);
3798 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
3799 return;
3800 }
sewardj362cf842012-06-07 08:59:53 +00003801 }
3802 break;
3803 }
3804
3805 /* --------- Call to DIRTY helper --------- */
3806 case Ist_Dirty: {
sewardj362cf842012-06-07 08:59:53 +00003807 IRDirty *d = stmt->Ist.Dirty.details;
sewardj362cf842012-06-07 08:59:53 +00003808
sewardjcfe046e2013-01-17 14:23:53 +00003809 /* Figure out the return type, if any. */
3810 IRType retty = Ity_INVALID;
3811 if (d->tmp != IRTemp_INVALID)
3812 retty = typeOfIRTemp(env->type_env, d->tmp);
3813
sewardj74142b82013-08-08 10:28:59 +00003814 /* Throw out any return types we don't know about. */
3815 Bool retty_ok = False;
sewardjcfe046e2013-01-17 14:23:53 +00003816 switch (retty) {
sewardj74142b82013-08-08 10:28:59 +00003817 case Ity_INVALID: /* Function doesn't return anything. */
3818 case Ity_V128:
3819 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
3820 retty_ok = True; break;
sewardjcfe046e2013-01-17 14:23:53 +00003821 default:
3822 break;
3823 }
sewardj74142b82013-08-08 10:28:59 +00003824
3825 if (!retty_ok)
sewardjcfe046e2013-01-17 14:23:53 +00003826 break; /* will go to stmt_fail: */
3827
sewardj74142b82013-08-08 10:28:59 +00003828 /* Marshal args, do the call, clear stack, set the return value
3829 to 0x555..555 if this is a conditional call that returns a
3830 value and the call is skipped. */
3831 UInt addToSp = 0;
3832 RetLoc rloc = mk_RetLoc_INVALID();
3833 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
3834 vassert(is_sane_RetLoc(rloc));
sewardj362cf842012-06-07 08:59:53 +00003835
3836 /* Now figure out what to do with the returned value, if any. */
sewardj74142b82013-08-08 10:28:59 +00003837 switch (retty) {
3838 case Ity_INVALID: {
3839 /* No return value. Nothing to do. */
3840 vassert(d->tmp == IRTemp_INVALID);
3841 vassert(rloc.pri == RLPri_None);
3842 vassert(addToSp == 0);
3843 return;
3844 }
3845 case Ity_I32: case Ity_I16: case Ity_I8: {
3846 /* The returned value is in $v0. Park it in the register
3847 associated with tmp. */
3848 HReg r_dst = lookupIRTemp(env, d->tmp);
3849 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
3850 vassert(rloc.pri == RLPri_Int);
3851 vassert(addToSp == 0);
3852 return;
3853 }
3854 case Ity_I64: {
3855 if (mode64) {
3856 /* The returned value is in $v0. Park it in the register
3857 associated with tmp. */
3858 HReg r_dst = lookupIRTemp(env, d->tmp);
3859 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
3860 vassert(rloc.pri == RLPri_Int);
3861 vassert(addToSp == 0);
3862 return;
3863 } else {
3864 HReg rHi = newVRegI(env);
3865 HReg rLo = newVRegI(env);
3866 HReg dstHi, dstLo;
3867 addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64)));
3868 addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64)));
3869 lookupIRTemp64(&dstHi, &dstLo, env, d->tmp);
3870 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
3871 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
3872 return;
3873 }
3874 }
3875 case Ity_V128: {
3876 /* ATC. The code that this produces really
3877 needs to be looked at, to verify correctness.
3878 I don't think this can ever happen though, since the
3879 MIPS front end never produces 128-bit loads/stores. */
3880 vassert(0);
3881 vassert(rloc.pri == RLPri_V128SpRel);
3882 vassert(addToSp >= 16);
3883 HReg dst = lookupIRTemp(env, d->tmp);
3884 MIPSAMode* am = MIPSAMode_IR(rloc.spOff, StackPointer(mode64));
3885 addInstr(env, MIPSInstr_Load(mode64 ? 8 : 4, dst, am, mode64));
3886 add_to_sp(env, addToSp);
3887 return;
sewardj362cf842012-06-07 08:59:53 +00003888
sewardj74142b82013-08-08 10:28:59 +00003889 }
3890 default:
3891 /*NOTREACHED*/
3892 vassert(0);
sewardj362cf842012-06-07 08:59:53 +00003893 }
sewardj362cf842012-06-07 08:59:53 +00003894 }
3895
3896 /* --------- Load Linked or Store Conditional --------- */
3897 case Ist_LLSC: {
petarjb92a9542013-02-27 22:57:17 +00003898 /* Temporary solution; this need to be rewritten again for MIPS.
3899 On MIPS you can not read from address that is locked with LL
3900 before SC. If you read from address that is locked than SC will
3901 fall. */
sewardj362cf842012-06-07 08:59:53 +00003902 IRTemp res = stmt->Ist.LLSC.result;
3903 IRType tyRes = typeOfIRTemp(env->type_env, res);
3904 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
3905
3906 if (!mode64 && (tyAddr != Ity_I32))
3907 goto stmt_fail;
3908
3909 if (stmt->Ist.LLSC.storedata == NULL) {
3910 /* LL */
3911 MIPSAMode *r_addr;
petarjb92a9542013-02-27 22:57:17 +00003912 /* constructs addressing mode from address provided */
sewardj362cf842012-06-07 08:59:53 +00003913 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
3914
3915 HReg r_dst = lookupIRTemp(env, res);
3916 if (tyRes == Ity_I32) {
petarj1e994b92012-11-23 00:44:37 +00003917 addInstr(env, MIPSInstr_LoadL(4, r_dst, r_addr, mode64));
sewardj362cf842012-06-07 08:59:53 +00003918 return;
3919 } else if (tyRes == Ity_I64 && mode64) {
petarj1e994b92012-11-23 00:44:37 +00003920 addInstr(env, MIPSInstr_LoadL(8, r_dst, r_addr, mode64));
sewardj362cf842012-06-07 08:59:53 +00003921 return;
3922 }
sewardj362cf842012-06-07 08:59:53 +00003923 } else {
3924 /* SC */
3925 MIPSAMode *r_addr;
3926 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
3927 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
3928 HReg r_dst = lookupIRTemp(env, res);
dejanjc3fee0d2013-07-25 09:08:03 +00003929 IRType tyData = typeOfIRExpr(env->type_env,
sewardj362cf842012-06-07 08:59:53 +00003930 stmt->Ist.LLSC.storedata);
3931
3932 if (tyData == Ity_I32) {
petarj1e994b92012-11-23 00:44:37 +00003933 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3934 addInstr(env, MIPSInstr_StoreC(4, r_addr, r_dst, mode64));
sewardj362cf842012-06-07 08:59:53 +00003935 return;
3936 } else if (tyData == Ity_I64 && mode64) {
petarj1e994b92012-11-23 00:44:37 +00003937 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
3938 addInstr(env, MIPSInstr_StoreC(8, r_addr, r_dst, mode64));
sewardj362cf842012-06-07 08:59:53 +00003939 return;
3940 }
sewardj362cf842012-06-07 08:59:53 +00003941 }
3942 goto stmt_fail;
petarjb92a9542013-02-27 22:57:17 +00003943 /* NOTREACHED */}
sewardj362cf842012-06-07 08:59:53 +00003944
dejanj6ced72b2014-06-04 11:28:07 +00003945 case Ist_CAS:
3946 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
3947 IRCAS *cas = stmt->Ist.CAS.details;
3948 HReg old = lookupIRTemp(env, cas->oldLo);
3949 HReg addr = iselWordExpr_R(env, cas->addr);
3950 HReg expd = iselWordExpr_R(env, cas->expdLo);
3951 HReg data = iselWordExpr_R(env, cas->dataLo);
3952 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) {
3953 addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64));
3954 } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
3955 addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64));
3956 }
3957 }
petarj67ec22c2014-10-09 01:19:34 +00003958 return;
dejanj6ced72b2014-06-04 11:28:07 +00003959
petarjb92a9542013-02-27 22:57:17 +00003960 /* --------- INSTR MARK --------- */
3961 /* Doesn't generate any executable code ... */
sewardj362cf842012-06-07 08:59:53 +00003962 case Ist_IMark:
3963 return;
3964
petarjb92a9542013-02-27 22:57:17 +00003965 /* --------- ABI HINT --------- */
3966 /* These have no meaning (denotation in the IR) and so we ignore
3967 them ... if any actually made it this far. */
sewardj362cf842012-06-07 08:59:53 +00003968 case Ist_AbiHint:
3969 return;
3970
petarjb92a9542013-02-27 22:57:17 +00003971 /* --------- NO-OP --------- */
3972 /* Fairly self-explanatory, wouldn't you say? */
sewardj362cf842012-06-07 08:59:53 +00003973 case Ist_NoOp:
3974 return;
3975
3976 /* --------- EXIT --------- */
3977 case Ist_Exit: {
3978 IRConst* dst = stmt->Ist.Exit.dst;
3979 if (!mode64 && dst->tag != Ico_U32)
3980 vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value");
3981 if (mode64 && dst->tag != Ico_U64)
3982 vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value");
3983
3984 MIPSCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
3985 MIPSAMode* amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP,
petarjb92a9542013-02-27 22:57:17 +00003986 GuestStatePointer(mode64));
sewardj362cf842012-06-07 08:59:53 +00003987
3988 /* Case: boring transfer to known address */
3989 if (stmt->Ist.Exit.jk == Ijk_Boring
3990 || stmt->Ist.Exit.jk == Ijk_Call
3991 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
3992 if (env->chainingAllowed) {
3993 /* .. almost always true .. */
3994 /* Skip the event check at the dst if this is a forwards
3995 edge. */
3996 Bool toFastEP
3997 = mode64
3998 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
3999 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
4000 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
4001 addInstr(env, MIPSInstr_XDirect(
4002 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
4003 : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
4004 amPC, cc, toFastEP));
4005 } else {
4006 /* .. very occasionally .. */
4007 /* We can't use chaining, so ask for an assisted transfer,
4008 as that's the only alternative that is allowable. */
4009 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4010 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring));
4011 }
4012 return;
4013 }
4014
4015 /* Case: assisted transfer to arbitrary address */
4016 switch (stmt->Ist.Exit.jk) {
4017 /* Keep this list in sync with that in iselNext below */
4018 case Ijk_ClientReq:
4019 case Ijk_EmFail:
4020 case Ijk_EmWarn:
4021 case Ijk_NoDecode:
4022 case Ijk_NoRedir:
4023 case Ijk_SigBUS:
dejanj6ced72b2014-06-04 11:28:07 +00004024 case Ijk_Yield:
sewardj362cf842012-06-07 08:59:53 +00004025 case Ijk_SigTRAP:
petarja6a19862012-10-19 14:55:58 +00004026 case Ijk_SigFPE_IntDiv:
4027 case Ijk_SigFPE_IntOvf:
sewardj362cf842012-06-07 08:59:53 +00004028 case Ijk_Sys_syscall:
sewardj05f5e012014-05-04 10:52:11 +00004029 case Ijk_InvalICache:
sewardj362cf842012-06-07 08:59:53 +00004030 {
4031 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
4032 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc,
4033 stmt->Ist.Exit.jk));
4034 return;
4035 }
4036 default:
4037 break;
4038 }
4039
4040 /* Do we ever expect to see any other kind? */
4041 goto stmt_fail;
4042 }
4043
4044 default:
4045 break;
4046 }
4047
4048 stmt_fail:
4049 vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
4050 ppIRStmt(stmt);
4051 vpanic("iselStmt:\n");
4052}
4053
4054/*---------------------------------------------------------*/
4055/*--- ISEL: Basic block terminators (Nexts) ---*/
4056/*---------------------------------------------------------*/
4057
4058static void iselNext ( ISelEnv* env,
4059 IRExpr* next, IRJumpKind jk, Int offsIP )
4060{
4061 if (vex_traceflags & VEX_TRACE_VCODE) {
4062 vex_printf( "\n-- PUT(%d) = ", offsIP);
4063 ppIRExpr( next );
4064 vex_printf( "; exit-");
4065 ppIRJumpKind(jk);
4066 vex_printf( "\n");
4067 }
4068
4069 /* Case: boring transfer to known address */
4070 if (next->tag == Iex_Const) {
4071 IRConst* cdst = next->Iex.Const.con;
4072 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
4073 if (jk == Ijk_Boring || jk == Ijk_Call) {
4074 /* Boring transfer to known address */
petarjb92a9542013-02-27 22:57:17 +00004075 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
sewardj362cf842012-06-07 08:59:53 +00004076 if (env->chainingAllowed) {
4077 /* .. almost always true .. */
4078 /* Skip the event check at the dst if this is a forwards
4079 edge. */
4080 Bool toFastEP
4081 = env->mode64
4082 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
4083 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
4084 if (0) vex_printf("%s", toFastEP ? "X" : ".");
4085 addInstr(env, MIPSInstr_XDirect(
4086 env->mode64 ? (Addr64)cdst->Ico.U64
4087 : (Addr64)cdst->Ico.U32,
4088 amPC, MIPScc_AL, toFastEP));
4089 } else {
4090 /* .. very occasionally .. */
4091 /* We can't use chaining, so ask for an assisted transfer,
4092 as that's the only alternative that is allowable. */
4093 HReg r = iselWordExpr_R(env, next);
4094 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
4095 Ijk_Boring));
4096 }
4097 return;
4098 }
4099 }
4100
4101 /* Case: call/return (==boring) transfer to any address */
4102 switch (jk) {
4103 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
sewardj362cf842012-06-07 08:59:53 +00004104 HReg r = iselWordExpr_R(env, next);
dejanja759d172013-09-19 13:35:45 +00004105 MIPSAMode* amPC = MIPSAMode_IR(offsIP,
4106 GuestStatePointer(env->mode64));
sewardj362cf842012-06-07 08:59:53 +00004107 if (env->chainingAllowed) {
4108 addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL));
4109 } else {
4110 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
dejanja759d172013-09-19 13:35:45 +00004111 Ijk_Boring));
sewardj362cf842012-06-07 08:59:53 +00004112 }
4113 return;
4114 }
4115 default:
4116 break;
4117 }
4118
4119 /* Case: assisted transfer to arbitrary address */
4120 switch (jk) {
4121 /* Keep this list in sync with that for Ist_Exit above */
4122 case Ijk_ClientReq:
4123 case Ijk_EmFail:
4124 case Ijk_EmWarn:
4125 case Ijk_NoDecode:
4126 case Ijk_NoRedir:
4127 case Ijk_SigBUS:
dejanj0e006f22014-02-19 11:56:29 +00004128 case Ijk_SigILL:
sewardj362cf842012-06-07 08:59:53 +00004129 case Ijk_SigTRAP:
petarja6a19862012-10-19 14:55:58 +00004130 case Ijk_SigFPE_IntDiv:
4131 case Ijk_SigFPE_IntOvf:
sewardj362cf842012-06-07 08:59:53 +00004132 case Ijk_Sys_syscall:
sewardj05f5e012014-05-04 10:52:11 +00004133 case Ijk_InvalICache: {
sewardj362cf842012-06-07 08:59:53 +00004134 HReg r = iselWordExpr_R(env, next);
petarjb92a9542013-02-27 22:57:17 +00004135 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
sewardj362cf842012-06-07 08:59:53 +00004136 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk));
4137 return;
4138 }
4139 default:
4140 break;
4141 }
4142
petarjb92a9542013-02-27 22:57:17 +00004143 vex_printf("\n-- PUT(%d) = ", offsIP);
4144 ppIRExpr(next );
4145 vex_printf("; exit-");
sewardj362cf842012-06-07 08:59:53 +00004146 ppIRJumpKind(jk);
petarjb92a9542013-02-27 22:57:17 +00004147 vex_printf("\n");
4148 vassert(0); /* are we expecting any other kind? */
sewardj362cf842012-06-07 08:59:53 +00004149}
4150
4151/*---------------------------------------------------------*/
4152/*--- Insn selector top-level ---*/
4153/*---------------------------------------------------------*/
4154
4155/* Translate an entire BB to mips code. */
floriancacba8e2014-12-15 18:58:07 +00004156HInstrArray *iselSB_MIPS ( const IRSB* bb,
sewardj362cf842012-06-07 08:59:53 +00004157 VexArch arch_host,
floriand8c64e02014-10-08 08:54:44 +00004158 const VexArchInfo* archinfo_host,
4159 const VexAbiInfo* vbi,
sewardj362cf842012-06-07 08:59:53 +00004160 Int offs_Host_EvC_Counter,
4161 Int offs_Host_EvC_FailAddr,
4162 Bool chainingAllowed,
4163 Bool addProfInc,
floriandcd6d232015-01-02 17:32:21 +00004164 Addr max_ga )
sewardj362cf842012-06-07 08:59:53 +00004165{
4166 Int i, j;
4167 HReg hreg, hregHI;
4168 ISelEnv* env;
4169 UInt hwcaps_host = archinfo_host->hwcaps;
4170 MIPSAMode *amCounter, *amFailAddr;
4171
4172 /* sanity ... */
petarjb92a9542013-02-27 22:57:17 +00004173 vassert(arch_host == VexArchMIPS32 || arch_host == VexArchMIPS64);
Elliott Hughesa0664b92017-04-18 17:46:52 -07004174 vassert(VEX_PRID_COMP_MIPS == VEX_MIPS_COMP_ID(hwcaps_host)
4175 || VEX_PRID_COMP_CAVIUM == VEX_MIPS_COMP_ID(hwcaps_host)
4176 || VEX_PRID_COMP_BROADCOM == VEX_MIPS_COMP_ID(hwcaps_host)
4177 || VEX_PRID_COMP_NETLOGIC == VEX_MIPS_COMP_ID(hwcaps_host)
4178 || VEX_PRID_COMP_INGENIC_E1 == VEX_MIPS_COMP_ID(hwcaps_host)
4179 || VEX_PRID_COMP_LEGACY == VEX_MIPS_COMP_ID(hwcaps_host));
sewardj362cf842012-06-07 08:59:53 +00004180
sewardj9b769162014-07-24 12:42:03 +00004181 /* Check that the host's endianness is as expected. */
4182 vassert(archinfo_host->endness == VexEndnessLE
4183 || archinfo_host->endness == VexEndnessBE);
4184
sewardj362cf842012-06-07 08:59:53 +00004185 mode64 = arch_host != VexArchMIPS32;
Elliott Hughesa0664b92017-04-18 17:46:52 -07004186 fp_mode64 = VEX_MIPS_HOST_FP_MODE(hwcaps_host);
sewardj362cf842012-06-07 08:59:53 +00004187
4188 /* Make up an initial environment to use. */
floriand8e3eca2015-03-13 12:46:49 +00004189 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
sewardj362cf842012-06-07 08:59:53 +00004190 env->vreg_ctr = 0;
4191 env->mode64 = mode64;
dejanj0e006f22014-02-19 11:56:29 +00004192 env->fp_mode64 = fp_mode64;
sewardj362cf842012-06-07 08:59:53 +00004193
4194 /* Set up output code array. */
4195 env->code = newHInstrArray();
4196
4197 /* Copy BB's type env. */
4198 env->type_env = bb->tyenv;
4199
4200 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
4201 change as we go along. */
4202 env->n_vregmap = bb->tyenv->types_used;
floriand8e3eca2015-03-13 12:46:49 +00004203 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
4204 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
sewardj362cf842012-06-07 08:59:53 +00004205
4206 /* and finally ... */
4207 env->hwcaps = hwcaps_host;
4208 env->chainingAllowed = chainingAllowed;
4209 env->hwcaps = hwcaps_host;
4210 env->max_ga = max_ga;
4211
4212 /* For each IR temporary, allocate a suitably-kinded virtual
4213 register. */
4214 j = 0;
4215 for (i = 0; i < env->n_vregmap; i++) {
4216 hregHI = hreg = INVALID_HREG;
4217 switch (bb->tyenv->types[i]) {
4218 case Ity_I1:
4219 case Ity_I8:
4220 case Ity_I16:
petarjb92a9542013-02-27 22:57:17 +00004221 case Ity_I32:
4222 if (mode64) {
sewardja5b50222015-03-26 07:18:32 +00004223 hreg = mkHReg(True, HRcInt64, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004224 break;
4225 } else {
sewardja5b50222015-03-26 07:18:32 +00004226 hreg = mkHReg(True, HRcInt32, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004227 break;
4228 }
4229 case Ity_I64:
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++);
4235 hregHI = mkHReg(True, HRcInt32, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004236 break;
4237 }
sewardj362cf842012-06-07 08:59:53 +00004238 case Ity_I128:
4239 vassert(mode64);
sewardja5b50222015-03-26 07:18:32 +00004240 hreg = mkHReg(True, HRcInt64, 0, j++);
4241 hregHI = mkHReg(True, HRcInt64, 0, j++);
sewardj362cf842012-06-07 08:59:53 +00004242 break;
petarjb92a9542013-02-27 22:57:17 +00004243 case Ity_F32:
4244 if (mode64) {
sewardja5b50222015-03-26 07:18:32 +00004245 hreg = mkHReg(True, HRcFlt64, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004246 break;
4247 } else {
sewardja5b50222015-03-26 07:18:32 +00004248 hreg = mkHReg(True, HRcFlt32, 0, j++);
petarjb92a9542013-02-27 22:57:17 +00004249 break;
4250 }
sewardj362cf842012-06-07 08:59:53 +00004251 case Ity_F64:
sewardja5b50222015-03-26 07:18:32 +00004252 hreg = mkHReg(True, HRcFlt64, 0, j++);
sewardj362cf842012-06-07 08:59:53 +00004253 break;
4254 default:
4255 ppIRType(bb->tyenv->types[i]);
4256 vpanic("iselBB(mips): IRTemp type");
dejanj0e006f22014-02-19 11:56:29 +00004257 break;
sewardj362cf842012-06-07 08:59:53 +00004258 }
4259 env->vregmap[i] = hreg;
4260 env->vregmapHI[i] = hregHI;
4261 }
4262 env->vreg_ctr = j;
4263
4264 /* The very first instruction must be an event check. */
petarjb92a9542013-02-27 22:57:17 +00004265 amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, GuestStatePointer(mode64));
4266 amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, GuestStatePointer(mode64));
sewardj362cf842012-06-07 08:59:53 +00004267 addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr));
4268
4269 /* Possibly a block counter increment (for profiling). At this
4270 point we don't know the address of the counter, so just pretend
4271 it is zero. It will have to be patched later, but before this
4272 translation is used, by a call to LibVEX_patchProfCtr. */
4273 if (addProfInc) {
4274 addInstr(env, MIPSInstr_ProfInc());
4275 }
4276
4277 /* Ok, finally we can iterate over the statements. */
4278 for (i = 0; i < bb->stmts_used; i++)
4279 iselStmt(env, bb->stmts[i]);
4280
4281 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
4282
4283 /* record the number of vregs we used. */
4284 env->code->n_vregs = env->vreg_ctr;
4285 return env->code;
4286
4287}
4288
4289/*---------------------------------------------------------------*/
4290/*--- end host_mips_isel.c ---*/
4291/*---------------------------------------------------------------*/