Bug 439685 compiler warning in callgrind/main.c
[valgrind.git] / VEX / priv / host_mips_isel.c
blob33e4f52169a7654a030a90e689e764f1fff97dec
2 /*---------------------------------------------------------------*/
3 /*--- begin host_mips_isel.c ---*/
4 /*---------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2010-2017 RT-RK
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, see <http://www.gnu.org/licenses/>.
25 The GNU General Public License is contained in the file COPYING.
28 #include "libvex_basictypes.h"
29 #include "libvex_ir.h"
30 #include "libvex.h"
32 #include "main_util.h"
33 #include "main_globals.h"
34 #include "host_generic_regs.h"
35 #include "host_generic_simd64.h" /* for 64-bit SIMD helpers */
36 #include "host_mips_defs.h"
38 /*---------------------------------------------------------*/
39 /*--- Register Usage Conventions ---*/
40 /*---------------------------------------------------------*/
42 /* Integer Regs
43 ------------
44 ZERO0 Reserved
45 GPR12:22 Allocateable
46 23 GuestStatePointer
47 SP StackFramePointer
48 RA LinkRegister */
50 static Bool mode64 = False;
52 /* Host CPU has FPU and 32 dbl. prec. FP registers. */
53 static Bool fp_mode64 = False;
55 /* Host hwcaps */
56 static UInt hwcaps_host = 0;
58 /* Host CPU has MSA ASE */
59 static Bool has_msa = False;
61 /* GPR register class for mips32/64 */
62 #define HRcGPR(_mode64) ((_mode64) ? HRcInt64 : HRcInt32)
64 /* FPR register class for mips32/64 */
65 #define HRcFPR(_mode64) ((_mode64) ? HRcFlt64 : HRcFlt32)
67 /*---------------------------------------------------------*/
68 /*--- ISelEnv ---*/
69 /*---------------------------------------------------------*/
71 /* This carries around:
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.
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.
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.
89 - The code array, that is, the insns selected so far.
91 - A counter, for generating new virtual registers.
93 - The host subarchitecture we are selecting insns for.
94 This is set at the start and does not change.
96 - A Bool for indicating whether we may generate chain-me
97 instructions for control flow transfers, or whether we must use
98 XAssisted.
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.
108 Note, this is all (well, mostly) host-independent.
111 typedef
112 struct {
113 /* Constant -- are set at the start and do not change. */
114 IRTypeEnv* type_env;
116 HReg* vregmap;
117 HReg* vregmapHI;
118 Int n_vregmap;
120 UInt hwcaps;
121 Bool mode64;
122 Bool fp_mode64;
124 Bool chainingAllowed;
125 Addr64 max_ga;
127 /* These are modified as we go along. */
128 HInstrArray* code;
129 Int vreg_ctr;
131 ISelEnv;
133 static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp)
135 vassert(tmp < env->n_vregmap);
136 return env->vregmap[tmp];
139 static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
141 vassert(tmp < env->n_vregmap);
142 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
143 *vrLO = env->vregmap[tmp];
144 *vrHI = env->vregmapHI[tmp];
147 static void
148 lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
150 vassert(env->mode64);
151 vassert(tmp < env->n_vregmap);
152 vassert(! hregIsInvalid(env->vregmapHI[tmp]));
153 *vrLO = env->vregmap[tmp];
154 *vrHI = env->vregmapHI[tmp];
157 static void addInstr(ISelEnv * env, MIPSInstr * instr)
159 addHInstr(env->code, instr);
160 if (vex_traceflags & VEX_TRACE_VCODE) {
161 ppMIPSInstr(instr, mode64);
162 vex_printf("\n");
166 static HReg newVRegI(ISelEnv * env)
168 HReg reg = mkHReg(True/*virtual reg*/,
169 HRcGPR(env->mode64), 0/*enc*/, env->vreg_ctr);
170 env->vreg_ctr++;
171 return reg;
174 static HReg newVRegD(ISelEnv * env)
176 HReg reg = mkHReg(True/*virtual reg*/,
177 HRcFlt64, 0/*enc*/, env->vreg_ctr);
178 env->vreg_ctr++;
179 return reg;
182 static HReg newVRegF(ISelEnv * env)
184 HReg reg = mkHReg(True/*virtual reg*/,
185 HRcFPR(env->mode64), 0/*enc*/, env->vreg_ctr);
186 env->vreg_ctr++;
187 return reg;
190 static HReg newVRegV ( ISelEnv* env )
192 HReg reg = mkHReg(True/*virtual reg*/, HRcVec128, 0, env->vreg_ctr);
193 env->vreg_ctr++;
194 return reg;
197 static void add_to_sp(ISelEnv * env, UInt n)
199 HReg sp = StackPointer(mode64);
200 vassert(n < 256 && (n % 8) == 0);
201 if (mode64)
202 addInstr(env, MIPSInstr_Alu(Malu_DADD, sp, sp, MIPSRH_Imm(True,
203 toUShort(n))));
204 else
205 addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True,
206 toUShort(n))));
209 static void sub_from_sp(ISelEnv * env, UInt n)
211 HReg sp = StackPointer(mode64);
212 vassert(n < 256 && (n % 8) == 0);
213 if (mode64)
214 addInstr(env, MIPSInstr_Alu(Malu_DSUB, sp, sp,
215 MIPSRH_Imm(True, toUShort(n))));
216 else
217 addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp,
218 MIPSRH_Imm(True, toUShort(n))));
221 /*---------------------------------------------------------*/
222 /*--- ISEL: Forward declarations ---*/
223 /*---------------------------------------------------------*/
225 /* These are organised as iselXXX and iselXXX_wrk pairs. The
226 iselXXX_wrk do the real work, but are not to be called directly.
227 For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
228 checks that all returned registers are virtual. You should not
229 call the _wrk version directly.
231 /* 32-bit mode: Compute an I8/I16/I32 into a RH
232 (reg-or-halfword-immediate).
233 It's important to specify whether the immediate is to be regarded
234 as signed or not. If yes, this will never return -32768 as an
235 immediate; this guaranteed that all signed immediates that are
236 return can have their sign inverted if need be.
238 static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
239 static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
241 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an
242 immediate in the range 1 .. 31 inclusive. Used for doing shift amounts. */
243 static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
244 static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
246 /* Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an
247 immediate in the range 1 .. 63 inclusive. Used for doing shift amounts. */
248 static MIPSRH *iselWordExpr_RH6u_wrk(ISelEnv * env, IRExpr * e);
249 static MIPSRH *iselWordExpr_RH6u(ISelEnv * env, IRExpr * e);
251 /* Compute an I8 into a reg-or-7-bit-unsigned-immediate, the latter being an
252 immediate in the range 1 .. 127 inclusive. Used for doing shift amounts. */
253 static MIPSRH *iselWordExpr_RH7u_wrk(ISelEnv * env, IRExpr * e);
254 static MIPSRH *iselWordExpr_RH7u(ISelEnv * env, IRExpr * e);
256 /* compute an I8/I16/I32 into a GPR*/
257 static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
258 static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
260 /* compute an I32 into an AMode. */
261 static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
262 IRType xferTy);
263 static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy);
265 static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
266 IRExpr * e);
267 static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
269 /* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */
270 static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo,
271 ISelEnv * env, IRExpr * e);
272 static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e);
274 static HReg iselV128Expr( ISelEnv* env, IRExpr* e );
275 static HReg iselV128Expr_wrk( ISelEnv* env, IRExpr* e );
277 static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
278 static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e);
280 static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e);
281 static HReg iselDblExpr(ISelEnv * env, IRExpr * e);
283 static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e);
284 static HReg iselFltExpr(ISelEnv * env, IRExpr * e);
286 static void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode)
289 rounding mode | MIPS | IR
290 ------------------------
291 to nearest | 00 | 00
292 to zero | 01 | 11
293 to +infinity | 10 | 10
294 to -infinity | 11 | 01
296 /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 3 */
297 HReg irrm = iselWordExpr_R(env, mode);
298 HReg tmp = newVRegI(env);
299 HReg fcsr_old = newVRegI(env);
300 MIPSAMode *am_addr;
302 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
303 MIPSRH_Imm(False, 1)));
304 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
305 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, MIPSRH_Imm(False, 3)));
306 /* save old value of FCSR */
307 addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
308 sub_from_sp(env, 8); /* Move SP down 8 bytes */
309 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
311 /* store old FCSR to stack */
312 addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
314 /* set new value of FCSR */
315 addInstr(env, MIPSInstr_MtFCSR(tmp));
318 static void set_MIPS_rounding_mode_MSA(ISelEnv * env, IRExpr * mode) {
320 rounding mode | MIPS | IR
321 ------------------------
322 to nearest | 00 | 00
323 to zero | 01 | 11
324 to +infinity | 10 | 10
325 to -infinity | 11 | 01
327 /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 3 */
328 HReg irrm = iselWordExpr_R(env, mode);
329 HReg tmp = newVRegI(env);
330 HReg msacsr_old = newVRegI(env);
331 MIPSAMode *am_addr;
332 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
333 MIPSRH_Imm(False, 1)));
334 addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
335 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp, MIPSRH_Imm(False, 3)));
336 /* save old value of MSACSR */
337 addInstr(env, MIPSInstr_MsaElm(MSA_CFCMSA, hregMIPS_GPR0(mode64), msacsr_old,
338 MSA_DFN_W));
339 sub_from_sp(env, 8); /* Move SP down 8 bytes */
340 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
341 /* store old MSACSR to stack */
342 addInstr(env, MIPSInstr_Store(4, am_addr, msacsr_old, mode64));
343 /* set new value of MSACSR */
344 addInstr(env, MIPSInstr_MsaElm(MSA_CTCMSA, tmp, hregMIPS_GPR0(mode64),
345 MSA_DFN_W));
349 static void set_guest_MIPS_rounding_mode_MSA(ISelEnv * env) {
351 rounding mode | MIPS | IR
352 ------------------------
353 to nearest | 00 | 00
354 to zero | 01 | 11
355 to +infinity | 10 | 10
356 to -infinity | 11 | 01
358 /* rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 3 */
359 HReg irrm = newVRegI(env);
360 HReg msacsr_old = newVRegI(env);
361 MIPSAMode *am_addr;
362 MIPSAMode *rm_addr = MIPSAMode_IR(MSACSR_OFFSET(mode64),
363 GuestStatePointer(mode64));
364 addInstr(env, MIPSInstr_Load(4, irrm, rm_addr, mode64));
365 /* save old value of MSACSR */
366 addInstr(env, MIPSInstr_MsaElm(MSA_CFCMSA, hregMIPS_GPR0(mode64), msacsr_old,
367 MSA_DFN_W));
368 sub_from_sp(env, 8); /* Move SP down 8 bytes */
369 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
370 /* store old MSACSR to stack */
371 addInstr(env, MIPSInstr_Store(4, am_addr, msacsr_old, mode64));
372 /* set new value of MSACSR */
373 addInstr(env, MIPSInstr_MsaElm(MSA_CTCMSA, irrm, hregMIPS_GPR0(mode64),
374 MSA_DFN_W));
378 static void set_MIPS_rounding_default(ISelEnv * env)
380 HReg fcsr = newVRegI(env);
381 /* load as float */
382 MIPSAMode *am_addr;
383 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
385 addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64));
387 add_to_sp(env, 8); /* Reset SP */
389 /* set new value of FCSR*/
390 addInstr(env, MIPSInstr_MtFCSR(fcsr));
393 static void set_MIPS_rounding_default_MSA(ISelEnv * env) {
394 HReg msacsr = newVRegI(env);
395 /* load as float */
396 MIPSAMode *am_addr;
397 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
398 addInstr(env, MIPSInstr_Load(4, msacsr, am_addr, mode64));
399 add_to_sp(env, 8); /* Reset SP */
400 /* set new value of FCSR*/
401 addInstr(env, MIPSInstr_MsaElm(MSA_CTCMSA, msacsr, hregMIPS_GPR0(mode64),
402 MSA_DFN_W));
405 /*---------------------------------------------------------*/
406 /*--- ISEL: Misc helpers ---*/
407 /*---------------------------------------------------------*/
409 /* Make an int reg-reg move. */
410 static MIPSInstr *mk_iMOVds_RR(HReg r_dst, HReg r_src)
412 vassert(hregClass(r_dst) == hregClass(r_src));
413 vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64);
414 return MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src));
417 /*---------------------------------------------------------*/
418 /*--- ISEL: Function call helpers ---*/
419 /*---------------------------------------------------------*/
421 /* Used only in doHelperCall. See big comment in doHelperCall re
422 handling of register-parameter args. This function figures out
423 whether evaluation of an expression might require use of a fixed
424 register. If in doubt return True (safe but suboptimal).
426 static Bool mightRequireFixedRegs(IRExpr * e)
428 switch (e->tag) {
429 case Iex_RdTmp:
430 case Iex_Const:
431 case Iex_Get:
432 return False;
433 default:
434 return True;
438 /* Load 2*I32 regs to fp reg */
439 static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
441 HReg fr_dst = newVRegD(env);
442 MIPSAMode *am_addr0, *am_addr1;
444 vassert(hregClass(r_srcHi) == HRcInt32);
445 vassert(hregClass(r_srcLo) == HRcInt32);
447 sub_from_sp(env, 16); /* Move SP down 16 bytes */
448 am_addr0 = MIPSAMode_IR(0, StackPointer(mode64));
449 am_addr1 = MIPSAMode_IR(4, StackPointer(mode64));
451 /* store hi,lo as Ity_I32's */
452 #if defined (_MIPSEL)
453 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64));
454 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64));
455 #elif defined (_MIPSEB)
456 addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcHi, mode64));
457 addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcLo, mode64));
458 #else
459 /* Stop gcc on other platforms complaining about am_addr1 being set
460 but not used. */
461 (void)am_addr1;
462 #endif
464 /* load as float */
465 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0));
467 add_to_sp(env, 16); /* Reset SP */
468 return fr_dst;
471 /* Do a complete function call. |guard| is a Ity_Bit expression
472 indicating whether or not the call happens. If guard==NULL, the
473 call is unconditional. |retloc| is set to indicate where the
474 return value is after the call. The caller (of this fn) must
475 generate code to add |stackAdjustAfterCall| to the stack pointer
476 after the call is done. */
478 static void doHelperCall(/*OUT*/UInt* stackAdjustAfterCall,
479 /*OUT*/RetLoc* retloc,
480 ISelEnv* env,
481 IRExpr* guard,
482 IRCallee* cee, IRType retTy, IRExpr** args )
484 MIPSCondCode cc;
485 HReg argregs[8];
486 HReg tmpregs[8];
487 Bool go_fast;
488 Int n_args, i, argreg;
489 UInt argiregs;
490 HReg src = INVALID_HREG;
492 /* Set default returns. We'll update them later if needed. */
493 *stackAdjustAfterCall = 0;
494 *retloc = mk_RetLoc_INVALID();
496 /* These are used for cross-checking that IR-level constraints on
497 the use of IRExpr_VECRET() and IRExpr_GSPTR() are observed. */
498 UInt nVECRETs = 0;
499 UInt nGSPTRs = 0;
501 /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
502 are allowed to be used for passing integer arguments. They correspond
503 to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
504 on MIPS host (since we only implement one calling convention) and so we
505 always ignore it. */
507 /* MIPS 64 calling convention: up to four registers ($a0 ... $a7)
508 are allowed to be used for passing integer arguments. They correspond
509 to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
510 on MIPS host (since we only implement one calling convention) and so we
511 always ignore it. */
513 /* The return type can be I{64,32,16,8} or V{128,256}. In the
514 latter two cases, it is expected that |args| will contain the
515 special node IRExpr_VECRET(), in which case this routine
516 generates code to allocate space on the stack for the vector
517 return value. Since we are not passing any scalars on the
518 stack, it is enough to preallocate the return space before
519 marshalling any arguments, in this case.
521 |args| may also contain IRExpr_GSPTR(), in which case the value
522 in the guest state pointer register is passed as the
523 corresponding argument. */
525 n_args = 0;
526 for (i = 0; args[i]; i++) {
527 IRExpr* arg = args[i];
528 if (UNLIKELY(arg->tag == Iex_VECRET)) {
529 nVECRETs++;
530 } else if (UNLIKELY(arg->tag == Iex_GSPTR)) {
531 nGSPTRs++;
533 n_args++;
536 if (n_args > MIPS_N_REGPARMS) {
537 vpanic("doHelperCall(MIPS): cannot currently handle > 4 or 8 args");
539 if (mode64) {
540 argregs[0] = hregMIPS_GPR4(mode64);
541 argregs[1] = hregMIPS_GPR5(mode64);
542 argregs[2] = hregMIPS_GPR6(mode64);
543 argregs[3] = hregMIPS_GPR7(mode64);
544 argregs[4] = hregMIPS_GPR8(mode64);
545 argregs[5] = hregMIPS_GPR9(mode64);
546 argregs[6] = hregMIPS_GPR10(mode64);
547 argregs[7] = hregMIPS_GPR11(mode64);
548 argiregs = 0;
549 tmpregs[0] = tmpregs[1] = tmpregs[2] =
550 tmpregs[3] = tmpregs[4] = tmpregs[5] =
551 tmpregs[6] = tmpregs[7] = INVALID_HREG;
552 } else {
553 argregs[0] = hregMIPS_GPR4(mode64);
554 argregs[1] = hregMIPS_GPR5(mode64);
555 argregs[2] = hregMIPS_GPR6(mode64);
556 argregs[3] = hregMIPS_GPR7(mode64);
557 argiregs = 0;
558 tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = INVALID_HREG;
561 /* First decide which scheme (slow or fast) is to be used. First assume the
562 fast scheme, and select slow if any contraindications (wow) appear. */
564 go_fast = True;
566 /* We'll need space on the stack for the return value. Avoid
567 possible complications with nested calls by using the slow
568 scheme. */
569 if (retTy == Ity_V128 || retTy == Ity_V256)
570 go_fast = False;
572 if (go_fast && guard) {
573 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
574 && guard->Iex.Const.con->Ico.U1 == True) {
575 /* unconditional */
576 } else {
577 /* Not manifestly unconditional -- be conservative. */
578 go_fast = False;
582 if (go_fast) {
583 for (i = 0; i < n_args; i++) {
584 if (mightRequireFixedRegs(args[i])) {
585 go_fast = False;
586 break;
591 /* At this point the scheme to use has been established. Generate
592 code to get the arg values into the argument rregs. */
593 if (go_fast) {
594 /* FAST SCHEME */
595 argreg = 0;
597 for (i = 0; i < n_args; i++) {
598 IRExpr* arg = args[i];
599 vassert(argreg < MIPS_N_REGPARMS);
601 IRType aTy = Ity_INVALID;
602 if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
603 aTy = typeOfIRExpr(env->type_env, arg);
605 if (aTy == Ity_I32 || (mode64 && aTy != Ity_INVALID)) {
606 argiregs |= (1 << (argreg + 4));
607 addInstr(env, mk_iMOVds_RR(argregs[argreg],
608 iselWordExpr_R(env, arg)));
609 argreg++;
610 } else if (aTy == Ity_I64) { /* Ity_I64 */
611 if (argreg & 1) {
612 argreg++;
613 argiregs |= (1 << (argreg + 4));
615 HReg rHi, rLo;
616 iselInt64Expr(&rHi, &rLo, env, arg);
617 argiregs |= (1 << (argreg + 4));
618 addInstr(env, mk_iMOVds_RR( argregs[argreg++], rLo ));
619 argiregs |= (1 << (argreg + 4));
620 addInstr(env, mk_iMOVds_RR( argregs[argreg], rHi));
621 argreg++;
622 } else if (arg->tag == Iex_GSPTR) {
623 vassert(0); // ATC
624 addInstr(env, mk_iMOVds_RR(argregs[argreg],
625 GuestStatePointer(mode64)));
626 argreg++;
627 } else if (arg->tag == Iex_VECRET) {
628 // If this happens, it denotes ill-formed IR.
629 vassert(0);
632 /* Fast scheme only applies for unconditional calls. Hence: */
633 cc = MIPScc_AL;
634 } else {
635 /* SLOW SCHEME; move via temporaries */
636 argreg = 0;
638 for (i = 0; i < n_args; i++) {
639 vassert(argreg < MIPS_N_REGPARMS);
640 IRExpr* arg = args[i];
642 IRType aTy = Ity_INVALID;
643 if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
644 aTy = typeOfIRExpr(env->type_env, arg);
646 if (aTy == Ity_I32 || (mode64 && aTy != Ity_INVALID)) {
647 tmpregs[argreg] = iselWordExpr_R(env, arg);
648 argreg++;
649 } else if (aTy == Ity_I64) { /* Ity_I64 */
650 if (argreg & 1)
651 argreg++;
652 if (argreg + 1 >= MIPS_N_REGPARMS)
653 vassert(0); /* out of argregs */
654 HReg raHi, raLo;
655 iselInt64Expr(&raHi, &raLo, env, arg);
656 tmpregs[argreg] = raLo;
657 argreg++;
658 tmpregs[argreg] = raHi;
659 argreg++;
660 } else if (arg->tag == Iex_GSPTR) {
661 tmpregs[argreg] = GuestStatePointer(mode64);
662 argreg++;
664 else if (arg->tag == Iex_VECRET) {
665 tmpregs[argreg++] = StackPointer(mode64);
666 sub_from_sp(env, 16); /* Move SP down 16 bytes */
670 /* Now we can compute the condition. We can't do it earlier
671 because the argument computations could trash the condition
672 codes. Be a bit clever to handle the common case where the
673 guard is 1:Bit. */
674 cc = MIPScc_AL;
675 if (guard) {
676 if (guard->tag == Iex_Const && guard->Iex.Const.con->tag == Ico_U1
677 && guard->Iex.Const.con->Ico.U1 == True) {
678 /* unconditional -- do nothing */
679 } else {
680 cc = iselCondCode(env, guard);
681 src = iselWordExpr_R(env, guard);
684 /* Move the args to their final destinations. */
685 for (i = 0; i < argreg; i++) {
686 if (hregIsInvalid(tmpregs[i])) /* Skip invalid regs */
687 continue;
688 /* None of these insns, including any spill code that might
689 be generated, may alter the condition codes. */
690 argiregs |= (1 << (i + 4));
691 addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
695 /* Do final checks, set the return values, and generate the call
696 instruction proper. */
697 vassert(nGSPTRs == 0 || nGSPTRs == 1);
698 vassert(nVECRETs == ((retTy == Ity_V128 || retTy == Ity_V256) ? 1 : 0));
699 vassert(*stackAdjustAfterCall == 0);
700 vassert(is_RetLoc_INVALID(*retloc));
701 switch (retTy) {
702 case Ity_INVALID:
703 /* Function doesn't return a value. */
704 *retloc = mk_RetLoc_simple(RLPri_None);
705 break;
706 case Ity_I64:
707 *retloc = mk_RetLoc_simple(mode64 ? RLPri_Int : RLPri_2Int);
708 break;
709 case Ity_I32: case Ity_I16: case Ity_I8:
710 *retloc = mk_RetLoc_simple(RLPri_Int);
711 break;
712 case Ity_V128:
713 *retloc = mk_RetLoc_spRel(RLPri_V128SpRel, 0);
714 *stackAdjustAfterCall = 16;
715 break;
716 case Ity_V256:
717 vassert(0); // ATC
718 *retloc = mk_RetLoc_spRel(RLPri_V256SpRel, 0);
719 *stackAdjustAfterCall = 32;
720 break;
721 default:
722 /* IR can denote other possible return types, but we don't
723 handle those here. */
724 vassert(0);
727 Addr64 target = mode64 ? (Addr)cee->addr :
728 toUInt((Addr)cee->addr);
730 /* Finally, generate the call itself. This needs the *retloc value
731 set in the switch above, which is why it's at the end. */
732 if (cc == MIPScc_AL)
733 addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs,
734 *retloc));
735 else
736 addInstr(env, MIPSInstr_Call(cc, target, argiregs, src, *retloc));
739 /*---------------------------------------------------------*/
740 /*--- ISEL: Integer expression auxiliaries ---*/
741 /*---------------------------------------------------------*/
743 /* --------------------- AMODEs --------------------- */
745 /* Return an AMode which computes the value of the specified
746 expression, possibly also adding insns to the code list as a
747 result. The expression may only be a word-size one.
750 static Bool uInt_fits_in_16_bits(UInt u)
752 Int i = u & 0xFFFF;
753 i <<= 16;
754 i >>= 16;
755 return toBool(u == (UInt) i);
758 static Bool uLong_fits_in_16_bits ( ULong u )
760 Long i = u & 0xFFFFULL;
761 i <<= 48;
762 i >>= 48;
763 return toBool(u == (ULong) i);
766 static Bool uLong_is_4_aligned ( ULong u )
768 return toBool((u & 3ULL) == 0);
771 static Bool sane_AMode(ISelEnv * env, MIPSAMode * am)
773 switch (am->tag) {
774 case Mam_IR:
775 return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) &&
776 hregIsVirtual(am->Mam.IR.base) &&
777 uInt_fits_in_16_bits(am->Mam.IR.index));
778 case Mam_RR:
779 return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) &&
780 hregIsVirtual(am->Mam.RR.base) &&
781 hregClass(am->Mam.RR.index) == HRcGPR(mode64) &&
782 hregIsVirtual(am->Mam.RR.index));
783 default:
784 vpanic("sane_AMode: unknown mips amode tag");
788 static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy)
790 MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
791 vassert(sane_AMode(env, am));
792 return am;
795 /* DO NOT CALL THIS DIRECTLY ! */
796 static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
797 IRType xferTy)
799 IRType ty = typeOfIRExpr(env->type_env, e);
800 if (env->mode64) {
801 Bool aligned4imm = toBool(xferTy == Ity_I32 || xferTy == Ity_I64);
802 vassert(ty == Ity_I64);
804 /* Add64(expr,i), where i == sign-extend of (i & 0xFFFF) */
805 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64
806 && e->Iex.Binop.arg2->tag == Iex_Const
807 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U64
808 && (aligned4imm ?
809 uLong_is_4_aligned(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64) : True)
810 && uLong_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con->Ico.U64)) {
811 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U64,
812 iselWordExpr_R(env, e->Iex.Binop.arg1));
815 /* Add64(expr,expr) */
816 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add64) {
817 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
818 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
819 return MIPSAMode_RR(r_idx, r_base);
821 } else {
822 vassert(ty == Ity_I32);
824 /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
825 if (e->tag == Iex_Binop
826 && e->Iex.Binop.op == Iop_Add32
827 && e->Iex.Binop.arg2->tag == Iex_Const
828 && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
829 && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) {
830 return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
831 iselWordExpr_R(env, e->Iex.Binop.arg1));
834 /* Add32(expr,expr) */
835 if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) {
836 HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
837 HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
839 return MIPSAMode_RR(r_idx, r_base);
843 /* Doesn't match anything in particular. Generate it into
844 a register and use that. */
845 return MIPSAMode_IR(0, iselWordExpr_R(env, e));
848 /*---------------------------------------------------------*/
849 /*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
850 /*---------------------------------------------------------*/
852 /* Select insns for an integer-typed expression, and add them to the
853 code list. Return a reg holding the result. This reg will be a
854 virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
855 want to modify it, ask for a new vreg, copy it in there, and modify
856 the copy. The register allocator will do its best to map both
857 vregs to the same real register, so the copies will often disappear
858 later in the game.
860 This should handle expressions of 64, 32, 16 and 8-bit type.
861 All results are returned in a (mode64 ? 64bit : 32bit) register.
862 For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
863 are arbitrary, so you should mask or sign extend partial values
864 if necessary.
866 static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e)
868 HReg r = iselWordExpr_R_wrk(env, e);
869 /* sanity checks ... */
871 vassert(hregClass(r) == HRcGPR(env->mode64));
872 vassert(hregIsVirtual(r));
873 return r;
876 /* DO NOT CALL THIS DIRECTLY ! */
877 static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
879 UInt argiregs = 0;
880 IRType ty = typeOfIRExpr(env->type_env, e);
881 vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1
882 || ty == Ity_F32 || (ty == Ity_I64 && mode64)
883 || (ty == Ity_I128 && mode64));
885 switch (e->tag) {
886 /* --------- TEMP --------- */
887 case Iex_RdTmp:
888 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
890 /* --------- LOAD --------- */
891 case Iex_Load: {
892 HReg r_dst = newVRegI(env);
893 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
895 if (e->Iex.Load.end != Iend_LE
896 && e->Iex.Load.end != Iend_BE)
897 goto irreducible;
899 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)),
900 r_dst, am_addr, mode64));
901 return r_dst;
904 /* --------- BINARY OP --------- */
905 case Iex_Binop: {
906 MIPSAluOp aluOp;
907 MIPSShftOp shftOp;
909 /* Is it an addition or logical style op? */
910 switch (e->Iex.Binop.op) {
911 case Iop_Add8:
912 case Iop_Add16:
913 case Iop_Add32:
914 aluOp = Malu_ADD;
915 break;
917 case Iop_Sub8:
918 case Iop_Sub16:
919 case Iop_Sub32:
920 aluOp = Malu_SUB;
921 break;
923 case Iop_Sub64:
924 aluOp = Malu_DSUB;
925 break;
927 case Iop_And1:
928 case Iop_And8:
929 case Iop_And16:
930 case Iop_And32:
931 case Iop_And64:
932 aluOp = Malu_AND;
933 break;
935 case Iop_Or1:
936 case Iop_Or8:
937 case Iop_Or16:
938 case Iop_Or32:
939 case Iop_Or64:
940 aluOp = Malu_OR;
941 break;
943 case Iop_Xor8:
944 case Iop_Xor16:
945 case Iop_Xor32:
946 case Iop_Xor64:
947 aluOp = Malu_XOR;
948 break;
950 case Iop_Add64:
951 aluOp = Malu_DADD;
952 break;
954 default:
955 aluOp = Malu_INVALID;
956 break;
959 /* For commutative ops we assume any literal
960 values are on the second operand. */
961 if (aluOp != Malu_INVALID) {
962 HReg r_dst = newVRegI(env);
963 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
964 MIPSRH *ri_srcR = NULL;
965 /* get right arg into an RH, in the appropriate way */
966 switch (aluOp) {
967 case Malu_ADD:
968 case Malu_SUB:
969 case Malu_DADD:
970 case Malu_DSUB:
971 ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
972 e->Iex.Binop.arg2);
973 break;
974 case Malu_AND:
975 case Malu_OR:
976 case Malu_XOR:
977 ri_srcR = iselWordExpr_RH(env, False /*unsigned */,
978 e->Iex.Binop.arg2);
979 break;
980 default:
981 vpanic("iselWordExpr_R_wrk-aluOp-arg2");
983 addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
984 return r_dst;
987 /* a shift? */
988 switch (e->Iex.Binop.op) {
989 case Iop_Shl32:
990 case Iop_Shl64:
991 shftOp = Mshft_SLL;
992 break;
993 case Iop_Shr16:
994 case Iop_Shr32:
995 case Iop_Shr64:
996 shftOp = Mshft_SRL;
997 break;
998 case Iop_Sar16:
999 case Iop_Sar32:
1000 case Iop_Sar64:
1001 shftOp = Mshft_SRA;
1002 break;
1003 default:
1004 shftOp = Mshft_INVALID;
1005 break;
1008 /* we assume any literal values are on the second operand. */
1009 if (shftOp != Mshft_INVALID) {
1010 HReg r_dst = newVRegI(env);
1011 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1012 MIPSRH *ri_srcR;
1013 if (mode64)
1014 ri_srcR = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
1015 else
1016 ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop.arg2);
1018 if (ty == Ity_I8) {
1019 vassert(0);
1020 } else if (ty == Ity_I16) {
1021 if (shftOp == Mshft_SRA) {
1022 HReg tmp = newVRegI(env);
1023 HReg r_srcL_se = newVRegI(env);
1024 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp,
1025 r_srcL, MIPSRH_Imm(False, 16)));
1026 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_srcL_se,
1027 tmp, MIPSRH_Imm(False, 16)));
1028 addInstr(env, MIPSInstr_Shft(shftOp, True,
1029 r_dst, r_srcL_se, ri_srcR));
1030 } else if (shftOp == Mshft_SRL) {
1031 HReg r_srcL_se = newVRegI(env);
1032 addInstr(env, MIPSInstr_Alu(Malu_AND, r_srcL_se, r_srcL,
1033 MIPSRH_Imm(False, 0xFFFF)));
1034 addInstr(env, MIPSInstr_Shft(shftOp, True,
1035 r_dst, r_srcL_se, ri_srcR));
1036 } else {
1037 vassert(0);
1039 } else if (ty == Ity_I32) {
1040 if (mode64 && (shftOp == Mshft_SRA || shftOp == Mshft_SRL)) {
1041 HReg tmp = newVRegI(env);
1042 HReg r_srcL_se = newVRegI(env);
1043 /* SRA, SRAV, SRL, SRLV: On 64-bit processors, if GPR rt does
1044 not contain a sign-extended 32-bit value (bits 63..31
1045 equal), then the result of the operation is UNPREDICTABLE.
1046 So we need to sign-extend r_srcL:
1047 DSLLV tmp, r_srcL, 32
1048 DSRAV r_srcL_se, tmp, 32
1050 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tmp,
1051 r_srcL, MIPSRH_Imm(False, 32)));
1052 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, r_srcL_se,
1053 tmp, MIPSRH_Imm(False, 32)));
1054 /* And finally do the shift. */
1055 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
1056 r_dst, r_srcL_se, ri_srcR));
1057 } else
1058 addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
1059 r_dst, r_srcL, ri_srcR));
1060 } else if (ty == Ity_I64) {
1061 vassert(mode64);
1062 addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */,
1063 r_dst, r_srcL, ri_srcR));
1064 } else
1065 goto irreducible;
1066 return r_dst;
1069 if (!mode64 && (e->Iex.Binop.op == Iop_CasCmpEQ64
1070 || e->Iex.Binop.op == Iop_CmpEQ64)) {
1071 HReg tmp1, tmp2, tmp3, tmp4;
1072 HReg dst1 = newVRegI(env);
1073 HReg dst2 = newVRegI(env);
1074 iselInt64Expr(&tmp1, &tmp2, env, e->Iex.Binop.arg1);
1075 iselInt64Expr(&tmp3, &tmp4, env, e->Iex.Binop.arg2);
1076 addInstr(env, MIPSInstr_Cmp(False, True, dst1, tmp1, tmp3, MIPScc_EQ));
1077 addInstr(env, MIPSInstr_Cmp(False, True, dst2, tmp2, tmp4, MIPScc_EQ));
1078 addInstr(env, MIPSInstr_Alu(Malu_AND, dst1, dst1, MIPSRH_Reg(dst2)));
1079 return dst1;
1082 /* Cmp*32*(x,y) ? */
1083 if (e->Iex.Binop.op == Iop_CmpEQ32
1084 || e->Iex.Binop.op == Iop_CmpEQ8
1085 || e->Iex.Binop.op == Iop_CmpEQ16
1086 || e->Iex.Binop.op == Iop_CmpNE32
1087 || e->Iex.Binop.op == Iop_CmpNE64
1088 || e->Iex.Binop.op == Iop_CmpLT32S
1089 || e->Iex.Binop.op == Iop_CmpLT32U
1090 || e->Iex.Binop.op == Iop_CmpLT64U
1091 || e->Iex.Binop.op == Iop_CmpLE32U
1092 || e->Iex.Binop.op == Iop_CmpLE32S
1093 || e->Iex.Binop.op == Iop_CmpLE64S
1094 || e->Iex.Binop.op == Iop_CmpLT64S
1095 || e->Iex.Binop.op == Iop_CmpEQ64
1096 || e->Iex.Binop.op == Iop_CasCmpEQ32
1097 || e->Iex.Binop.op == Iop_CasCmpEQ64) {
1099 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
1100 || e->Iex.Binop.op == Iop_CmpLE32S
1101 || e->Iex.Binop.op == Iop_CmpLT64S
1102 || e->Iex.Binop.op == Iop_CmpLE64S);
1103 Bool size32;
1104 HReg dst = newVRegI(env);
1105 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
1106 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
1108 MIPSCondCode cc;
1110 switch (e->Iex.Binop.op) {
1111 case Iop_CmpEQ32:
1112 case Iop_CasCmpEQ32:
1113 cc = MIPScc_EQ;
1114 size32 = True;
1115 break;
1116 case Iop_CmpEQ8:
1117 case Iop_CmpEQ16:
1118 cc = MIPScc_EQ;
1119 size32 = True;
1120 break;
1121 case Iop_CmpNE32:
1122 cc = MIPScc_NE;
1123 size32 = True;
1124 break;
1125 case Iop_CmpNE64:
1126 cc = MIPScc_NE;
1127 size32 = False;
1128 break;
1129 case Iop_CmpLT32S:
1130 cc = MIPScc_LT;
1131 size32 = True;
1132 break;
1133 case Iop_CmpLT32U:
1134 cc = MIPScc_LO;
1135 size32 = True;
1136 break;
1137 case Iop_CmpLT64U:
1138 cc = MIPScc_LO;
1139 size32 = False;
1140 break;
1141 case Iop_CmpLE32U:
1142 cc = MIPScc_LE;
1143 size32 = True;
1144 break;
1145 case Iop_CmpLE32S:
1146 cc = MIPScc_LE;
1147 size32 = True;
1148 break;
1149 case Iop_CmpLE64S:
1150 cc = MIPScc_LE;
1151 size32 = False;
1152 break;
1153 case Iop_CmpLT64S:
1154 cc = MIPScc_LT;
1155 size32 = False;
1156 break;
1157 case Iop_CmpEQ64:
1158 case Iop_CasCmpEQ64:
1159 cc = MIPScc_EQ;
1160 size32 = False;
1161 break;
1162 default:
1163 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
1166 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
1167 return dst;
1170 if (e->Iex.Binop.op == Iop_Max32U) {
1171 HReg tmp = newVRegI(env);
1172 HReg r_dst = newVRegI(env);
1173 HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1174 HReg argR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1175 MIPSRH *argRH = MIPSRH_Reg(argR);
1176 /* max (v0, s0)
1177 ------------
1178 slt v1, v0, s0
1179 movn v0, s0, v1 */
1181 addInstr(env, MIPSInstr_Alu(Malu_SLT, tmp, argL, argRH));
1182 #if (__mips_isa_rev >= 6)
1184 HReg r_temp = newVRegI(env);
1185 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dst, argL, tmp));
1186 addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, argR, tmp));
1187 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
1188 MIPSRH_Reg(r_temp)));
1191 #else
1192 addInstr(env, mk_iMOVds_RR(r_dst, argL));
1193 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, argR, tmp));
1194 #endif
1195 return r_dst;
1198 if (e->Iex.Binop.op == Iop_Mul32) {
1199 HReg r_dst = newVRegI(env);
1200 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1201 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1202 #if (__mips_isa_rev >= 6)
1203 addInstr(env, MIPSInstr_Mulr6(False, True, True,
1204 r_dst, r_srcL, r_srcR));
1205 #else
1206 addInstr(env, MIPSInstr_Mul(r_dst, r_srcL, r_srcR));
1207 #endif
1208 return r_dst;
1211 if (e->Iex.Binop.op == Iop_Mul64 ||
1212 e->Iex.Binop.op == Iop_MullS32) {
1213 vassert(mode64);
1214 HReg r_dst = newVRegI(env);
1215 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1216 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1217 #if (__mips_isa_rev >= 6)
1218 addInstr(env, MIPSInstr_Mulr6(False, False, True,
1219 r_dst, r_srcL, r_srcR));
1220 #else
1221 addInstr(env, MIPSInstr_Mult(True, r_srcL, r_srcR));
1222 addInstr(env, MIPSInstr_Mflo(r_dst));
1223 #endif
1224 return r_dst;
1227 if (e->Iex.Binop.op == Iop_MullU32) {
1228 vassert(mode64);
1229 HReg r_tmpL = newVRegI(env);
1230 HReg r_tmpR = newVRegI(env);
1231 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1232 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1233 #if (__mips_isa_rev >= 6)
1234 addInstr(env, MIPSInstr_Ext(r_tmpL, r_srcL, 0, 32));
1235 addInstr(env, MIPSInstr_Ext(r_tmpR, r_srcR, 0, 32));
1236 addInstr(env, MIPSInstr_Mulr6(True, False, True,
1237 r_tmpR, r_tmpL, r_tmpR));
1238 #else
1239 if (VEX_MIPS_CPU_HAS_MIPS64R2(hwcaps_host)) {
1240 addInstr(env, MIPSInstr_Ext(r_tmpL, r_srcL, 0, 32));
1241 addInstr(env, MIPSInstr_Ext(r_tmpR, r_srcR, 0, 32));
1242 } else {
1243 addInstr(env, MIPSInstr_LI(r_tmpL, 0xFFFFFFFF));
1244 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmpR, r_srcR,
1245 MIPSRH_Reg(r_tmpL)));
1246 addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmpL, r_srcL,
1247 MIPSRH_Reg(r_tmpL)));
1249 addInstr(env, MIPSInstr_Mult(False, r_tmpL, r_tmpR));
1250 addInstr(env, MIPSInstr_Mflo(r_tmpR));
1251 #endif
1252 return r_tmpR;
1255 if (e->Iex.Binop.op == Iop_MullU8 ||
1256 e->Iex.Binop.op == Iop_MullS8 ||
1257 e->Iex.Binop.op == Iop_MullU16 ||
1258 e->Iex.Binop.op == Iop_MullS16) {
1259 Bool syned = toBool((e->Iex.Binop.op == Iop_MullS8) ||
1260 (e->Iex.Binop.op == Iop_MullS16));
1261 HReg r_dst = newVRegI(env);
1262 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1263 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1264 #if (__mips_isa_rev >= 6)
1265 if (syned) {
1266 Int no_bits = (e->Iex.Binop.op == Iop_MullS16) ? 16 : 24;
1267 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True,
1268 r_srcL, r_srcL,
1269 MIPSRH_Imm(False, no_bits)));
1270 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True,
1271 r_srcL, r_srcL,
1272 MIPSRH_Imm(False, no_bits)));
1273 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True,
1274 r_srcR, r_srcR,
1275 MIPSRH_Imm(False, no_bits)));
1276 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True,
1277 r_srcR, r_srcR,
1278 MIPSRH_Imm(False, no_bits)));
1280 addInstr(env, MIPSInstr_Mulr6(syned, True, True,
1281 r_dst, r_srcL, r_srcR));
1282 #else
1283 if (syned) {
1284 Int no_bits = (e->Iex.Binop.op == Iop_MullS16) ? 16 : 24;
1285 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True,
1286 r_srcL, r_srcL,
1287 MIPSRH_Imm(False, no_bits)));
1288 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True,
1289 r_srcL, r_srcL,
1290 MIPSRH_Imm(False, no_bits)));
1291 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True,
1292 r_srcR, r_srcR,
1293 MIPSRH_Imm(False, no_bits)));
1294 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True,
1295 r_srcR, r_srcR,
1296 MIPSRH_Imm(False, no_bits)));
1297 addInstr(env, MIPSInstr_Mul(r_dst, r_srcL, r_srcR));
1299 } else {
1300 addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR));
1301 addInstr(env, MIPSInstr_Mflo(r_dst));
1303 #endif
1304 return r_dst;
1307 if (e->Iex.Binop.op == Iop_CmpF64) {
1308 HReg r_srcL, r_srcR;
1309 if (mode64) {
1310 r_srcL = iselFltExpr(env, e->Iex.Binop.arg1);
1311 r_srcR = iselFltExpr(env, e->Iex.Binop.arg2);
1312 } else {
1313 r_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
1314 r_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
1316 #if (__mips_isa_rev >= 6)
1317 HReg tmp = newVRegI(env);
1318 HReg tmpf;
1319 HReg result = newVRegI(env);
1320 if (mode64) tmpf = newVRegF(env);
1321 else tmpf = newVRegD(env);
1322 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmpf, r_srcL, r_srcR));
1323 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf));
1324 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1325 MIPSRH_Imm(False, 0x45)));
1326 addInstr(env, MIPSInstr_Alu(Malu_OR, result,
1327 hregMIPS_GPR0(env->mode64),
1328 MIPSRH_Reg(tmp)));
1329 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmpf, r_srcL, r_srcR));
1330 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf));
1331 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1332 MIPSRH_Imm(False, 0x1)));
1333 addInstr(env, MIPSInstr_Alu(Malu_OR, result, result,
1334 MIPSRH_Reg(tmp)));
1335 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmpf, r_srcL, r_srcR));
1336 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf));
1337 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1338 MIPSRH_Imm(False, 0x40)));
1339 addInstr(env, MIPSInstr_Alu(Malu_OR, result, result,
1340 MIPSRH_Reg(tmp)));
1341 return result;
1342 #else
1343 HReg tmp = newVRegI(env);
1344 HReg r_ccMIPS = newVRegI(env);
1345 HReg r_ccIR = newVRegI(env);
1346 HReg r_ccIR_b0 = newVRegI(env);
1347 HReg r_ccIR_b2 = newVRegI(env);
1348 HReg r_ccIR_b6 = newVRegI(env);
1350 /* Create in dst, the IRCmpF64Result encoded result. */
1351 /* chech for EQ */
1352 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ, tmp, r_srcL, r_srcR));
1353 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccMIPS, tmp,
1354 MIPSRH_Imm(False, 1)));
1355 /* chech for UN */
1356 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN, tmp, r_srcL, r_srcR));
1357 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1358 MIPSRH_Reg(tmp)));
1359 /* chech for LT */
1360 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT, tmp, r_srcL, r_srcR));
1361 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp,
1362 tmp, MIPSRH_Imm(False, 2)));
1363 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1364 MIPSRH_Reg(tmp)));
1365 /* chech for GT */
1366 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_NGT,
1367 tmp, r_srcL, r_srcR));
1368 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, tmp,
1369 MIPSRH_Imm(False, 3)));
1371 addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp)));
1372 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1373 MIPSRH_Imm(False, 8)));
1374 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
1375 MIPSRH_Reg(tmp)));
1376 /* Map compare result from MIPS to IR,
1377 conforming to CmpF64 definition.
1378 FP cmp result | MIPS | IR
1379 --------------------------
1380 UN | 0x1 | 0x45
1381 EQ | 0x2 | 0x40
1382 GT | 0x4 | 0x00
1383 LT | 0x8 | 0x01
1386 /* r_ccIR_b0 = r_ccMIPS[0] | r_ccMIPS[3] */
1387 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS,
1388 MIPSRH_Imm(False, 0x3)));
1389 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS,
1390 MIPSRH_Reg(r_ccIR_b0)));
1391 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0,
1392 MIPSRH_Imm(False, 0x1)));
1394 /* r_ccIR_b2 = r_ccMIPS[0] */
1395 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS,
1396 MIPSRH_Imm(False, 0x2)));
1397 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2,
1398 MIPSRH_Imm(False, 0x4)));
1400 /* r_ccIR_b6 = r_ccMIPS[0] | r_ccMIPS[1] */
1401 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6,
1402 r_ccMIPS, MIPSRH_Imm(False, 0x1)));
1403 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS,
1404 MIPSRH_Reg(r_ccIR_b6)));
1405 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6,
1406 MIPSRH_Imm(False, 0x6)));
1407 addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6,
1408 MIPSRH_Imm(False, 0x40)));
1410 /* r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6 */
1411 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0,
1412 MIPSRH_Reg(r_ccIR_b2)));
1413 addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR,
1414 MIPSRH_Reg(r_ccIR_b6)));
1415 return r_ccIR;
1416 #endif
1419 if (e->Iex.Binop.op == Iop_CmpF32) {
1420 #if (__mips_isa_rev >= 6)
1421 HReg r_srcL = iselFltExpr(env, e->Iex.Binop.arg1);
1422 HReg r_srcR = iselFltExpr(env, e->Iex.Binop.arg2);
1423 HReg tmp = newVRegI(env);
1424 HReg tmpf;
1425 HReg result = newVRegI(env);
1426 if (mode64) tmpf = newVRegF(env);
1427 else tmpf = newVRegD(env);
1428 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_UN_S, tmpf, r_srcL, r_srcR));
1429 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf));
1430 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1431 MIPSRH_Imm(False, 0x45)));
1432 addInstr(env, MIPSInstr_Alu(Malu_OR, result,
1433 hregMIPS_GPR0(env->mode64),
1434 MIPSRH_Reg(tmp)));
1435 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_LT_S, tmpf, r_srcL, r_srcR));
1436 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf));
1437 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1438 MIPSRH_Imm(False, 0x1)));
1439 addInstr(env, MIPSInstr_Alu(Malu_OR, result, result,
1440 MIPSRH_Reg(tmp)));
1441 addInstr(env, MIPSInstr_FpCompare(Mfp_CMP_EQ_S, tmpf, r_srcL, r_srcR));
1442 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, tmp, tmpf));
1443 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
1444 MIPSRH_Imm(False, 0x40)));
1445 addInstr(env, MIPSInstr_Alu(Malu_OR, result, result,
1446 MIPSRH_Reg(tmp)));
1447 return result;
1448 #endif
1451 if (e->Iex.Binop.op == Iop_DivModU32to32 ||
1452 e->Iex.Binop.op == Iop_DivModS32to32) {
1453 HReg tLo = newVRegI(env);
1454 HReg tHi = newVRegI(env);
1455 HReg mask = newVRegI(env);
1456 HReg tLo_1 = newVRegI(env);
1457 HReg tHi_1 = newVRegI(env);
1458 HReg r_dst = newVRegI(env);
1459 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS32to32);
1461 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1462 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1463 #if (__mips_isa_rev >= 6)
1464 addInstr(env, MIPSInstr_Divr6(syned /* Unsigned or Signed */ ,
1465 True /* 32bit or 64bit div */ ,
1466 False /* mod */,
1467 tLo, r_srcL, r_srcR));
1468 addInstr(env, MIPSInstr_Divr6(syned /* Unsigned or Signed */ ,
1469 True /*3 2bit or 64bit div */ ,
1470 True /* mod */,
1471 tHi, r_srcL, r_srcR));
1472 #else
1473 addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
1474 addInstr(env, MIPSInstr_Mfhi(tHi));
1475 addInstr(env, MIPSInstr_Mflo(tLo));
1476 #endif
1477 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1478 MIPSRH_Imm(False, 32)));
1480 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1481 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1482 MIPSRH_Reg(mask)));
1484 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1485 MIPSRH_Reg(tLo_1)));
1487 return r_dst;
1490 if (e->Iex.Binop.op == Iop_DivS32 ||
1491 e->Iex.Binop.op == Iop_DivU32 ||
1492 (e->Iex.Binop.op == Iop_DivS64 && mode64) ||
1493 (e->Iex.Binop.op == Iop_DivU64 && mode64)) {
1494 HReg r_dst = newVRegI(env);
1495 Bool syned = toBool(e->Iex.Binop.op == Iop_DivS32 ||
1496 e->Iex.Binop.op == Iop_DivS64);
1497 Bool div32 = toBool(e->Iex.Binop.op == Iop_DivS32 ||
1498 e->Iex.Binop.op == Iop_DivU32);
1499 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1500 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1501 #if (__mips_isa_rev >= 6)
1502 addInstr(env, MIPSInstr_Divr6(syned, div32, False,
1503 r_dst, r_srcL, r_srcR));
1504 #else
1505 addInstr(env, MIPSInstr_Div(syned, div32, r_srcL, r_srcR));
1506 addInstr(env, MIPSInstr_Mflo(r_dst));
1507 #endif
1508 return r_dst;
1511 if (e->Iex.Binop.op == Iop_8HLto16
1512 || e->Iex.Binop.op == Iop_16HLto32) {
1513 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1514 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1515 HReg tLo_1 = newVRegI(env);
1516 HReg tHi_1 = newVRegI(env);
1517 HReg r_dst = newVRegI(env);
1518 UInt shift = 0;
1519 UInt mask = 0;
1520 switch (e->Iex.Binop.op) {
1521 case Iop_8HLto16:
1522 shift = 8;
1523 mask = 0xff;
1524 break;
1525 case Iop_16HLto32:
1526 shift = 16;
1527 mask = 0xffff;
1528 break;
1529 default:
1530 break;
1533 /* sll tHi_1, tHi, shift
1534 and tLo_1, tLo, mask
1535 or r_dst, tHi_1, tLo_1 */
1536 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tHi_1, tHi,
1537 MIPSRH_Imm(False, shift)));
1538 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1539 MIPSRH_Imm(False, mask)));
1540 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1541 MIPSRH_Reg(tLo_1)));
1542 return r_dst;
1545 if (e->Iex.Binop.op == Iop_32HLto64) {
1546 vassert(mode64);
1547 HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
1548 HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
1549 HReg tLo_1 = newVRegI(env);
1550 HReg tHi_1 = newVRegI(env);
1551 HReg r_dst = newVRegI(env);
1552 HReg mask = newVRegI(env);
1554 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
1555 MIPSRH_Imm(False, 32)));
1557 addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
1558 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
1559 MIPSRH_Reg(mask)));
1560 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
1561 MIPSRH_Reg(tLo_1)));
1563 return r_dst;
1566 if (e->Iex.Binop.op == Iop_F32toI64S) {
1567 vassert(mode64);
1568 HReg valS = newVRegI(env);
1569 HReg tmpF = newVRegF(env);
1570 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1572 /* CVTLS tmpF, valF */
1573 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1574 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpF, valF));
1575 set_MIPS_rounding_default(env);
1577 /* Doubleword Move from Floating Point
1578 dmfc1 valS, tmpF */
1579 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF));
1581 return valS;
1584 if (e->Iex.Binop.op == Iop_F64toI64S) {
1585 vassert(mode64);
1586 HReg valS = newVRegI(env);
1587 HReg tmpF = newVRegF(env);
1588 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1590 /* CVTLS tmpF, valF */
1591 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1592 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, tmpF, valF));
1593 set_MIPS_rounding_default(env);
1595 /* Doubleword Move from Floating Point
1596 dmfc1 valS, tmpF */
1597 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, valS, tmpF));
1599 return valS;
1602 if (e->Iex.Binop.op == Iop_F64toI32S) {
1603 HReg valD;
1604 if (mode64)
1605 valD = iselFltExpr(env, e->Iex.Binop.arg2);
1606 else
1607 valD = iselDblExpr(env, e->Iex.Binop.arg2);
1608 HReg valS = newVRegF(env);
1609 HReg r_dst = newVRegI(env);
1611 /* CVTWD valS, valD */
1612 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1613 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1614 set_MIPS_rounding_default(env);
1616 /* Move Word From Floating Point
1617 mfc1 r_dst, valS */
1618 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1620 return r_dst;
1623 if (e->Iex.Binop.op == Iop_F32toI32U) {
1624 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1625 HReg tmpD = newVRegD(env);
1626 HReg r_dst = newVRegI(env);
1627 MIPSAMode *am_addr;
1629 /* CVTLS tmpD, valF */
1630 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1631 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
1632 set_MIPS_rounding_default(env);
1634 sub_from_sp(env, 16); /* Move SP down 16 bytes */
1635 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
1637 /* store as F64 */
1638 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
1639 am_addr));
1640 /* load as 2xI32 */
1641 #if defined (_MIPSEL)
1642 addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64));
1643 #elif defined (_MIPSEB)
1644 addInstr(env, MIPSInstr_Load(4, r_dst, nextMIPSAModeFloat(am_addr),
1645 mode64));
1646 #endif
1648 /* Reset SP */
1649 add_to_sp(env, 16);
1651 return r_dst;
1654 if (e->Iex.Binop.op == Iop_F64toI64U) {
1655 HReg r_src;
1656 HReg tmp = newVRegV(env);
1657 vassert(has_msa);
1658 r_src = iselFltExpr( env, e->Iex.Binop.arg2);
1659 set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
1660 addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_U, MSA_F_DW, tmp, r_src));
1661 HReg r_dst = newVRegI(env);
1662 addInstr(env,
1663 MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_dst, MSA_DFN_D | 0));
1664 set_MIPS_rounding_default_MSA(env);
1665 return r_dst;
1668 if (e->Iex.Binop.op == Iop_GetElem8x16) {
1669 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
1670 HReg r_dst = newVRegI(env);
1671 MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
1672 vassert(has_msa);
1673 switch (tmp->tag) {
1674 case Mrh_Imm:
1675 addInstr(env,
1676 MIPSInstr_MsaElm(MSA_COPY_U, v_src, r_dst,
1677 MSA_DFN_B |
1678 (tmp->Mrh.Imm.imm16 & 0x0f)));
1679 break;
1681 case Mrh_Reg: {
1682 HReg v_tmp = newVRegV(env);
1683 addInstr(env,
1684 MIPSInstr_Msa3R(MSA_SPLAT, MSA_B, v_tmp, v_src,
1685 tmp->Mrh.Reg.reg));
1686 addInstr(env,
1687 MIPSInstr_MsaElm(MSA_COPY_U, v_tmp, r_dst,
1688 MSA_DFN_B));
1689 break;
1693 return r_dst;
1697 if (e->Iex.Binop.op == Iop_GetElem16x8) {
1698 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
1699 HReg r_dst = newVRegI(env);
1700 MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
1701 vassert(has_msa);
1702 switch (tmp->tag) {
1703 case Mrh_Imm:
1704 addInstr(env,
1705 MIPSInstr_MsaElm(MSA_COPY_U, v_src, r_dst,
1706 MSA_DFN_H |
1707 (tmp->Mrh.Imm.imm16 & 0x07)));
1708 break;
1710 case Mrh_Reg: {
1711 HReg v_tmp = newVRegV(env);
1712 addInstr(env,
1713 MIPSInstr_Msa3R(MSA_SPLAT, MSA_H, v_tmp, v_src,
1714 tmp->Mrh.Reg.reg));
1715 addInstr(env,
1716 MIPSInstr_MsaElm(MSA_COPY_U, v_tmp, r_dst,
1717 MSA_DFN_H));
1718 break;
1722 return r_dst;
1725 if (e->Iex.Binop.op == Iop_GetElem32x4) {
1726 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
1727 HReg r_dst = newVRegI(env);
1728 MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
1729 vassert(has_msa);
1730 switch (tmp->tag) {
1731 case Mrh_Imm:
1732 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dst,
1733 MSA_DFN_W |
1734 (tmp->Mrh.Imm.imm16 & 0x03)));
1735 break;
1737 case Mrh_Reg: {
1738 HReg v_tmp = newVRegV(env);
1739 addInstr(env,
1740 MIPSInstr_Msa3R(MSA_SPLAT, MSA_W, v_tmp, v_src,
1741 tmp->Mrh.Reg.reg));
1742 addInstr(env,
1743 MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dst,
1744 MSA_DFN_W));
1745 break;
1749 return r_dst;
1751 if (e->Iex.Binop.op == Iop_GetElem64x2) {
1752 vassert(mode64);
1753 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
1754 HReg r_dst = newVRegI(env);
1755 MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
1756 vassert(has_msa);
1757 switch (tmp->tag) {
1758 case Mrh_Imm:
1759 addInstr(env,
1760 MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dst,
1761 MSA_DFN_D |
1762 (tmp->Mrh.Imm.imm16 & 0x01)));
1763 break;
1765 case Mrh_Reg: {
1766 HReg v_tmp = newVRegV(env);
1767 addInstr(env,
1768 MIPSInstr_Msa3R(MSA_SPLAT, MSA_D, v_tmp, v_src,
1769 tmp->Mrh.Reg.reg));
1770 addInstr(env,
1771 MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dst,
1772 MSA_DFN_D));
1773 break;
1777 return r_dst;
1780 if (e->Iex.Binop.op == Iop_F32toI32S) {
1781 HReg valS = newVRegF(env);
1782 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
1783 HReg r_dst = newVRegI(env);
1785 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1786 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
1787 set_MIPS_rounding_default(env);
1789 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1791 return r_dst;
1794 /* -------- DSP ASE -------- */
1795 /* All used cases involving host-side helper calls. */
1796 void* fn = NULL;
1797 switch (e->Iex.Binop.op) {
1798 case Iop_HAdd8Ux4:
1799 fn = &h_generic_calc_HAdd8Ux4; break;
1800 case Iop_HSub8Ux4:
1801 fn = &h_generic_calc_HSub8Ux4; break;
1802 case Iop_HSub16Sx2:
1803 fn = &h_generic_calc_HSub16Sx2; break;
1804 case Iop_QSub8Ux4:
1805 fn = &h_generic_calc_QSub8Ux4; break;
1806 default:
1807 break;
1810 /* What's the retloc? */
1811 RetLoc rloc = mk_RetLoc_INVALID();
1812 if (ty == Ity_I32) {
1813 rloc = mk_RetLoc_simple(RLPri_Int);
1815 else if (ty == Ity_I64) {
1816 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
1817 mk_RetLoc_simple(RLPri_2Int);
1819 else {
1820 goto irreducible;
1823 if (fn) {
1824 HReg regL = iselWordExpr_R(env, e->Iex.Binop.arg1);
1825 HReg regR = iselWordExpr_R(env, e->Iex.Binop.arg2);
1826 HReg res = newVRegI(env);
1827 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
1828 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR5(env->mode64), regR));
1829 argiregs |= (1 << 4);
1830 argiregs |= (1 << 5);
1831 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
1832 (Addr)fn,
1833 argiregs, rloc));
1834 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
1835 return res;
1837 break;
1840 /* --------- UNARY OP --------- */
1841 case Iex_Unop: {
1842 IROp op_unop = e->Iex.Unop.op;
1844 switch (op_unop) {
1845 case Iop_1Sto8:
1846 case Iop_1Sto16:
1847 case Iop_1Sto32:
1848 case Iop_8Sto16:
1849 case Iop_8Sto32:
1850 case Iop_16Sto32:
1851 case Iop_16Sto64:
1852 case Iop_8Sto64:
1853 case Iop_1Sto64: {
1854 HReg r_dst = newVRegI(env);
1855 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1856 Bool sz32;
1857 UShort amt;
1858 switch (op_unop) {
1859 case Iop_1Sto8:
1860 amt = 31;
1861 sz32 = True;
1862 break;
1863 case Iop_1Sto16:
1864 amt = 31;
1865 sz32 = True;
1866 break;
1867 case Iop_1Sto32:
1868 amt = 31;
1869 sz32 = True;
1870 break;
1871 case Iop_16Sto32:
1872 amt = 16;
1873 sz32 = True;
1874 break;
1875 case Iop_16Sto64:
1876 amt = 48;
1877 sz32 = False;
1878 break;
1879 case Iop_8Sto16:
1880 amt = 24;
1881 sz32 = True;
1882 break;
1883 case Iop_8Sto32:
1884 amt = 24;
1885 sz32 = True;
1886 break;
1887 case Iop_8Sto64:
1888 amt = 56;
1889 sz32 = False;
1890 break;
1891 case Iop_1Sto64:
1892 amt = 63;
1893 sz32 = False;
1894 break;
1895 default:
1896 vassert(0);
1899 addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src,
1900 MIPSRH_Imm(False, amt)));
1901 addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst,
1902 MIPSRH_Imm(False, amt)));
1903 return r_dst;
1906 /* not(x) = nor(x,x) */
1907 case Iop_Not1: {
1908 HReg r_dst = newVRegI(env);
1909 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1910 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1912 addInstr(env, MIPSInstr_LI(r_dst, 0x1));
1913 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
1914 return r_dst;
1917 case Iop_Not8:
1918 case Iop_Not16:
1919 case Iop_Not32:
1920 case Iop_Not64: {
1921 HReg r_dst = newVRegI(env);
1922 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
1923 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
1925 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR));
1926 return r_dst;
1929 case Iop_ReinterpF32asI32: {
1930 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1931 HReg r_dst = newVRegI(env);
1933 /* Move Word From Floating Point
1934 mfc1 r_dst, fr_src */
1935 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, fr_src));
1937 return r_dst;
1940 case Iop_ReinterpF64asI64: {
1941 vassert(mode64);
1942 HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
1943 HReg r_dst = newVRegI(env);
1945 /* Doubleword Move from Floating Point
1946 mfc1 r_dst, fr_src */
1947 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmfc1, r_dst, fr_src));
1949 return r_dst;
1952 case Iop_F64toI32S: {
1953 HReg valD;
1954 if (mode64)
1955 valD = iselFltExpr(env, e->Iex.Binop.arg2);
1956 else
1957 valD = iselDblExpr(env, e->Iex.Binop.arg2);
1958 HReg valS = newVRegF(env);
1959 HReg r_dst = newVRegI(env);
1961 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
1962 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
1963 set_MIPS_rounding_default(env);
1965 /* Move Word From Floating Point
1966 mfc1 r_dst, valS */
1967 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mfc1, r_dst, valS));
1969 return r_dst;
1972 case Iop_16to8:
1973 case Iop_32to1:
1974 case Iop_32to8:
1975 case Iop_32to16:
1976 return iselWordExpr_R(env, e->Iex.Unop.arg);
1978 case Iop_32HIto16: {
1979 HReg r_dst = newVRegI(env);
1980 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1981 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
1982 r_dst, r_src, MIPSRH_Imm(False, 16)));
1983 return r_dst;
1986 case Iop_64to1:
1987 case Iop_64to8: {
1988 HReg r_src, r_dst;
1989 UShort mask = (op_unop == Iop_64to1) ? 0x1 : 0xFF;
1990 r_dst = newVRegI(env);
1991 if (mode64)
1992 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
1993 else {
1994 HReg tmp;
1995 iselInt64Expr(&tmp, &r_src, env, e->Iex.Unop.arg);
1997 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
1998 MIPSRH_Imm(False, mask)));
1999 return r_dst;
2002 case Iop_16HIto8: {
2003 HReg r_dst = newVRegI(env);
2004 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2005 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
2006 r_dst, r_src, MIPSRH_Imm(False, 8)));
2007 return r_dst;
2010 case Iop_1Uto8:
2011 case Iop_1Uto32:
2012 case Iop_1Uto64:
2013 case Iop_8Uto16:
2014 case Iop_8Uto32:
2015 case Iop_8Uto64:
2016 case Iop_16Uto32:
2017 case Iop_16Uto64: {
2018 HReg r_dst = newVRegI(env);
2019 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2020 UShort mask = 0;
2021 switch (op_unop) {
2022 case Iop_1Uto64:
2023 vassert(mode64);
2024 /* fallthrough */
2025 case Iop_1Uto8:
2026 case Iop_1Uto32:
2027 mask = toUShort(0x1);
2028 break;
2029 case Iop_8Uto64:
2030 vassert(mode64);
2031 /* fallthrough */
2032 case Iop_8Uto16:
2033 case Iop_8Uto32:
2034 mask = toUShort(0xFF);
2035 break;
2036 case Iop_16Uto64:
2037 vassert(mode64);
2038 /* fallthrough */
2039 case Iop_16Uto32:
2040 mask = toUShort(0xFFFF);
2041 break;
2042 default:
2043 vassert(0);
2044 break;
2046 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
2047 MIPSRH_Imm(False, mask)));
2048 return r_dst;
2051 case Iop_32Uto64: {
2052 HReg r_dst = newVRegI(env);
2053 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2054 vassert(mode64);
2055 addInstr(env, MIPSInstr_Shft(Mshft_SLL, False /*!32bit shift */,
2056 r_dst, r_src, MIPSRH_Imm(False, 32)));
2057 addInstr(env, MIPSInstr_Shft(Mshft_SRL, False /*!32bit shift */,
2058 r_dst, r_dst, MIPSRH_Imm(False, 32)));
2059 return r_dst;
2062 case Iop_64HIto32: {
2063 if (env->mode64) {
2064 HReg r_dst = newVRegI(env);
2065 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2066 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False /*64bit shift */,
2067 r_dst, r_src, MIPSRH_Imm(True, 32)));
2068 return r_dst;
2069 } else {
2070 HReg rHi, rLo;
2071 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
2072 return rHi;
2076 case Iop_64to32: {
2077 if (env->mode64) {
2078 HReg r_dst = newVRegI(env);
2079 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
2080 return r_dst;
2081 } else {
2082 HReg rHi, rLo;
2083 iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
2084 return rLo;
2088 case Iop_64to16: {
2089 vassert(env->mode64);
2090 HReg r_dst = newVRegI(env);
2091 r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
2092 return r_dst;
2095 case Iop_32Sto64: {
2096 HReg r_dst = newVRegI(env);
2097 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2098 vassert(mode64);
2099 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /*!32bit shift */,
2100 r_dst, r_src, MIPSRH_Imm(True, 0)));
2101 return r_dst;
2104 case Iop_CmpNEZ8:
2105 case Iop_CmpNEZ16: {
2106 HReg r_dst = newVRegI(env);
2107 HReg tmp = newVRegI(env);
2108 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2109 UShort mask = (op_unop == Iop_CmpNEZ8) ? 0xFF : 0xFFFF;
2111 addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src,
2112 MIPSRH_Imm(False, mask)));
2113 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp,
2114 hregMIPS_GPR0(mode64), MIPScc_NE));
2115 return r_dst;
2118 case Iop_CmpNEZ32: {
2119 HReg r_dst = newVRegI(env);
2120 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2122 addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src,
2123 hregMIPS_GPR0(mode64), MIPScc_NE));
2124 return r_dst;
2127 case Iop_CmpwNEZ32: {
2128 HReg r_dst = newVRegI(env);
2129 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2131 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
2132 MIPSRH_Reg(r_src)));
2134 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
2135 MIPSRH_Reg(r_src)));
2136 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst,
2137 MIPSRH_Imm(False, 31)));
2138 return r_dst;
2141 case Iop_Left8:
2142 case Iop_Left16:
2143 case Iop_Left32:
2144 case Iop_Left64: {
2145 if (op_unop == Iop_Left64 && !mode64)
2146 goto irreducible;
2147 HReg r_dst = newVRegI(env);
2148 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2149 MIPSAluOp op = (op_unop == Iop_Left64) ? Malu_DSUB : Malu_SUB;
2150 addInstr(env, MIPSInstr_Alu(op, r_dst,
2151 hregMIPS_GPR0(mode64),
2152 MIPSRH_Reg(r_src)));
2153 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
2154 MIPSRH_Reg(r_src)));
2155 return r_dst;
2158 case Iop_Clz64:
2159 vassert(mode64);
2160 /* fallthrough */
2161 case Iop_Clz32: {
2162 HReg r_dst = newVRegI(env);
2163 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2164 MIPSUnaryOp op = (op_unop == Iop_Clz64) ? Mun_DCLZ : Mun_CLZ;
2165 addInstr(env, MIPSInstr_Unary(op, r_dst, r_src));
2166 return r_dst;
2169 case Iop_CmpNEZ64: {
2170 HReg hi, lo;
2171 HReg r_dst = newVRegI(env);
2172 HReg r_src;
2173 if (env->mode64) {
2174 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2175 } else {
2176 r_src = newVRegI(env);
2177 iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg);
2178 addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi)));
2180 addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src,
2181 hregMIPS_GPR0(mode64), MIPScc_NE));
2182 return r_dst;
2185 case Iop_CmpwNEZ64: {
2186 HReg tmp1;
2187 HReg tmp2 = newVRegI(env);
2188 vassert(env->mode64);
2189 tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
2191 addInstr(env, MIPSInstr_Alu(Malu_DSUB, tmp2, hregMIPS_GPR0(mode64),
2192 MIPSRH_Reg(tmp1)));
2194 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
2195 addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2,
2196 MIPSRH_Imm (False, 63)));
2197 return tmp2;
2200 case Iop_128HIto64: {
2201 vassert(mode64);
2202 HReg rHi, rLo;
2203 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
2204 return rHi; /* and abandon rLo .. poor wee thing :-) */
2207 case Iop_128to64: {
2208 vassert(mode64);
2209 HReg rHi, rLo;
2210 iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
2211 return rLo; /* and abandon rLo .. poor wee thing :-) */
2214 case Iop_V128to32: {
2215 HReg i_dst = newVRegI(env);
2216 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2217 vassert(has_msa);
2218 addInstr(env,
2219 MIPSInstr_MsaElm(MSA_COPY_S, v_src, i_dst, MSA_DFN_W));
2220 return i_dst;
2223 case Iop_V128HIto64: {
2224 vassert(mode64);
2225 vassert(has_msa);
2226 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2227 HReg reg = newVRegI(env);
2228 addInstr(env,
2229 MIPSInstr_MsaElm(MSA_COPY_S, v_src, reg, MSA_DFN_D | 1));
2230 return reg;
2233 case Iop_V128to64: {
2234 vassert(mode64);
2235 vassert(has_msa);
2236 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2237 HReg reg = newVRegI(env);
2238 addInstr(env,
2239 MIPSInstr_MsaElm(MSA_COPY_S, v_src, reg, MSA_DFN_D | 0));
2240 return reg;
2243 case Iop_F32toF16x4_DEP: {
2244 vassert(mode64);
2245 vassert(has_msa);
2246 HReg v_arg = iselV128Expr(env, e->Iex.Unop.arg);
2247 HReg v_src = newVRegV(env);
2248 set_guest_MIPS_rounding_mode_MSA(env);
2249 addInstr(env,
2250 MIPSInstr_Msa3RF(MSA_FEXDO, MSA_F_WH,
2251 v_src, v_arg, v_arg));
2252 set_MIPS_rounding_default_MSA(env);
2253 HReg reg = newVRegI(env);
2254 addInstr(env,
2255 MIPSInstr_MsaElm(MSA_COPY_S, v_src, reg, MSA_DFN_D | 0));
2256 return reg;
2260 default:
2261 break;
2264 /* -------- DSP ASE -------- */
2265 /* All Unop cases involving host-side helper calls. */
2266 void* fn = NULL;
2267 switch (e->Iex.Unop.op) {
2268 case Iop_CmpNEZ16x2:
2269 fn = &h_generic_calc_CmpNEZ16x2; break;
2270 case Iop_CmpNEZ8x4:
2271 fn = &h_generic_calc_CmpNEZ8x4; break;
2272 default:
2273 break;
2276 RetLoc rloc = mk_RetLoc_INVALID();
2277 if (ty == Ity_I32) {
2278 rloc = mk_RetLoc_simple(RLPri_Int);
2280 else if (ty == Ity_I64) {
2281 rloc = mode64 ? mk_RetLoc_simple(RLPri_Int) :
2282 mk_RetLoc_simple(RLPri_2Int);
2284 else {
2285 goto irreducible;
2288 if (fn) {
2289 HReg regL = iselWordExpr_R(env, e->Iex.Unop.arg);
2290 HReg res = newVRegI(env);
2291 addInstr(env, mk_iMOVds_RR(hregMIPS_GPR4(env->mode64), regL));
2292 argiregs |= (1 << 4);
2293 addInstr(env, MIPSInstr_CallAlways( MIPScc_AL,
2294 (Addr)fn,
2295 argiregs, rloc));
2296 addInstr(env, mk_iMOVds_RR(res, hregMIPS_GPR2(env->mode64)));
2297 return res;
2300 break;
2303 /* --------- GET --------- */
2304 case Iex_Get: {
2305 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
2306 || ((ty == Ity_I64) && mode64)) {
2307 HReg r_dst = newVRegI(env);
2309 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
2310 GuestStatePointer(mode64));
2311 addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr,
2312 mode64));
2313 return r_dst;
2315 break;
2318 /* --------- ITE --------- */
2319 case Iex_ITE: {
2320 if ((ty == Ity_I8 || ty == Ity_I16 ||
2321 ty == Ity_I32 || ((ty == Ity_I64))) &&
2322 typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
2323 HReg r0 = iselWordExpr_R(env, e->Iex.ITE.iffalse);
2324 HReg r1 = iselWordExpr_R(env, e->Iex.ITE.iftrue);
2325 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
2326 HReg r_dst = newVRegI(env);
2328 * r_dst = r0
2329 * movn r_dst, r1, r_cond
2331 #if (__mips_isa_rev >= 6)
2332 HReg r_temp = newVRegI(env);
2333 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dst, r0, r_cond));
2334 addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, r1, r_cond));
2335 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
2336 MIPSRH_Reg(r_temp)));
2338 #else
2339 addInstr(env, mk_iMOVds_RR(r_dst, r0));
2340 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dst, r1, r_cond));
2341 #endif
2342 return r_dst;
2344 break;
2347 /* --------- LITERAL --------- */
2348 /* 32/16/8-bit literals */
2349 case Iex_Const: {
2350 Long l;
2351 HReg r_dst = newVRegI(env);
2352 IRConst *con = e->Iex.Const.con;
2353 switch (con->tag) {
2354 case Ico_U64:
2355 if (!mode64)
2356 goto irreducible;
2357 l = (Long) con->Ico.U64;
2358 break;
2359 case Ico_U32:
2360 l = (Long) (Int) con->Ico.U32;
2361 break;
2362 case Ico_U16:
2363 l = (Long) (Int) (Short) con->Ico.U16;
2364 break;
2365 case Ico_U8:
2366 l = (Long) (Int) (Char) con->Ico.U8;
2367 break;
2368 case Ico_U1:
2369 l = con->Ico.U1 ? 1 : 0;
2370 break;
2371 default:
2372 vpanic("iselIntExpr_R.const(mips)");
2374 addInstr(env, MIPSInstr_LI(r_dst, (ULong) l));
2375 return r_dst;
2378 /* --------- CCALL --------- */
2379 case Iex_CCall: {
2380 HReg r_dst = newVRegI(env);
2381 vassert(ty == e->Iex.CCall.retty);
2383 /* be very restrictive for now. Only 32/64-bit ints allowed for
2384 args, and 64 and 32 bits for return type. Don't forget to change
2385 the RetLoc if more return types are allowed in future. */
2386 if (e->Iex.CCall.retty != Ity_I64 && e->Iex.CCall.retty != Ity_I32)
2387 goto irreducible;
2389 /* Marshal args, do the call, clear stack. */
2390 UInt addToSp = 0;
2391 RetLoc rloc = mk_RetLoc_INVALID();
2392 doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
2393 e->Iex.CCall.retty, e->Iex.CCall.args );
2395 vassert(is_sane_RetLoc(rloc));
2396 vassert(rloc.pri == RLPri_Int);
2397 vassert(addToSp == 0);
2398 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
2399 return r_dst;
2402 #if (__mips_isa_rev >= 6)
2403 case Iex_Qop: {
2404 HReg dst = newVRegI(env);
2405 HReg src1 = iselWordExpr_R(env, e->Iex.Qop.details->arg1);
2406 HReg src2 = iselWordExpr_R(env, e->Iex.Qop.details->arg2);
2407 HReg src3 = iselWordExpr_R(env, e->Iex.Qop.details->arg3);
2408 HReg src4 = iselWordExpr_R(env, e->Iex.Qop.details->arg4);
2409 switch (e->Iex.Qop.details->op) {
2410 case Iop_Rotx32:
2411 addInstr(env, MIPSInstr_Bitswap(Rotx32, dst, src1, src2, src3, src4));
2412 break;
2413 case Iop_Rotx64:
2414 addInstr(env, MIPSInstr_Bitswap(Rotx64, dst, src1, src2, src3, src4));
2415 break;
2416 default:
2417 break;
2419 return dst;
2421 #endif
2423 default:
2424 break;
2425 } /* end switch(e->tag) */
2427 /* We get here if no pattern matched. */
2428 irreducible:
2429 vex_printf("--------------->\n");
2430 if (e->tag == Iex_RdTmp)
2431 vex_printf("Iex_RdTmp \n");
2432 ppIRExpr(e);
2434 vpanic("iselWordExpr_R(mips): cannot reduce tree");
2437 /* --------------------- RH --------------------- */
2439 /* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
2440 (reg-or-halfword-immediate). It's important to specify whether the
2441 immediate is to be regarded as signed or not. If yes, this will
2442 never return -32768 as an immediate; this guaranteed that all
2443 signed immediates that are return can have their sign inverted if
2444 need be. */
2446 static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e)
2448 MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e);
2449 /* sanity checks ... */
2450 switch (ri->tag) {
2451 case Mrh_Imm:
2452 vassert(ri->Mrh.Imm.syned == syned);
2453 if (syned)
2454 vassert(ri->Mrh.Imm.imm16 != 0x8000);
2455 return ri;
2456 case Mrh_Reg:
2457 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
2458 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2459 return ri;
2460 default:
2461 vpanic("iselIntExpr_RH: unknown mips RH tag");
2465 /* DO NOT CALL THIS DIRECTLY ! */
2466 static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e)
2468 ULong u;
2469 Long l;
2470 IRType ty = typeOfIRExpr(env->type_env, e);
2471 vassert(ty == Ity_I1 || ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
2472 ((ty == Ity_I64) && env->mode64));
2474 /* special case: immediate */
2475 if (e->tag == Iex_Const) {
2476 IRConst *con = e->Iex.Const.con;
2477 /* What value are we aiming to generate? */
2478 switch (con->tag) {
2479 /* Note: Not sign-extending - we carry 'syned' around */
2480 case Ico_U64:
2481 vassert(env->mode64);
2482 u = con->Ico.U64;
2483 break;
2484 case Ico_U32:
2485 u = 0xFFFFFFFF & con->Ico.U32;
2486 break;
2487 case Ico_U16:
2488 u = 0x0000FFFF & con->Ico.U16;
2489 break;
2490 case Ico_U8:
2491 u = 0x000000FF & con->Ico.U8;
2492 break;
2493 case Ico_U1:
2494 u = 0x00000001 & con->Ico.U1;
2495 break;
2496 default:
2497 vpanic("iselIntExpr_RH.Iex_Const(mips)");
2499 l = (Long) u;
2500 /* Now figure out if it's representable. */
2501 if (!syned && u <= 65535) {
2502 return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
2504 if (syned && l >= -32767 && l <= 32767) {
2505 return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
2507 /* no luck; use the Slow Way. */
2509 /* default case: calculate into a register and return that */
2510 return MIPSRH_Reg(iselWordExpr_R(env, e));
2513 /* --------------------- RH5u --------------------- */
2515 /* Compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter
2516 being an immediate in the range 1 .. 31 inclusive. Used for doing
2517 shift amounts. */
2519 static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e)
2521 MIPSRH *ri;
2522 ri = iselWordExpr_RH5u_wrk(env, e);
2523 /* sanity checks ... */
2524 switch (ri->tag) {
2525 case Mrh_Imm:
2526 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31);
2527 vassert(!ri->Mrh.Imm.syned);
2528 return ri;
2529 case Mrh_Reg:
2530 vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32);
2531 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2532 return ri;
2533 default:
2534 vpanic("iselIntExpr_RH5u: unknown mips RH tag");
2538 /* DO NOT CALL THIS DIRECTLY ! */
2539 static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e)
2541 IRType ty = typeOfIRExpr(env->type_env, e);
2542 vassert(ty == Ity_I8);
2544 /* special case: immediate */
2545 if (e->tag == Iex_Const
2546 && e->Iex.Const.con->tag == Ico_U8
2547 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) {
2548 return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
2551 /* default case: calculate into a register and return that */
2552 return MIPSRH_Reg(iselWordExpr_R(env, e));
2555 /* --------------------- RH6u --------------------- */
2557 static MIPSRH *iselWordExpr_RH6u ( ISelEnv * env, IRExpr * e )
2559 MIPSRH *ri;
2560 ri = iselWordExpr_RH6u_wrk(env, e);
2561 /* sanity checks ... */
2562 switch (ri->tag) {
2563 case Mrh_Imm:
2564 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 63);
2565 vassert(!ri->Mrh.Imm.syned);
2566 return ri;
2567 case Mrh_Reg:
2568 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
2569 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2570 return ri;
2571 default:
2572 vpanic("iselIntExpr_RH6u: unknown RI tag");
2576 /* DO NOT CALL THIS DIRECTLY ! */
2577 static MIPSRH *iselWordExpr_RH6u_wrk ( ISelEnv * env, IRExpr * e )
2579 IRType ty = typeOfIRExpr(env->type_env, e);
2580 vassert(ty == Ity_I8);
2582 /* special case: immediate */
2583 if (e->tag == Iex_Const
2584 && e->Iex.Const.con->tag == Ico_U8
2585 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 63)
2587 return MIPSRH_Imm(False /*unsigned */ ,
2588 e->Iex.Const.con->Ico.U8);
2591 /* default case: calculate into a register and return that */
2592 return MIPSRH_Reg(iselWordExpr_R(env, e));
2594 /* --------------------- RH7u --------------------- */
2596 static MIPSRH *iselWordExpr_RH7u ( ISelEnv * env, IRExpr * e )
2598 MIPSRH *ri;
2599 ri = iselWordExpr_RH7u_wrk(env, e);
2600 /* sanity checks ... */
2601 switch (ri->tag) {
2602 case Mrh_Imm:
2603 vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 127);
2604 vassert(!ri->Mrh.Imm.syned);
2605 return ri;
2606 case Mrh_Reg:
2607 vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
2608 vassert(hregIsVirtual(ri->Mrh.Reg.reg));
2609 return ri;
2610 default:
2611 vpanic("iselIntExpr_RH7u: unknown RI tag");
2615 /* DO NOT CALL THIS DIRECTLY ! */
2616 static MIPSRH *iselWordExpr_RH7u_wrk ( ISelEnv * env, IRExpr * e )
2618 IRType ty = typeOfIRExpr(env->type_env, e);
2619 vassert(ty == Ity_I8);
2621 /* special case: immediate */
2622 if (e->tag == Iex_Const
2623 && e->Iex.Const.con->tag == Ico_U8
2624 && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 127)
2626 return MIPSRH_Imm(False /*unsigned */ ,
2627 e->Iex.Const.con->Ico.U8);
2630 /* default case: calculate into a register and return that */
2631 return MIPSRH_Reg(iselWordExpr_R(env, e));
2635 /* --------------------- CONDCODE --------------------- */
2637 /* Generate code to evaluated a bit-typed expression, returning the
2638 condition code which would correspond when the expression would
2639 notionally have returned 1. */
2641 static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e)
2643 MIPSCondCode cc = iselCondCode_wrk(env,e);
2644 vassert(cc != MIPScc_NV);
2645 return cc;
2648 /* DO NOT CALL THIS DIRECTLY ! */
2649 static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
2651 vassert(e);
2652 vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
2653 /* Cmp*32*(x,y) ? */
2654 if (e->tag == Iex_Binop
2655 && (e->Iex.Binop.op == Iop_CmpEQ32
2656 || e->Iex.Binop.op == Iop_CmpNE32
2657 || e->Iex.Binop.op == Iop_CmpNE64
2658 || e->Iex.Binop.op == Iop_CmpLT32S
2659 || e->Iex.Binop.op == Iop_CmpLT32U
2660 || e->Iex.Binop.op == Iop_CmpLT64U
2661 || e->Iex.Binop.op == Iop_CmpLE32S
2662 || e->Iex.Binop.op == Iop_CmpLE64S
2663 || e->Iex.Binop.op == Iop_CmpLT64S
2664 || e->Iex.Binop.op == Iop_CmpEQ64
2665 || e->Iex.Binop.op == Iop_CasCmpEQ32
2666 || e->Iex.Binop.op == Iop_CasCmpEQ64)) {
2668 Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
2669 || e->Iex.Binop.op == Iop_CmpLE32S
2670 || e->Iex.Binop.op == Iop_CmpLT64S
2671 || e->Iex.Binop.op == Iop_CmpLE64S);
2672 Bool size32;
2673 HReg dst = newVRegI(env);
2674 HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
2675 HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
2677 MIPSCondCode cc;
2679 switch (e->Iex.Binop.op) {
2680 case Iop_CmpEQ32:
2681 case Iop_CasCmpEQ32:
2682 cc = MIPScc_EQ;
2683 size32 = True;
2684 break;
2685 case Iop_CmpNE32:
2686 cc = MIPScc_NE;
2687 size32 = True;
2688 break;
2689 case Iop_CmpNE64:
2690 cc = MIPScc_NE;
2691 size32 = False;
2692 break;
2693 case Iop_CmpLT32S:
2694 cc = MIPScc_LT;
2695 size32 = True;
2696 break;
2697 case Iop_CmpLT32U:
2698 cc = MIPScc_LO;
2699 size32 = True;
2700 break;
2701 case Iop_CmpLT64U:
2702 cc = MIPScc_LO;
2703 size32 = False;
2704 break;
2705 case Iop_CmpLE32S:
2706 cc = MIPScc_LE;
2707 size32 = True;
2708 break;
2709 case Iop_CmpLE64S:
2710 cc = MIPScc_LE;
2711 size32 = False;
2712 break;
2713 case Iop_CmpLT64S:
2714 cc = MIPScc_LT;
2715 size32 = False;
2716 break;
2717 case Iop_CmpEQ64:
2718 case Iop_CasCmpEQ64:
2719 cc = MIPScc_EQ;
2720 size32 = False;
2721 break;
2722 default:
2723 vpanic("iselCondCode(mips): CmpXX32 or CmpXX64");
2724 break;
2727 addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
2728 /* Store result to guest_COND */
2729 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2731 addInstr(env, MIPSInstr_Store(4,
2732 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2733 am_addr->Mam.IR.base),
2734 dst, mode64));
2735 return cc;
2737 if (e->tag == Iex_Unop && e->Iex.Binop.op == Iop_Not1) {
2738 HReg r_dst = newVRegI(env);
2739 HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
2740 MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
2742 addInstr(env, MIPSInstr_LI(r_dst, 0x1));
2743 addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
2744 /* Store result to guest_COND */
2745 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2747 addInstr(env, MIPSInstr_Store(4,
2748 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2749 am_addr->Mam.IR.base),
2750 r_dst, mode64));
2751 return MIPScc_NE;
2754 if (e->tag == Iex_Unop
2755 && (e->Iex.Unop.op == Iop_CmpNEZ32
2756 || ((e->Iex.Unop.op == Iop_CmpNEZ64) && mode64))) {
2757 HReg r_dst = newVRegI(env);
2758 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
2760 addInstr(env, MIPSInstr_Cmp(False, !mode64, r_dst, r_src,
2761 hregMIPS_GPR0(mode64), MIPScc_NE));
2762 /* Store result to guest_COND */
2763 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2765 addInstr(env, MIPSInstr_Store(4,
2766 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2767 am_addr->Mam.IR.base),
2768 r_dst, mode64));
2769 return MIPScc_NE;
2772 if (e->tag == Iex_Binop
2773 && (e->Iex.Binop.op == Iop_And1 || e->Iex.Binop.op == Iop_Or1)) {
2774 HReg r_argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
2775 HReg r_argR = iselWordExpr_R(env, e->Iex.Binop.arg2);
2776 HReg r_dst = newVRegI(env);
2777 addInstr(env, MIPSInstr_Alu(e->Iex.Binop.op == Iop_And1 ? Malu_AND : Malu_OR,
2778 r_dst, r_argL, MIPSRH_Reg(r_argR)));
2779 addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_dst, MIPSRH_Imm(False, 1)));
2780 /* Store result to guest_COND */
2781 /* sewardj 2019Dec13: this seems wrong to me. The host-side instruction
2782 selector shouldn't touch the guest-side state, except in response to
2783 Iex_Get and Ist_Put. */
2784 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2786 addInstr(env, MIPSInstr_Store(4,
2787 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2788 am_addr->Mam.IR.base),
2789 r_dst, mode64));
2790 return MIPScc_EQ;
2793 if (e->tag == Iex_RdTmp) {
2794 HReg r_dst = iselWordExpr_R_wrk(env, e);
2795 /* Store result to guest_COND */
2796 MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
2798 addInstr(env, MIPSInstr_Store(4,
2799 MIPSAMode_IR(am_addr->Mam.IR.index + COND_OFFSET(mode64),
2800 am_addr->Mam.IR.base),
2801 r_dst, mode64));
2802 return MIPScc_EQ;
2805 vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag);
2806 ppIRExpr(e);
2807 vpanic("iselCondCode(mips)");
2810 /*---------------------------------------------------------*/
2811 /*--- ISEL: Vector expressions (128 bit - SIMD) ---*/
2812 /*---------------------------------------------------------*/
2814 /* Compute a vector value into vector register. */
2815 static HReg iselV128Expr (ISelEnv* env, IRExpr* e) {
2816 vassert(has_msa);
2817 HReg r = iselV128Expr_wrk(env, e);
2818 vassert(hregClass(r) == HRcVec128);
2819 vassert(hregIsVirtual(r));
2820 return r;
2823 /* DO NOT CALL THIS DIRECTLY ! */
2824 static HReg iselV128Expr_wrk(ISelEnv* env, IRExpr* e) {
2825 IRType ty = typeOfIRExpr(env->type_env, e);
2826 vassert(e);
2827 vassert(ty == Ity_V128);
2829 if (e->tag == Iex_RdTmp) {
2830 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
2833 if (e->tag == Iex_Load) {
2834 vassert (e->Iex.Load.ty == Ity_V128);
2835 HReg v_dst = newVRegV(env);
2836 addInstr(env, MIPSInstr_MsaMi10(MSA_LD, 0, iselWordExpr_R(env,
2837 e->Iex.Load.addr), v_dst, MSA_B));
2838 return v_dst;
2841 if (e->tag == Iex_Get) {
2842 HReg v_dst = newVRegV(env);
2843 #if defined(_MIPSEB)
2844 HReg r_addr = newVRegI(env);
2845 vassert(!(e->Iex.Get.offset & ~0x7FFF));
2846 addInstr(env, MIPSInstr_Alu(mode64 ? Malu_DADD : Malu_ADD, r_addr, GuestStatePointer(mode64),
2847 MIPSRH_Imm(True, e->Iex.Get.offset)));
2848 addInstr(env, MIPSInstr_MsaMi10(MSA_LD, 0, r_addr, v_dst, MSA_B));
2849 #else
2850 vassert(!(e->Iex.Get.offset & 7));
2851 addInstr(env, MIPSInstr_MsaMi10(MSA_LD, e->Iex.Get.offset >> 3,
2852 GuestStatePointer(mode64), v_dst, MSA_D));
2853 #endif
2854 return v_dst;
2857 if (e->tag == Iex_Unop) {
2858 IROp op_unop = e->Iex.Unop.op;
2860 switch (op_unop) {
2861 case Iop_Abs64x2: {
2862 HReg v_dst = newVRegV(env);
2863 HReg v_help = newVRegV(env);
2864 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2865 addInstr(env,
2866 MIPSInstr_Msa3R(MSA_SUBV, MSA_D, v_help, v_src, v_src));
2867 addInstr(env,
2868 MIPSInstr_Msa3R(MSA_ADD_A, MSA_D,
2869 v_dst, v_src, v_help));
2870 return v_dst;
2873 case Iop_Abs32x4: {
2874 HReg v_dst = newVRegV(env);
2875 HReg v_help = newVRegV(env);
2876 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2877 addInstr(env,
2878 MIPSInstr_Msa3R(MSA_SUBV, MSA_W, v_help, v_src, v_src));
2879 addInstr(env,
2880 MIPSInstr_Msa3R(MSA_ADD_A, MSA_W,
2881 v_dst, v_src, v_help));
2882 return v_dst;
2885 case Iop_Abs16x8: {
2886 HReg v_dst = newVRegV(env);
2887 HReg v_help = newVRegV(env);
2888 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2889 addInstr(env,
2890 MIPSInstr_Msa3R(MSA_SUBV, MSA_H, v_help, v_src, v_src));
2891 addInstr(env,
2892 MIPSInstr_Msa3R(MSA_ADD_A, MSA_H,
2893 v_dst, v_src, v_help));
2894 return v_dst;
2897 case Iop_Abs8x16: {
2898 HReg v_dst = newVRegV(env);
2899 HReg v_help = newVRegV(env);
2900 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2901 addInstr(env,
2902 MIPSInstr_Msa3R(MSA_SUBV, MSA_B, v_help, v_src, v_src));
2903 addInstr(env,
2904 MIPSInstr_Msa3R(MSA_ADD_A, MSA_B,
2905 v_dst, v_src, v_help));
2906 return v_dst;
2909 case Iop_Cnt8x16: {
2910 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2911 HReg res = newVRegV(env);
2912 addInstr(env, MIPSInstr_Msa2R(MSA_PCNT, MSA_B, v_src, res));
2913 return res;
2916 case Iop_NotV128: {
2917 HReg v_dst = newVRegV(env);
2918 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2919 addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_src, v_src));
2920 return v_dst;
2923 case Iop_Reverse8sIn16_x8: {
2924 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2925 HReg v_tmp = newVRegV(env);
2926 addInstr(env,
2927 MIPSInstr_Msa3R(MSA_ILVEV, MSA_B, v_tmp, v_src, v_src));
2928 addInstr(env,
2929 MIPSInstr_Msa3R(MSA_ILVOD, MSA_B, v_src, v_tmp, v_src));
2930 return v_src;
2933 case Iop_Reverse8sIn32_x4: {
2934 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2935 HReg v_tmp = newVRegV(env);
2936 addInstr(env,
2937 MIPSInstr_Msa3R(MSA_ILVEV, MSA_H, v_tmp, v_src, v_src));
2938 addInstr(env,
2939 MIPSInstr_Msa3R(MSA_ILVOD, MSA_H, v_src, v_tmp, v_src));
2940 addInstr(env,
2941 MIPSInstr_Msa3R(MSA_ILVEV, MSA_B, v_tmp, v_src, v_src));
2942 addInstr(env,
2943 MIPSInstr_Msa3R(MSA_ILVOD, MSA_B, v_src, v_tmp, v_src));
2944 return v_src;
2947 case Iop_Reverse8sIn64_x2: {
2948 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2949 HReg v_tmp = newVRegV(env);
2950 addInstr(env,
2951 MIPSInstr_Msa3R(MSA_ILVEV, MSA_W, v_tmp, v_src, v_src));
2952 addInstr(env,
2953 MIPSInstr_Msa3R(MSA_ILVOD, MSA_W, v_src, v_tmp, v_src));
2954 addInstr(env,
2955 MIPSInstr_Msa3R(MSA_ILVEV, MSA_H, v_tmp, v_src, v_src));
2956 addInstr(env,
2957 MIPSInstr_Msa3R(MSA_ILVOD, MSA_H, v_src, v_tmp, v_src));
2958 addInstr(env,
2959 MIPSInstr_Msa3R(MSA_ILVEV, MSA_B, v_tmp, v_src, v_src));
2960 addInstr(env,
2961 MIPSInstr_Msa3R(MSA_ILVOD, MSA_B, v_src, v_tmp, v_src));
2962 return v_src;
2965 case Iop_Cls8x16: {
2966 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2967 HReg v_dst = newVRegV(env);
2968 addInstr(env, MIPSInstr_Msa2R(MSA_NLOC, MSA_B, v_src, v_dst));
2969 return v_dst;
2972 case Iop_Cls16x8: {
2973 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2974 HReg v_dst = newVRegV(env);
2975 addInstr(env, MIPSInstr_Msa2R(MSA_NLOC, MSA_H, v_src, v_dst));
2976 return v_dst;
2979 case Iop_Cls32x4: {
2980 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2981 HReg v_dst = newVRegV(env);
2982 addInstr(env, MIPSInstr_Msa2R(MSA_NLOC, MSA_W, v_src, v_dst));
2983 return v_dst;
2986 case Iop_Clz8x16: {
2987 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2988 HReg v_dst = newVRegV(env);
2989 addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_B, v_src, v_dst));
2990 return v_dst;
2993 case Iop_Clz16x8: {
2994 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
2995 HReg v_dst = newVRegV(env);
2996 addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_H, v_src, v_dst));
2997 return v_dst;
3000 case Iop_Clz32x4: {
3001 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3002 HReg v_dst = newVRegV(env);
3003 addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_W, v_src, v_dst));
3004 return v_dst;
3007 case Iop_Clz64x2: {
3008 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3009 HReg v_dst = newVRegV(env);
3010 addInstr(env, MIPSInstr_Msa2R(MSA_NLZC, MSA_D, v_src, v_dst));
3011 return v_dst;
3014 case Iop_Abs32Fx4: {
3015 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3016 HReg v_dst = newVRegV(env);
3017 HReg v_help = newVRegV(env);
3018 addInstr(env,
3019 MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_WH,
3020 v_help, v_src, v_src));
3021 addInstr(env,
3022 MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_WH, v_dst, v_help));
3023 return v_dst;
3026 case Iop_Abs64Fx2: {
3027 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3028 HReg v_dst = newVRegV(env);
3029 HReg v_help = newVRegV(env);
3030 addInstr(env,
3031 MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_DW,
3032 v_help, v_src, v_src));
3033 addInstr(env,
3034 MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_DW, v_dst, v_help));
3035 return v_dst;
3038 case Iop_RecipEst32Fx4: {
3039 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3040 HReg v_dst = newVRegV(env);
3041 set_guest_MIPS_rounding_mode_MSA(env);
3042 addInstr(env,
3043 MIPSInstr_Msa2RF(MSA_FRCP, MSA_F_WH, v_dst, v_src));
3044 set_MIPS_rounding_default_MSA(env);
3045 return v_dst;
3048 case Iop_RecipEst64Fx2: {
3049 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3050 HReg v_dst = newVRegV(env);
3051 set_guest_MIPS_rounding_mode_MSA(env);
3052 addInstr(env,
3053 MIPSInstr_Msa2RF(MSA_FRCP, MSA_F_DW, v_dst, v_src));
3054 set_MIPS_rounding_default_MSA(env);
3055 return v_dst;
3058 case Iop_RSqrtEst32Fx4: {
3059 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3060 HReg v_dst = newVRegV(env);
3061 set_guest_MIPS_rounding_mode_MSA(env);
3062 addInstr(env,
3063 MIPSInstr_Msa2RF(MSA_FRSQRT, MSA_F_WH, v_dst, v_src));
3064 set_MIPS_rounding_default_MSA(env);
3065 return v_dst;
3068 case Iop_RSqrtEst64Fx2: {
3069 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3070 HReg v_dst = newVRegV(env);
3071 set_guest_MIPS_rounding_mode_MSA(env);
3072 addInstr(env,
3073 MIPSInstr_Msa2RF(MSA_FRSQRT, MSA_F_DW, v_dst, v_src));
3074 set_MIPS_rounding_default_MSA(env);
3075 return v_dst;
3078 case Iop_F16toF32x4: {
3079 HReg v_dst = newVRegV(env);
3081 if (mode64) {
3082 HReg r_src;
3083 r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
3084 addInstr(env,
3085 MIPSInstr_Msa2R(MSA_FILL, MSA_D, r_src, v_dst));
3086 addInstr(env,
3087 MIPSInstr_MsaElm(MSA_INSERT, r_src, v_dst,
3088 MSA_DFN_D | 1));
3089 } else {
3090 HReg r_srch, r_srcl;
3091 iselInt64Expr(&r_srch, &r_srcl, env, e->Iex.Unop.arg);
3092 addInstr(env,
3093 MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_srcl, v_dst));
3094 addInstr(env,
3095 MIPSInstr_MsaElm(MSA_INSERT, r_srch, v_dst,
3096 MSA_DFN_W | 1));
3097 addInstr(env,
3098 MIPSInstr_MsaElm(MSA_INSERT, r_srcl, v_dst,
3099 MSA_DFN_W | 2));
3100 addInstr(env,
3101 MIPSInstr_MsaElm(MSA_INSERT, r_srch, v_dst,
3102 MSA_DFN_W | 3));
3105 addInstr(env,
3106 MIPSInstr_Msa2RF(MSA_FEXUPR, MSA_F_WH, v_dst, v_dst));
3107 return v_dst;
3110 case Iop_I32UtoF32x4_DEP: {
3111 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3112 HReg v_dst = newVRegV(env);
3113 set_guest_MIPS_rounding_mode_MSA(env);
3114 addInstr(env,
3115 MIPSInstr_Msa2RF(MSA_FFINT_U, MSA_F_WH, v_dst, v_src));
3116 set_MIPS_rounding_default_MSA(env);
3117 return v_dst;
3120 case Iop_F32toI32Sx4_RZ: {
3121 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3122 HReg v_dst = newVRegV(env);
3123 addInstr(env,
3124 MIPSInstr_Msa2RF(MSA_FTRUNC_S, MSA_F_WH, v_dst, v_src));
3125 return v_dst;
3128 case Iop_F32toI32Ux4_RZ: {
3129 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3130 HReg v_dst = newVRegV(env);
3131 addInstr(env,
3132 MIPSInstr_Msa2RF(MSA_FTRUNC_U, MSA_F_WH, v_dst, v_src));
3133 return v_dst;
3136 case Iop_Log2_32Fx4: {
3137 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3138 HReg v_dst = newVRegV(env);
3139 addInstr(env,
3140 MIPSInstr_Msa2RF(MSA_FLOG2, MSA_F_WH, v_dst, v_src));
3141 return v_dst;
3144 case Iop_Log2_64Fx2: {
3145 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3146 HReg v_dst = newVRegV(env);
3147 addInstr(env,
3148 MIPSInstr_Msa2RF(MSA_FLOG2, MSA_F_DW, v_dst, v_src));
3149 return v_dst;
3151 case Iop_CmpNEZ8x16: {
3152 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3153 HReg v_dst = newVRegV(env);
3154 HReg zero = Zero(mode64);
3155 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
3156 addInstr(env,
3157 MIPSInstr_Msa3R(MSA_CEQ, MSA_B, v_dst, v_src, v_dst));
3158 addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
3159 return v_dst;
3161 case Iop_CmpNEZ16x8: {
3162 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3163 HReg v_dst = newVRegV(env);
3164 HReg zero = Zero(mode64);
3165 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
3166 addInstr(env,
3167 MIPSInstr_Msa3R(MSA_CEQ, MSA_H, v_dst, v_src, v_dst));
3168 addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
3169 return v_dst;
3171 case Iop_CmpNEZ32x4: {
3172 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3173 HReg v_dst = newVRegV(env);
3174 HReg zero = Zero(mode64);
3175 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
3176 addInstr(env,
3177 MIPSInstr_Msa3R(MSA_CEQ, MSA_W, v_dst, v_src, v_dst));
3178 addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
3179 return v_dst;
3181 case Iop_CmpNEZ64x2: {
3182 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
3183 HReg v_dst = newVRegV(env);
3184 HReg zero = Zero(mode64);
3185 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
3186 addInstr(env,
3187 MIPSInstr_Msa3R(MSA_CEQ, MSA_D, v_dst, v_src, v_dst));
3188 addInstr(env, MIPSInstr_MsaVec(MSA_NORV, v_dst, v_dst, v_dst));
3189 return v_dst;
3191 default:
3192 vex_printf("iselV128Expr_wrk: Unsupported unop: %u\n", op_unop);
3196 if (e->tag == Iex_Binop) {
3197 IROp op_binop = e->Iex.Binop.op;
3199 switch (op_binop) {
3200 case Iop_Add8x16: {
3201 HReg v_dst = newVRegV(env);
3202 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3203 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3204 addInstr(env,
3205 MIPSInstr_Msa3R(MSA_ADDV, MSA_B,
3206 v_dst, v_src1, v_src2));
3207 return v_dst;
3210 case Iop_Add16x8: {
3211 HReg v_dst = newVRegV(env);
3212 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3213 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3214 addInstr(env,
3215 MIPSInstr_Msa3R(MSA_ADDV, MSA_H,
3216 v_dst, v_src1, v_src2));
3217 return v_dst;
3220 case Iop_Add32x4: {
3221 HReg v_dst = newVRegV(env);
3222 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3223 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3224 addInstr(env,
3225 MIPSInstr_Msa3R(MSA_ADDV, MSA_W,
3226 v_dst, v_src1, v_src2));
3227 return v_dst;
3230 case Iop_Add64x2: {
3231 HReg v_dst = newVRegV(env);
3232 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3233 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3234 addInstr(env,
3235 MIPSInstr_Msa3R(MSA_ADDV, MSA_D,
3236 v_dst, v_src1, v_src2));
3237 return v_dst;
3240 case Iop_Sub8x16: {
3241 HReg v_dst = newVRegV(env);
3242 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3243 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3244 addInstr(env,
3245 MIPSInstr_Msa3R(MSA_SUBV, MSA_B,
3246 v_dst, v_src1, v_src2));
3247 return v_dst;
3250 case Iop_Sub16x8: {
3251 HReg v_dst = newVRegV(env);
3252 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3253 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3254 addInstr(env,
3255 MIPSInstr_Msa3R(MSA_SUBV, MSA_H,
3256 v_dst, v_src1, v_src2));
3257 return v_dst;
3260 case Iop_Sub32x4: {
3261 HReg v_dst = newVRegV(env);
3262 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3263 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3264 addInstr(env,
3265 MIPSInstr_Msa3R(MSA_SUBV, MSA_W,
3266 v_dst, v_src1, v_src2));
3267 return v_dst;
3270 case Iop_Sub64x2: {
3271 HReg v_dst = newVRegV(env);
3272 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3273 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3274 addInstr(env,
3275 MIPSInstr_Msa3R(MSA_SUBV, MSA_D,
3276 v_dst, v_src1, v_src2));
3277 return v_dst;
3280 case Iop_QAdd8Sx16: {
3281 HReg v_dst = newVRegV(env);
3282 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3283 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3284 addInstr(env,
3285 MIPSInstr_Msa3R(MSA_ADDS_S, MSA_B,
3286 v_dst, v_src1, v_src2));
3287 return v_dst;
3290 case Iop_QAdd16Sx8: {
3291 HReg v_dst = newVRegV(env);
3292 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3293 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3294 addInstr(env,
3295 MIPSInstr_Msa3R(MSA_ADDS_S, MSA_H,
3296 v_dst, v_src1, v_src2));
3297 return v_dst;
3300 case Iop_QAdd32Sx4: {
3301 HReg v_dst = newVRegV(env);
3302 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3303 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3304 addInstr(env,
3305 MIPSInstr_Msa3R(MSA_ADDS_S, MSA_W,
3306 v_dst, v_src1, v_src2));
3307 return v_dst;
3310 case Iop_QAdd64Sx2: {
3311 HReg v_dst = newVRegV(env);
3312 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3313 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3314 addInstr(env,
3315 MIPSInstr_Msa3R(MSA_ADDS_S, MSA_D,
3316 v_dst, v_src1, v_src2));
3317 return v_dst;
3320 case Iop_QAdd8Ux16: {
3321 HReg v_dst = newVRegV(env);
3322 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3323 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3324 addInstr(env,
3325 MIPSInstr_Msa3R(MSA_ADDS_U, MSA_B,
3326 v_dst, v_src1, v_src2));
3327 return v_dst;
3330 case Iop_QAdd16Ux8: {
3331 HReg v_dst = newVRegV(env);
3332 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3333 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3334 addInstr(env,
3335 MIPSInstr_Msa3R(MSA_ADDS_U, MSA_H,
3336 v_dst, v_src1, v_src2));
3337 return v_dst;
3340 case Iop_QAdd32Ux4: {
3341 HReg v_dst = newVRegV(env);
3342 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3343 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3344 addInstr(env,
3345 MIPSInstr_Msa3R(MSA_ADDS_U, MSA_W,
3346 v_dst, v_src1, v_src2));
3347 return v_dst;
3350 case Iop_QAdd64Ux2: {
3351 HReg v_dst = newVRegV(env);
3352 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3353 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3354 addInstr(env,
3355 MIPSInstr_Msa3R(MSA_ADDS_U, MSA_D,
3356 v_dst, v_src1, v_src2));
3357 return v_dst;
3360 case Iop_QSub8Sx16: {
3361 HReg v_dst = newVRegV(env);
3362 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3363 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3364 addInstr(env,
3365 MIPSInstr_Msa3R(MSA_SUBS_S, MSA_B,
3366 v_dst, v_src1, v_src2));
3367 return v_dst;
3370 case Iop_QSub16Sx8: {
3371 HReg v_dst = newVRegV(env);
3372 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3373 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3374 addInstr(env,
3375 MIPSInstr_Msa3R(MSA_SUBS_S, MSA_H,
3376 v_dst, v_src1, v_src2));
3377 return v_dst;
3380 case Iop_QSub32Sx4: {
3381 HReg v_dst = newVRegV(env);
3382 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3383 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3384 addInstr(env,
3385 MIPSInstr_Msa3R(MSA_SUBS_S, MSA_W,
3386 v_dst, v_src1, v_src2));
3387 return v_dst;
3390 case Iop_QSub64Sx2: {
3391 HReg v_dst = newVRegV(env);
3392 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3393 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3394 addInstr(env,
3395 MIPSInstr_Msa3R(MSA_SUBS_S, MSA_D,
3396 v_dst, v_src1, v_src2));
3397 return v_dst;
3400 case Iop_QSub8Ux16: {
3401 HReg v_dst = newVRegV(env);
3402 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3403 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3404 addInstr(env,
3405 MIPSInstr_Msa3R(MSA_SUBS_U, MSA_B,
3406 v_dst, v_src1, v_src2));
3407 return v_dst;
3410 case Iop_QSub16Ux8: {
3411 HReg v_dst = newVRegV(env);
3412 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3413 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3414 addInstr(env,
3415 MIPSInstr_Msa3R(MSA_SUBS_U, MSA_H,
3416 v_dst, v_src1, v_src2));
3417 return v_dst;
3420 case Iop_QSub32Ux4: {
3421 HReg v_dst = newVRegV(env);
3422 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3423 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3424 addInstr(env,
3425 MIPSInstr_Msa3R(MSA_SUBS_U, MSA_W,
3426 v_dst, v_src1, v_src2));
3427 return v_dst;
3430 case Iop_QSub64Ux2: {
3431 HReg v_dst = newVRegV(env);
3432 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3433 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3434 addInstr(env,
3435 MIPSInstr_Msa3R(MSA_SUBS_U, MSA_D,
3436 v_dst, v_src1, v_src2));
3437 return v_dst;
3440 case Iop_QDMulHi32Sx4: {
3441 HReg v_dst = newVRegV(env);
3442 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3443 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3444 addInstr(env,
3445 MIPSInstr_Msa3RF(MSA_MUL_Q, MSA_F_DW,
3446 v_dst, v_src1, v_src2));
3447 return v_dst;
3450 case Iop_QDMulHi16Sx8: {
3451 HReg v_dst = newVRegV(env);
3452 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3453 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3454 addInstr(env,
3455 MIPSInstr_Msa3RF(MSA_MUL_Q, MSA_F_WH,
3456 v_dst, v_src1, v_src2));
3457 return v_dst;
3460 case Iop_QRDMulHi32Sx4: {
3461 HReg v_dst = newVRegV(env);
3462 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3463 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3464 addInstr(env,
3465 MIPSInstr_Msa3RF(MSA_MULR_Q, MSA_F_DW,
3466 v_dst, v_src1, v_src2));
3467 return v_dst;
3470 case Iop_QRDMulHi16Sx8: {
3471 HReg v_dst = newVRegV(env);
3472 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3473 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3474 addInstr(env,
3475 MIPSInstr_Msa3RF(MSA_MULR_Q, MSA_F_WH,
3476 v_dst, v_src1, v_src2));
3477 return v_dst;
3480 case Iop_Max8Sx16: {
3481 HReg v_dst = newVRegV(env);
3482 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3483 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3484 addInstr(env,
3485 MIPSInstr_Msa3R(MSA_MAX_S, MSA_B,
3486 v_dst, v_src1, v_src2));
3487 return v_dst;
3490 case Iop_Max16Sx8: {
3491 HReg v_dst = newVRegV(env);
3492 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3493 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3494 addInstr(env,
3495 MIPSInstr_Msa3R(MSA_MAX_S, MSA_H,
3496 v_dst, v_src1, v_src2));
3497 return v_dst;
3500 case Iop_Max32Sx4: {
3501 HReg v_dst = newVRegV(env);
3502 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3503 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3504 addInstr(env,
3505 MIPSInstr_Msa3R(MSA_MAX_S, MSA_W,
3506 v_dst, v_src1, v_src2));
3507 return v_dst;
3510 case Iop_Max64Sx2: {
3511 HReg v_dst = newVRegV(env);
3512 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3513 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3514 addInstr(env,
3515 MIPSInstr_Msa3R(MSA_MAX_S, MSA_D,
3516 v_dst, v_src1, v_src2));
3517 return v_dst;
3520 case Iop_Max8Ux16: {
3521 HReg v_dst = newVRegV(env);
3522 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3523 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3524 addInstr(env,
3525 MIPSInstr_Msa3R(MSA_MAX_U, MSA_B,
3526 v_dst, v_src1, v_src2));
3527 return v_dst;
3530 case Iop_Max16Ux8: {
3531 HReg v_dst = newVRegV(env);
3532 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3533 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3534 addInstr(env,
3535 MIPSInstr_Msa3R(MSA_MAX_U, MSA_H,
3536 v_dst, v_src1, v_src2));
3537 return v_dst;
3540 case Iop_Max32Ux4: {
3541 HReg v_dst = newVRegV(env);
3542 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3543 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3544 addInstr(env,
3545 MIPSInstr_Msa3R(MSA_MAX_U, MSA_W,
3546 v_dst, v_src1, v_src2));
3547 return v_dst;
3550 case Iop_Max64Ux2: {
3551 HReg v_dst = newVRegV(env);
3552 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3553 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3554 addInstr(env,
3555 MIPSInstr_Msa3R(MSA_MAX_U, MSA_D,
3556 v_dst, v_src1, v_src2));
3557 return v_dst;
3560 case Iop_Min8Sx16: {
3561 HReg v_dst = newVRegV(env);
3562 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3563 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3564 addInstr(env,
3565 MIPSInstr_Msa3R(MSA_MIN_S, MSA_B,
3566 v_dst, v_src1, v_src2));
3567 return v_dst;
3570 case Iop_Min16Sx8: {
3571 HReg v_dst = newVRegV(env);
3572 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3573 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3574 addInstr(env,
3575 MIPSInstr_Msa3R(MSA_MIN_S, MSA_H,
3576 v_dst, v_src1, v_src2));
3577 return v_dst;
3580 case Iop_Min32Sx4: {
3581 HReg v_dst = newVRegV(env);
3582 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3583 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3584 addInstr(env,
3585 MIPSInstr_Msa3R(MSA_MIN_S, MSA_W,
3586 v_dst, v_src1, v_src2));
3587 return v_dst;
3590 case Iop_Min64Sx2: {
3591 HReg v_dst = newVRegV(env);
3592 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3593 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3594 addInstr(env,
3595 MIPSInstr_Msa3R(MSA_MIN_S, MSA_D,
3596 v_dst, v_src1, v_src2));
3597 return v_dst;
3600 case Iop_Min8Ux16: {
3601 HReg v_dst = newVRegV(env);
3602 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3603 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3604 addInstr(env,
3605 MIPSInstr_Msa3R(MSA_MIN_U, MSA_B,
3606 v_dst, v_src1, v_src2));
3607 return v_dst;
3610 case Iop_Min16Ux8: {
3611 HReg v_dst = newVRegV(env);
3612 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3613 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3614 addInstr(env,
3615 MIPSInstr_Msa3R(MSA_MIN_U, MSA_H,
3616 v_dst, v_src1, v_src2));
3617 return v_dst;
3620 case Iop_Min32Ux4: {
3621 HReg v_dst = newVRegV(env);
3622 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3623 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3624 addInstr(env,
3625 MIPSInstr_Msa3R(MSA_MIN_U, MSA_W,
3626 v_dst, v_src1, v_src2));
3627 return v_dst;
3630 case Iop_Min64Ux2: {
3631 HReg v_dst = newVRegV(env);
3632 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3633 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3634 addInstr(env,
3635 MIPSInstr_Msa3R(MSA_MIN_U, MSA_D,
3636 v_dst, v_src1, v_src2));
3637 return v_dst;
3640 case Iop_Shl8x16: {
3641 HReg v_dst = newVRegV(env);
3642 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3643 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3644 addInstr(env,
3645 MIPSInstr_Msa3R(MSA_SLL, MSA_B, v_dst, v_src1, v_src2));
3646 return v_dst;
3649 case Iop_Shl16x8: {
3650 HReg v_dst = newVRegV(env);
3651 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3652 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3653 addInstr(env,
3654 MIPSInstr_Msa3R(MSA_SLL, MSA_H, v_dst, v_src1, v_src2));
3655 return v_dst;
3658 case Iop_Shl32x4: {
3659 HReg v_dst = newVRegV(env);
3660 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3661 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3662 addInstr(env,
3663 MIPSInstr_Msa3R(MSA_SLL, MSA_W, v_dst, v_src1, v_src2));
3664 return v_dst;
3667 case Iop_Shl64x2: {
3668 HReg v_dst = newVRegV(env);
3669 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3670 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3671 addInstr(env,
3672 MIPSInstr_Msa3R(MSA_SLL, MSA_D, v_dst, v_src1, v_src2));
3673 return v_dst;
3676 case Iop_Shr8x16: {
3677 HReg v_dst = newVRegV(env);
3678 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3679 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3680 addInstr(env,
3681 MIPSInstr_Msa3R(MSA_SRL, MSA_B, v_dst, v_src1, v_src2));
3682 return v_dst;
3685 case Iop_Shr16x8: {
3686 HReg v_dst = newVRegV(env);
3687 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3688 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3689 addInstr(env,
3690 MIPSInstr_Msa3R(MSA_SRL, MSA_H, v_dst, v_src1, v_src2));
3691 return v_dst;
3694 case Iop_Shr32x4: {
3695 HReg v_dst = newVRegV(env);
3696 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3697 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3698 addInstr(env,
3699 MIPSInstr_Msa3R(MSA_SRL, MSA_W, v_dst, v_src1, v_src2));
3700 return v_dst;
3703 case Iop_Shr64x2: {
3704 HReg v_dst = newVRegV(env);
3705 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3706 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3707 addInstr(env,
3708 MIPSInstr_Msa3R(MSA_SRL, MSA_D, v_dst, v_src1, v_src2));
3709 return v_dst;
3712 case Iop_Sar8x16: {
3713 HReg v_dst = newVRegV(env);
3714 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3715 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3716 addInstr(env,
3717 MIPSInstr_Msa3R(MSA_SRA, MSA_B, v_dst, v_src1, v_src2));
3718 return v_dst;
3721 case Iop_Sar16x8: {
3722 HReg v_dst = newVRegV(env);
3723 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3724 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3725 addInstr(env,
3726 MIPSInstr_Msa3R(MSA_SRA, MSA_H, v_dst, v_src1, v_src2));
3727 return v_dst;
3730 case Iop_Sar32x4: {
3731 HReg v_dst = newVRegV(env);
3732 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3733 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3734 addInstr(env,
3735 MIPSInstr_Msa3R(MSA_SRA, MSA_W, v_dst, v_src1, v_src2));
3736 return v_dst;
3739 case Iop_Sar64x2: {
3740 HReg v_dst = newVRegV(env);
3741 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3742 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3743 addInstr(env,
3744 MIPSInstr_Msa3R(MSA_SRA, MSA_D, v_dst, v_src1, v_src2));
3745 return v_dst;
3748 case Iop_InterleaveHI8x16: {
3749 HReg v_dst = newVRegV(env);
3750 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3751 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3752 addInstr(env,
3753 MIPSInstr_Msa3R(MSA_ILVL, MSA_B, v_dst, v_src1, v_src2));
3754 return v_dst;
3757 case Iop_InterleaveHI16x8: {
3758 HReg v_dst = newVRegV(env);
3759 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3760 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3761 addInstr(env,
3762 MIPSInstr_Msa3R(MSA_ILVL, MSA_H,
3763 v_dst, v_src1, v_src2));
3764 return v_dst;
3767 case Iop_InterleaveHI32x4: {
3768 HReg v_dst = newVRegV(env);
3769 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3770 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3771 addInstr(env,
3772 MIPSInstr_Msa3R(MSA_ILVL, MSA_W,
3773 v_dst, v_src1, v_src2));
3774 return v_dst;
3777 case Iop_InterleaveHI64x2: {
3778 HReg v_dst = newVRegV(env);
3779 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3780 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3781 addInstr(env,
3782 MIPSInstr_Msa3R(MSA_ILVL, MSA_D,
3783 v_dst, v_src1, v_src2));
3784 return v_dst;
3787 case Iop_InterleaveLO8x16: {
3788 HReg v_dst = newVRegV(env);
3789 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3790 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3791 addInstr(env,
3792 MIPSInstr_Msa3R(MSA_ILVR, MSA_B,
3793 v_dst, v_src1, v_src2));
3794 return v_dst;
3797 case Iop_InterleaveLO16x8: {
3798 HReg v_dst = newVRegV(env);
3799 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3800 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3801 addInstr(env,
3802 MIPSInstr_Msa3R(MSA_ILVR, MSA_H,
3803 v_dst, v_src1, v_src2));
3804 return v_dst;
3807 case Iop_InterleaveLO32x4: {
3808 HReg v_dst = newVRegV(env);
3809 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3810 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3811 addInstr(env,
3812 MIPSInstr_Msa3R(MSA_ILVR, MSA_W,
3813 v_dst, v_src1, v_src2));
3814 return v_dst;
3817 case Iop_InterleaveLO64x2: {
3818 HReg v_dst = newVRegV(env);
3819 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3820 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3821 addInstr(env,
3822 MIPSInstr_Msa3R(MSA_ILVR, MSA_D,
3823 v_dst, v_src1, v_src2));
3824 return v_dst;
3827 case Iop_InterleaveEvenLanes8x16: {
3828 HReg v_dst = newVRegV(env);
3829 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3830 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3831 addInstr(env,
3832 MIPSInstr_Msa3R(MSA_ILVEV, MSA_B,
3833 v_dst, v_src1, v_src2));
3834 return v_dst;
3837 case Iop_InterleaveEvenLanes16x8: {
3838 HReg v_dst = newVRegV(env);
3839 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3840 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3841 addInstr(env,
3842 MIPSInstr_Msa3R(MSA_ILVEV, MSA_H,
3843 v_dst, v_src1, v_src2));
3844 return v_dst;
3847 case Iop_InterleaveEvenLanes32x4: {
3848 HReg v_dst = newVRegV(env);
3849 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3850 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3851 addInstr(env,
3852 MIPSInstr_Msa3R(MSA_ILVEV, MSA_W,
3853 v_dst, v_src1, v_src2));
3854 return v_dst;
3857 case Iop_InterleaveOddLanes8x16: {
3858 HReg v_dst = newVRegV(env);
3859 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3860 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3861 addInstr(env,
3862 MIPSInstr_Msa3R(MSA_ILVOD, MSA_B,
3863 v_dst, v_src1, v_src2));
3864 return v_dst;
3867 case Iop_InterleaveOddLanes16x8: {
3868 HReg v_dst = newVRegV(env);
3869 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3870 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3871 addInstr(env,
3872 MIPSInstr_Msa3R(MSA_ILVOD, MSA_H,
3873 v_dst, v_src1, v_src2));
3874 return v_dst;
3877 case Iop_InterleaveOddLanes32x4: {
3878 HReg v_dst = newVRegV(env);
3879 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3880 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3881 addInstr(env,
3882 MIPSInstr_Msa3R(MSA_ILVOD, MSA_W,
3883 v_dst, v_src1, v_src2));
3884 return v_dst;
3887 case Iop_PackEvenLanes8x16: {
3888 HReg v_dst = newVRegV(env);
3889 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3890 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3891 addInstr(env,
3892 MIPSInstr_Msa3R(MSA_PCKEV, MSA_B,
3893 v_dst, v_src1, v_src2));
3894 return v_dst;
3897 case Iop_PackEvenLanes16x8: {
3898 HReg v_dst = newVRegV(env);
3899 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3900 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3901 addInstr(env,
3902 MIPSInstr_Msa3R(MSA_PCKEV, MSA_H,
3903 v_dst, v_src1, v_src2));
3904 return v_dst;
3907 case Iop_PackEvenLanes32x4: {
3908 HReg v_dst = newVRegV(env);
3909 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3910 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3911 addInstr(env,
3912 MIPSInstr_Msa3R(MSA_PCKEV, MSA_W,
3913 v_dst, v_src1, v_src2));
3914 return v_dst;
3917 case Iop_PackOddLanes8x16: {
3918 HReg v_dst = newVRegV(env);
3919 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3920 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3921 addInstr(env,
3922 MIPSInstr_Msa3R(MSA_PCKOD, MSA_B,
3923 v_dst, v_src1, v_src2));
3924 return v_dst;
3927 case Iop_PackOddLanes16x8: {
3928 HReg v_dst = newVRegV(env);
3929 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3930 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3931 addInstr(env,
3932 MIPSInstr_Msa3R(MSA_PCKOD, MSA_H,
3933 v_dst, v_src1, v_src2));
3934 return v_dst;
3937 case Iop_PackOddLanes32x4: {
3938 HReg v_dst = newVRegV(env);
3939 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3940 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3941 addInstr(env,
3942 MIPSInstr_Msa3R(MSA_PCKOD, MSA_W,
3943 v_dst, v_src1, v_src2));
3944 return v_dst;
3947 case Iop_CmpEQ8x16: {
3948 HReg v_dst = newVRegV(env);
3949 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3950 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3951 addInstr(env,
3952 MIPSInstr_Msa3R(MSA_CEQ, MSA_B, v_dst, v_src1, v_src2));
3953 return v_dst;
3956 case Iop_CmpEQ16x8: {
3957 HReg v_dst = newVRegV(env);
3958 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3959 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3960 addInstr(env,
3961 MIPSInstr_Msa3R(MSA_CEQ, MSA_H, v_dst, v_src1, v_src2));
3962 return v_dst;
3965 case Iop_CmpEQ32x4: {
3966 HReg v_dst = newVRegV(env);
3967 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3968 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3969 addInstr(env,
3970 MIPSInstr_Msa3R(MSA_CEQ, MSA_W, v_dst, v_src1, v_src2));
3971 return v_dst;
3974 case Iop_CmpEQ64x2: {
3975 HReg v_dst = newVRegV(env);
3976 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3977 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3978 addInstr(env,
3979 MIPSInstr_Msa3R(MSA_CEQ, MSA_D, v_dst, v_src1, v_src2));
3980 return v_dst;
3983 case Iop_CmpGT8Sx16: {
3984 HReg v_dst = newVRegV(env);
3985 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3986 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3987 addInstr(env,
3988 MIPSInstr_Msa3R(MSA_CLT_S, MSA_B,
3989 v_dst, v_src2, v_src1));
3990 return v_dst;
3993 case Iop_CmpGT16Sx8: {
3994 HReg v_dst = newVRegV(env);
3995 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
3996 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
3997 addInstr(env,
3998 MIPSInstr_Msa3R(MSA_CLT_S, MSA_H,
3999 v_dst, v_src2, v_src1));
4000 return v_dst;
4003 case Iop_CmpGT32Sx4: {
4004 HReg v_dst = newVRegV(env);
4005 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4006 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4007 addInstr(env,
4008 MIPSInstr_Msa3R(MSA_CLT_S, MSA_W,
4009 v_dst, v_src2, v_src1));
4010 return v_dst;
4013 case Iop_CmpGT64Sx2: {
4014 HReg v_dst = newVRegV(env);
4015 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4016 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4017 addInstr(env,
4018 MIPSInstr_Msa3R(MSA_CLT_S, MSA_D,
4019 v_dst, v_src2, v_src1));
4020 return v_dst;
4023 case Iop_CmpGT8Ux16: {
4024 HReg v_dst = newVRegV(env);
4025 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4026 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4027 addInstr(env,
4028 MIPSInstr_Msa3R(MSA_CLT_U, MSA_B,
4029 v_dst, v_src2, v_src1));
4030 return v_dst;
4033 case Iop_CmpGT16Ux8: {
4034 HReg v_dst = newVRegV(env);
4035 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4036 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4037 addInstr(env,
4038 MIPSInstr_Msa3R(MSA_CLT_U, MSA_H,
4039 v_dst, v_src2, v_src1));
4040 return v_dst;
4043 case Iop_CmpGT32Ux4: {
4044 HReg v_dst = newVRegV(env);
4045 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4046 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4047 addInstr(env,
4048 MIPSInstr_Msa3R(MSA_CLT_U, MSA_W,
4049 v_dst, v_src2, v_src1));
4050 return v_dst;
4053 case Iop_CmpGT64Ux2: {
4054 HReg v_dst = newVRegV(env);
4055 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4056 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4057 addInstr(env,
4058 MIPSInstr_Msa3R(MSA_CLT_U, MSA_D,
4059 v_dst, v_src2, v_src1));
4060 return v_dst;
4063 case Iop_Avg8Sx16: {
4064 HReg v_dst = newVRegV(env);
4065 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4066 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4067 addInstr(env,
4068 MIPSInstr_Msa3R(MSA_AVER_S, MSA_B,
4069 v_dst, v_src1, v_src2));
4070 return v_dst;
4073 case Iop_Avg16Sx8: {
4074 HReg v_dst = newVRegV(env);
4075 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4076 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4077 addInstr(env,
4078 MIPSInstr_Msa3R(MSA_AVER_S, MSA_H,
4079 v_dst, v_src1, v_src2));
4080 return v_dst;
4083 case Iop_Avg32Sx4: {
4084 HReg v_dst = newVRegV(env);
4085 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4086 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4087 addInstr(env,
4088 MIPSInstr_Msa3R(MSA_AVER_S, MSA_W,
4089 v_dst, v_src1, v_src2));
4090 return v_dst;
4093 case Iop_Avg8Ux16: {
4094 HReg v_dst = newVRegV(env);
4095 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4096 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4097 addInstr(env,
4098 MIPSInstr_Msa3R(MSA_AVER_U, MSA_B,
4099 v_dst, v_src1, v_src2));
4100 return v_dst;
4103 case Iop_Avg16Ux8: {
4104 HReg v_dst = newVRegV(env);
4105 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4106 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4107 addInstr(env,
4108 MIPSInstr_Msa3R(MSA_AVER_U, MSA_H,
4109 v_dst, v_src1, v_src2));
4110 return v_dst;
4113 case Iop_Avg32Ux4: {
4114 HReg v_dst = newVRegV(env);
4115 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4116 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4117 addInstr(env,
4118 MIPSInstr_Msa3R(MSA_AVER_U, MSA_W,
4119 v_dst, v_src1, v_src2));
4120 return v_dst;
4123 case Iop_Mul8x16: {
4124 HReg v_dst = newVRegV(env);
4125 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4126 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4127 addInstr(env,
4128 MIPSInstr_Msa3R(MSA_MULV, MSA_B,
4129 v_dst, v_src1, v_src2));
4130 return v_dst;
4133 case Iop_Mul16x8: {
4134 HReg v_dst = newVRegV(env);
4135 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4136 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4137 addInstr(env,
4138 MIPSInstr_Msa3R(MSA_MULV, MSA_H,
4139 v_dst, v_src1, v_src2));
4140 return v_dst;
4143 case Iop_Mul32x4: {
4144 HReg v_dst = newVRegV(env);
4145 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4146 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4147 addInstr(env,
4148 MIPSInstr_Msa3R(MSA_MULV, MSA_W,
4149 v_dst, v_src1, v_src2));
4150 return v_dst;
4153 case Iop_AndV128: {
4154 HReg v_dst = newVRegV(env);
4155 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4156 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4157 addInstr(env, MIPSInstr_MsaVec(MSA_ANDV, v_dst, v_src1, v_src2));
4158 return v_dst;
4161 case Iop_OrV128: {
4162 HReg v_dst = newVRegV(env);
4163 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4164 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4165 addInstr(env, MIPSInstr_MsaVec(MSA_ORV, v_dst, v_src1, v_src2));
4166 return v_dst;
4169 case Iop_XorV128: {
4170 HReg v_dst = newVRegV(env);
4171 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4172 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4173 addInstr(env, MIPSInstr_MsaVec(MSA_XORV, v_dst, v_src1, v_src2));
4174 return v_dst;
4177 case Iop_ShrV128: {
4178 HReg v_dst = newVRegV(env);
4179 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4180 MIPSRH *sm;
4181 sm = iselWordExpr_RH7u(env, e->Iex.Binop.arg2);
4182 addInstr(env,
4183 MIPSInstr_Msa3R(MSA_SUBV, MSA_B,
4184 v_dst, v_src1, v_src1));
4186 if (sm->tag == Mrh_Imm) {
4187 int n = (sm->Mrh.Imm.imm16) >> 3;
4188 addInstr(env,
4189 MIPSInstr_MsaElm(MSA_SLDI, v_src1, v_dst,
4190 MSA_DFN_B | n));
4191 } else {
4192 HReg v_src2 = sm->Mrh.Reg.reg;
4193 MIPSRH *ri = MIPSRH_Imm(False, 3);
4194 HReg r_dst = newVRegI(env);
4195 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */,
4196 r_dst, v_src2, ri));
4197 addInstr(env,
4198 MIPSInstr_Msa3R(MSA_SLD, MSA_B,
4199 v_dst, v_src1, r_dst));
4202 return v_dst;
4205 case Iop_ShlV128: {
4206 HReg v_dst = newVRegV(env);
4207 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4208 MIPSRH *sm;
4209 sm = iselWordExpr_RH7u(env, e->Iex.Binop.arg2);
4210 addInstr(env,
4211 MIPSInstr_Msa3R(MSA_SUBV, MSA_B,
4212 v_dst, v_src1, v_src1));
4214 if (sm->tag == Mrh_Imm) {
4215 int n = 16 - ((sm->Mrh.Imm.imm16) >> 3);
4217 if (n == 16) n = 0;
4219 addInstr(env,
4220 MIPSInstr_MsaElm(MSA_SLDI, v_dst, v_src1,
4221 MSA_DFN_B | n));
4222 } else {
4223 HReg v_src2 = sm->Mrh.Reg.reg;
4224 MIPSRH *ri = MIPSRH_Imm(False, 3);
4225 HReg r_dst = newVRegI(env);
4226 HReg help = newVRegI(env);
4227 addInstr(env, MIPSInstr_Alu(Malu_XOR, help, v_src2, sm));
4228 addInstr(env, MIPSInstr_Alu(Malu_SUB, help, help, sm));
4229 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /*32bit shift */,
4230 r_dst, help, ri));
4231 addInstr(env,
4232 MIPSInstr_Msa3R(MSA_SLD, MSA_B,
4233 v_src1, v_dst, r_dst));
4236 return v_src1;
4239 case Iop_ShlN8x16: {
4240 HReg v_dst = newVRegV(env);
4241 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4242 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4243 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4244 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4245 addInstr(env,
4246 MIPSInstr_MsaBit(MSA_SLLI, MSA_B,
4247 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4248 v_src1, v_dst));
4249 return v_dst;
4252 case Iop_ShlN16x8: {
4253 HReg v_dst = newVRegV(env);
4254 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4255 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4256 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4257 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4258 addInstr(env,
4259 MIPSInstr_MsaBit(MSA_SLLI, MSA_H,
4260 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4261 v_src1, v_dst));
4262 return v_dst;
4265 case Iop_ShlN32x4: {
4266 HReg v_dst = newVRegV(env);
4267 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4268 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4269 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4270 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4271 addInstr(env,
4272 MIPSInstr_MsaBit(MSA_SLLI, MSA_W,
4273 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4274 v_src1, v_dst));
4275 return v_dst;
4278 case Iop_ShlN64x2: {
4279 HReg v_dst = newVRegV(env);
4280 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4281 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4282 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4283 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4284 addInstr(env,
4285 MIPSInstr_MsaBit(MSA_SLLI, MSA_D,
4286 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4287 v_src1, v_dst));
4288 return v_dst;
4291 case Iop_SarN8x16: {
4292 HReg v_dst = newVRegV(env);
4293 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4294 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4295 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4296 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4297 addInstr(env,
4298 MIPSInstr_MsaBit(MSA_SRAI, MSA_B,
4299 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4300 v_src1, v_dst));
4301 return v_dst;
4304 case Iop_SarN16x8: {
4305 HReg v_dst = newVRegV(env);
4306 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4307 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4308 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4309 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4310 addInstr(env,
4311 MIPSInstr_MsaBit(MSA_SRAI, MSA_H,
4312 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4313 v_src1, v_dst));
4314 return v_dst;
4317 case Iop_SarN32x4: {
4318 HReg v_dst = newVRegV(env);
4319 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4320 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4321 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4322 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4323 addInstr(env,
4324 MIPSInstr_MsaBit(MSA_SRAI, MSA_W,
4325 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4326 v_src1, v_dst));
4327 return v_dst;
4330 case Iop_SarN64x2: {
4331 HReg v_dst = newVRegV(env);
4332 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4333 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4334 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4335 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4336 addInstr(env,
4337 MIPSInstr_MsaBit(MSA_SRAI, MSA_D,
4338 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4339 v_src1, v_dst));
4340 return v_dst;
4343 case Iop_ShrN8x16: {
4344 HReg v_dst = newVRegV(env);
4345 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4346 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4347 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4348 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4349 addInstr(env,
4350 MIPSInstr_MsaBit(MSA_SRLI, MSA_B,
4351 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4352 v_src1, v_dst));
4353 return v_dst;
4356 case Iop_ShrN16x8: {
4357 HReg v_dst = newVRegV(env);
4358 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4359 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4360 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4361 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4362 addInstr(env,
4363 MIPSInstr_MsaBit(MSA_SRLI, MSA_H,
4364 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4365 v_src1, v_dst));
4366 return v_dst;
4369 case Iop_ShrN32x4: {
4370 HReg v_dst = newVRegV(env);
4371 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4372 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4373 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4374 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4375 addInstr(env,
4376 MIPSInstr_MsaBit(MSA_SRLI, MSA_W,
4377 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4378 v_src1, v_dst));
4379 return v_dst;
4382 case Iop_ShrN64x2: {
4383 HReg v_dst = newVRegV(env);
4384 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4385 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4386 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4387 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4388 addInstr(env,
4389 MIPSInstr_MsaBit(MSA_SRLI, MSA_D,
4390 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4391 v_src1, v_dst));
4392 return v_dst;
4395 case Iop_QandQSarNnarrow64Sto32Sx2: {
4396 HReg v_dst = newVRegV(env);
4397 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4398 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4399 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4400 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4401 addInstr(env,
4402 MIPSInstr_MsaBit(MSA_SRAI, MSA_D,
4403 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4404 v_src1, v_dst));
4405 addInstr(env, MIPSInstr_MsaBit(MSA_SAT_S, MSA_D, 31, v_dst, v_dst));
4406 return v_dst;
4409 case Iop_QandQSarNnarrow32Sto16Sx4: {
4410 HReg v_dst = newVRegV(env);
4411 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4412 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4413 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4414 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4415 addInstr(env,
4416 MIPSInstr_MsaBit(MSA_SRAI, MSA_W,
4417 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4418 v_src1, v_dst));
4419 addInstr(env,
4420 MIPSInstr_MsaBit(MSA_SAT_S, MSA_W, 15, v_dst, v_dst));
4421 return v_dst;
4424 case Iop_QandQRSarNnarrow64Sto32Sx2: {
4425 HReg v_dst = newVRegV(env);
4426 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4427 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4428 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4429 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4430 addInstr(env,
4431 MIPSInstr_MsaBit(MSA_SRARI, MSA_D,
4432 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4433 v_src1, v_dst));
4434 addInstr(env,
4435 MIPSInstr_MsaBit(MSA_SAT_S, MSA_D, 31, v_dst, v_dst));
4436 return v_dst;
4439 case Iop_QandQRSarNnarrow32Sto16Sx4: {
4440 HReg v_dst = newVRegV(env);
4441 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4442 vassert(e->Iex.Binop.arg2->tag == Iex_Const);
4443 vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8);
4444 vassert(e->Iex.Binop.arg2->Iex.Const.con->Ico.U8 <= 63);
4445 addInstr(env,
4446 MIPSInstr_MsaBit(MSA_SRARI, MSA_W,
4447 e->Iex.Binop.arg2->Iex.Const.con->Ico.U8,
4448 v_src1, v_dst));
4449 addInstr(env,
4450 MIPSInstr_MsaBit(MSA_SAT_S, MSA_W, 15, v_dst, v_dst));
4451 return v_dst;
4454 case Iop_CmpEQ32Fx4: {
4455 HReg v_dst = newVRegV(env);
4456 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4457 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4458 addInstr(env,
4459 MIPSInstr_Msa3RF(MSA_FCEQ, MSA_F_WH,
4460 v_dst, v_src1, v_src2));
4461 return v_dst;
4464 case Iop_CmpEQ64Fx2: {
4465 HReg v_dst = newVRegV(env);
4466 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4467 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4468 addInstr(env,
4469 MIPSInstr_Msa3RF(MSA_FCEQ, MSA_F_DW,
4470 v_dst, v_src1, v_src2));
4471 return v_dst;
4474 case Iop_CmpLT32Fx4: {
4475 HReg v_dst = newVRegV(env);
4476 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4477 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4478 addInstr(env,
4479 MIPSInstr_Msa3RF(MSA_FCLT, MSA_F_WH,
4480 v_dst, v_src1, v_src2));
4481 return v_dst;
4484 case Iop_CmpLT64Fx2: {
4485 HReg v_dst = newVRegV(env);
4486 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4487 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4488 addInstr(env,
4489 MIPSInstr_Msa3RF(MSA_FCLT, MSA_F_DW,
4490 v_dst, v_src1, v_src2));
4491 return v_dst;
4494 case Iop_CmpLE32Fx4: {
4495 HReg v_dst = newVRegV(env);
4496 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4497 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4498 addInstr(env,
4499 MIPSInstr_Msa3RF(MSA_FCLE, MSA_F_WH,
4500 v_dst, v_src1, v_src2));
4501 return v_dst;
4504 case Iop_CmpLE64Fx2: {
4505 HReg v_dst = newVRegV(env);
4506 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4507 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4508 addInstr(env,
4509 MIPSInstr_Msa3RF(MSA_FCLE, MSA_F_DW,
4510 v_dst, v_src1, v_src2));
4511 return v_dst;
4514 case Iop_CmpUN32Fx4: {
4515 HReg v_dst = newVRegV(env);
4516 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4517 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4518 addInstr(env,
4519 MIPSInstr_Msa3RF(MSA_FCUN, MSA_F_WH,
4520 v_dst, v_src1, v_src2));
4521 return v_dst;
4524 case Iop_CmpUN64Fx2: {
4525 HReg v_dst = newVRegV(env);
4526 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4527 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4528 addInstr(env,
4529 MIPSInstr_Msa3RF(MSA_FCUN, MSA_F_DW,
4530 v_dst, v_src1, v_src2));
4531 return v_dst;
4534 case Iop_64HLtoV128: {
4535 HReg v_dst = newVRegV(env);
4537 if (mode64) {
4538 HReg r_src1;
4539 HReg r_src2;
4540 r_src1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
4541 r_src2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
4542 addInstr(env,
4543 MIPSInstr_Msa2R(MSA_FILL, MSA_D, r_src2, v_dst));
4544 addInstr(env,
4545 MIPSInstr_MsaElm(MSA_INSERT, r_src1, v_dst,
4546 MSA_DFN_D | 1));
4547 } else {
4548 HReg r_src1h, r_src1l;
4549 HReg r_src2h, r_src2l;
4550 iselInt64Expr(&r_src1h, &r_src1l, env, e->Iex.Binop.arg1);
4551 iselInt64Expr(&r_src2h, &r_src2l, env, e->Iex.Binop.arg2);
4552 addInstr(env,
4553 MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_src2l, v_dst));
4554 addInstr(env,
4555 MIPSInstr_MsaElm(MSA_INSERT, r_src2h, v_dst,
4556 MSA_DFN_W | 1));
4557 addInstr(env,
4558 MIPSInstr_MsaElm(MSA_INSERT, r_src1l, v_dst,
4559 MSA_DFN_W | 2));
4560 addInstr(env,
4561 MIPSInstr_MsaElm(MSA_INSERT, r_src1h, v_dst,
4562 MSA_DFN_W | 3));
4565 return v_dst;
4568 case Iop_Min32Fx4: {
4569 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4570 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4571 HReg v_dst = newVRegV(env);
4572 addInstr(env,
4573 MIPSInstr_Msa3RF(MSA_FMIN, MSA_F_WH,
4574 v_dst, v_src1, v_src2));
4575 return v_dst;
4578 case Iop_Min64Fx2: {
4579 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4580 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4581 HReg v_dst = newVRegV(env);
4582 addInstr(env,
4583 MIPSInstr_Msa3RF(MSA_FMIN, MSA_F_DW,
4584 v_dst, v_src1, v_src2));
4585 return v_dst;
4588 case Iop_Max32Fx4: {
4589 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4590 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4591 HReg v_dst = newVRegV(env);
4592 addInstr(env,
4593 MIPSInstr_Msa3RF(MSA_FMAX, MSA_F_WH,
4594 v_dst, v_src1, v_src2));
4595 return v_dst;
4598 case Iop_Max64Fx2: {
4599 HReg v_src1 = iselV128Expr(env, e->Iex.Binop.arg1);
4600 HReg v_src2 = iselV128Expr(env, e->Iex.Binop.arg2);
4601 HReg v_dst = newVRegV(env);
4602 addInstr(env,
4603 MIPSInstr_Msa3RF(MSA_FMAX, MSA_F_DW,
4604 v_dst, v_src1, v_src2));
4605 return v_dst;
4608 case Iop_Sqrt32Fx4: {
4609 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg2);
4610 HReg v_dst = newVRegV(env);
4611 set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
4612 addInstr(env,
4613 MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_WH, v_dst, v_src));
4614 set_MIPS_rounding_default_MSA(env);
4615 return v_dst;
4618 case Iop_Sqrt64Fx2: {
4619 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg2);
4620 HReg v_dst = newVRegV(env);
4621 set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
4622 addInstr(env,
4623 MIPSInstr_Msa2RF(MSA_FSQRT, MSA_F_DW, v_dst, v_src));
4624 set_MIPS_rounding_default_MSA(env);
4625 return v_dst;
4628 default:
4629 vex_printf("iselV128Expr_wrk: unsupported binop: %x\n", op_binop);
4633 if (e->tag == Iex_Triop) {
4634 IROp op_triop = e->Iex.Triop.details->op;
4636 switch (op_triop) {
4637 case Iop_Add32Fx4: {
4638 HReg v_dst = newVRegV(env);
4639 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4640 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4641 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4642 addInstr(env,
4643 MIPSInstr_Msa3RF(MSA_FADD, MSA_F_WH,
4644 v_dst, v_src1, v_src2));
4645 set_MIPS_rounding_default_MSA(env);
4646 return v_dst;
4649 case Iop_Add64Fx2: {
4650 HReg v_dst = newVRegV(env);
4651 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4652 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4653 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4654 addInstr(env,
4655 MIPSInstr_Msa3RF(MSA_FADD, MSA_F_DW,
4656 v_dst, v_src1, v_src2));
4657 set_MIPS_rounding_default_MSA(env);
4658 return v_dst;
4661 case Iop_Sub32Fx4: {
4662 HReg v_dst = newVRegV(env);
4663 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4664 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4665 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4666 addInstr(env,
4667 MIPSInstr_Msa3RF(MSA_FSUB, MSA_F_WH,
4668 v_dst, v_src1, v_src2));
4669 set_MIPS_rounding_default_MSA(env);
4670 return v_dst;
4673 case Iop_Sub64Fx2: {
4674 HReg v_dst = newVRegV(env);
4675 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4676 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4677 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4678 addInstr(env,
4679 MIPSInstr_Msa3RF(MSA_FSUB, MSA_F_DW,
4680 v_dst, v_src1, v_src2));
4681 set_MIPS_rounding_default_MSA(env);
4682 return v_dst;
4685 case Iop_Mul32Fx4: {
4686 HReg v_dst = newVRegV(env);
4687 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4688 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4689 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4690 addInstr(env,
4691 MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_WH,
4692 v_dst, v_src1, v_src2));
4693 set_MIPS_rounding_default_MSA(env);
4694 return v_dst;
4697 case Iop_Mul64Fx2: {
4698 HReg v_dst = newVRegV(env);
4699 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4700 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4701 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4702 addInstr(env,
4703 MIPSInstr_Msa3RF(MSA_FMUL, MSA_F_DW,
4704 v_dst, v_src1, v_src2));
4705 set_MIPS_rounding_default_MSA(env);
4706 return v_dst;
4709 case Iop_Div32Fx4: {
4710 HReg v_dst = newVRegV(env);
4711 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4712 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4713 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4714 addInstr(env,
4715 MIPSInstr_Msa3RF(MSA_FDIV, MSA_F_WH,
4716 v_dst, v_src1, v_src2));
4717 set_MIPS_rounding_default_MSA(env);
4718 return v_dst;
4721 case Iop_Div64Fx2: {
4722 HReg v_dst = newVRegV(env);
4723 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4724 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4725 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4726 addInstr(env,
4727 MIPSInstr_Msa3RF(MSA_FDIV, MSA_F_DW,
4728 v_dst, v_src1, v_src2));
4729 set_MIPS_rounding_default_MSA(env);
4730 return v_dst;
4733 case Iop_F32x4_2toQ16x8: {
4734 HReg v_dst = newVRegV(env);
4735 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4736 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4737 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4738 addInstr(env,
4739 MIPSInstr_Msa3RF(MSA_FTQ, MSA_F_WH,
4740 v_dst, v_src1, v_src2));
4741 set_MIPS_rounding_default_MSA(env);
4742 return v_dst;
4745 case Iop_F64x2_2toQ32x4: {
4746 HReg v_dst = newVRegV(env);
4747 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4748 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4749 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4750 addInstr(env,
4751 MIPSInstr_Msa3RF(MSA_FTQ, MSA_F_DW,
4752 v_dst, v_src1, v_src2));
4753 set_MIPS_rounding_default_MSA(env);
4754 return v_dst;
4757 case Iop_Scale2_32Fx4: {
4758 HReg v_dst = newVRegV(env);
4759 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4760 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4761 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4762 addInstr(env,
4763 MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_WH,
4764 v_dst, v_src1, v_src2));
4765 set_MIPS_rounding_default_MSA(env);
4766 return v_dst;
4769 case Iop_Scale2_64Fx2: {
4770 HReg v_dst = newVRegV(env);
4771 HReg v_src1 = iselV128Expr(env, e->Iex.Triop.details->arg2);
4772 HReg v_src2 = iselV128Expr(env, e->Iex.Triop.details->arg3);
4773 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
4774 addInstr(env,
4775 MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_DW,
4776 v_dst, v_src1, v_src2));
4777 set_MIPS_rounding_default_MSA(env);
4778 return v_dst;
4781 default:
4782 vex_printf("iselV128Expr_wrk: unsupported triop: %x\n", op_triop);
4786 if (e->tag == Iex_Const) {
4787 IRConst *con = e->Iex.Const.con;
4789 if (con->tag != Ico_V128) {
4790 vpanic("iselV128Expr.const(mips)");
4791 } else {
4792 HReg v_dst = newVRegV(env);
4793 UShort val = con->Ico.V128;
4794 HReg zero = Zero(mode64);
4796 switch (val) {
4797 case 0: /* likely */
4798 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, zero, v_dst));
4799 break;
4801 default: {
4802 HReg r_tmp = newVRegI(env);
4803 UInt i;
4804 addInstr(env, MIPSInstr_LI(r_tmp, 0xfful));
4806 if (val & 1) {
4807 addInstr(env,
4808 MIPSInstr_Msa2R(MSA_FILL, MSA_B, r_tmp, v_dst));
4809 } else {
4810 addInstr(env,
4811 MIPSInstr_Msa2R(MSA_FILL, MSA_B, zero, v_dst));
4814 for (i = 1; i < 16; i++) {
4815 val >>= 1;
4817 if (val & 1) {
4818 addInstr(env,
4819 MIPSInstr_MsaElm(MSA_INSERT, r_tmp, v_dst,
4820 MSA_DFN_B | i));
4821 } else {
4822 addInstr(env,
4823 MIPSInstr_MsaElm(MSA_INSERT, zero, v_dst,
4824 MSA_DFN_B | i));
4828 break;
4832 return v_dst;
4836 if (e->tag == Iex_ITE) {
4837 HReg v_dst = newVRegV(env);
4838 HReg iff = iselV128Expr(env, e->Iex.ITE.iffalse);
4839 HReg ift = iselV128Expr(env, e->Iex.ITE.iftrue);
4840 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
4841 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_cond, r_cond,
4842 MIPSRH_Imm(False, 1)));
4843 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_cond, v_dst));
4844 addInstr(env,
4845 MIPSInstr_Alu(Malu_ADD, r_cond, r_cond, MIPSRH_Imm(True, 1)));
4846 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_cond, v_dst, MSA_DFN_W | 2));
4847 addInstr(env, MIPSInstr_Msa3R(MSA_VSHF, MSA_D, v_dst, ift, iff));
4848 return v_dst;
4851 vex_printf("iselV128Expr_wrk: Unsupported tag: %x\n", e->tag);
4852 ppIRExpr(e);
4853 vpanic("iselV128Expr(mips)");
4856 /*---------------------------------------------------------*/
4857 /*--- ISEL: Integer expressions (128 bit) ---*/
4858 /*---------------------------------------------------------*/
4860 /* 64-bit mode ONLY: compute a 128-bit value into a register pair,
4861 which is returned as the first two parameters. As with
4862 iselWordExpr_R, these may be either real or virtual regs; in any
4863 case they must not be changed by subsequent code emitted by the
4864 caller. */
4866 static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
4868 vassert(env->mode64);
4869 iselInt128Expr_wrk(rHi, rLo, env, e);
4870 vassert(hregClass(*rHi) == HRcGPR(env->mode64));
4871 vassert(hregIsVirtual(*rHi));
4872 vassert(hregClass(*rLo) == HRcGPR(env->mode64));
4873 vassert(hregIsVirtual(*rLo));
4876 /* DO NOT CALL THIS DIRECTLY ! */
4877 static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
4878 IRExpr * e)
4880 vassert(e);
4881 vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
4883 /* read 128-bit IRTemp */
4884 if (e->tag == Iex_RdTmp) {
4885 lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
4886 return;
4889 /* --------- BINARY ops --------- */
4890 if (e->tag == Iex_Binop) {
4891 switch (e->Iex.Binop.op) {
4892 /* 64 x 64 -> 128 multiply */
4893 case Iop_MullU64:
4894 case Iop_MullS64: {
4895 HReg tLo = newVRegI(env);
4896 HReg tHi = newVRegI(env);
4897 Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
4898 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
4899 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
4900 #if (__mips_isa_rev >= 6)
4901 addInstr(env, MIPSInstr_Mulr6(syned, False, True,
4902 tLo, r_srcL, r_srcR));
4903 addInstr(env, MIPSInstr_Mulr6(syned, False, False,
4904 tHi, r_srcL, r_srcR));
4905 #else
4906 addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR));
4907 addInstr(env, MIPSInstr_Mfhi(tHi));
4908 addInstr(env, MIPSInstr_Mflo(tLo));
4909 #endif
4910 *rHi = tHi;
4911 *rLo = tLo;
4912 return;
4915 /* 64HLto128(e1,e2) */
4916 case Iop_64HLto128:
4917 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
4918 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
4919 return;
4921 case Iop_DivModU64to64:
4922 case Iop_DivModS64to64: {
4923 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
4924 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
4925 HReg tLo = newVRegI(env);
4926 HReg tHi = newVRegI(env);
4927 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
4928 #if (__mips_isa_rev >= 6)
4929 addInstr(env, MIPSInstr_Divr6(syned/*Unsigned or Signed */ ,
4930 False /*32bit or 64bit div */ ,
4931 False /*mod*/,
4932 tLo, r_srcL, r_srcR));
4933 addInstr(env, MIPSInstr_Divr6(syned/*Unsigned or Signed */ ,
4934 False /*32bit or 64bit div */ ,
4935 True /*mod*/,
4936 tHi, r_srcL, r_srcR));
4937 #else
4938 addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
4939 addInstr(env, MIPSInstr_Mfhi(tHi));
4940 addInstr(env, MIPSInstr_Mflo(tLo));
4941 #endif
4942 *rHi = tHi;
4943 *rLo = tLo;
4944 return;
4947 default:
4948 break;
4951 vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag);
4952 ppIRExpr(e);
4953 vpanic("iselInt128Expr(mips64)");
4956 /*---------------------------------------------------------*/
4957 /*--- ISEL: Integer expressions (64 bit) ---*/
4958 /*---------------------------------------------------------*/
4960 /* 32-bit mode ONLY. Compute a 64-bit value into the register
4961 * pair HI, LO. HI and LO must not be changed by subsequent
4962 * code emitted by the caller. */
4964 static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
4966 vassert(!env->mode64);
4967 iselInt64Expr_wrk(rHi, rLo, env, e);
4968 vassert(hregClass(*rHi) == HRcInt32);
4969 vassert(hregIsVirtual(*rHi));
4970 vassert(hregClass(*rLo) == HRcInt32);
4971 vassert(hregIsVirtual(*rLo));
4974 /* DO NOT CALL THIS DIRECTLY ! */
4975 static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
4977 vassert(e);
4978 vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
4980 /* read 64-bit IRTemp */
4981 if (e->tag == Iex_RdTmp) {
4982 lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp);
4983 return;
4985 /* 64-bit load */
4986 if (e->tag == Iex_Load) {
4987 HReg tLo = newVRegI(env);
4988 HReg tHi = newVRegI(env);
4989 HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
4990 addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64));
4991 addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64));
4992 *rHi = tHi;
4993 *rLo = tLo;
4994 return;
4997 /* 64-bit literal */
4998 if (e->tag == Iex_Const) {
4999 ULong w64 = e->Iex.Const.con->Ico.U64;
5000 UInt wHi = toUInt(w64 >> 32);
5001 UInt wLo = toUInt(w64);
5002 HReg tLo = newVRegI(env);
5003 HReg tHi = newVRegI(env);
5004 vassert(e->Iex.Const.con->tag == Ico_U64);
5006 if (wLo == wHi) {
5007 /* Save a precious Int register in this special case. */
5008 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
5009 *rHi = tLo;
5010 *rLo = tLo;
5011 } else {
5012 addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi));
5013 addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
5014 *rHi = tHi;
5015 *rLo = tLo;
5018 return;
5021 /* 64-bit GET */
5022 if (e->tag == Iex_Get) {
5023 HReg tLo = newVRegI(env);
5024 HReg tHi = newVRegI(env);
5026 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
5027 GuestStatePointer(mode64));
5028 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
5029 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64));
5030 *rHi = tHi;
5031 *rLo = tLo;
5032 return;
5035 /* 64-bit ITE */
5036 if (e->tag == Iex_ITE) {
5037 vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1);
5038 HReg expr0Lo, expr0Hi;
5039 HReg expr1Lo, expr1Hi;
5040 HReg desLo = newVRegI(env);
5041 HReg desHi = newVRegI(env);
5042 HReg cond = iselWordExpr_R(env, e->Iex.ITE.cond);
5044 /* expr0Hi:expr0Lo = iffalse */
5045 /* expr1Hi:expr1Lo = iftrue */
5046 iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.ITE.iffalse);
5047 iselInt64Expr(&expr1Hi, &expr1Lo, env, e->Iex.ITE.iftrue);
5049 /* move desLo, expr0Lo
5050 * move desHi, expr0Hi
5051 * movn desLo, expr1Lo, cond
5052 * movn desHi, expr1Hi, cond */
5053 #if (__mips_isa_rev >= 6)
5055 HReg r_temp = newVRegI(env);
5056 addInstr(env, MIPSInstr_MoveCond(MSeleqz, desLo, expr0Lo, cond));
5057 addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, expr1Lo, cond));
5058 addInstr(env, MIPSInstr_Alu(Malu_OR, desLo, desLo, MIPSRH_Reg(r_temp)));
5060 addInstr(env, MIPSInstr_MoveCond(MSeleqz, desHi, expr0Hi, cond));
5061 addInstr(env, MIPSInstr_MoveCond(MSelnez, r_temp, expr1Hi, cond));
5062 addInstr(env, MIPSInstr_Alu(Malu_OR, desHi, desHi, MIPSRH_Reg(r_temp)));
5064 #else
5065 addInstr(env, mk_iMOVds_RR(desLo, expr0Lo));
5066 addInstr(env, mk_iMOVds_RR(desHi, expr0Hi));
5067 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desLo, expr1Lo, cond));
5068 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, desHi, expr1Hi, cond));
5069 #endif
5071 *rHi = desHi;
5072 *rLo = desLo;
5073 return;
5076 if (e->tag == Iex_CCall) {
5077 HReg r_dstH = newVRegI(env);
5078 HReg r_dstL = newVRegI(env);
5079 vassert(e->Iex.CCall.retty == Ity_I64);
5081 /* Marshal args, do the call, clear stack. */
5082 UInt addToSp = 0;
5083 RetLoc rloc = mk_RetLoc_INVALID();
5084 doHelperCall(&addToSp, &rloc, env, NULL/*guard*/, e->Iex.CCall.cee,
5085 e->Iex.CCall.retty, e->Iex.CCall.args );
5087 vassert(is_sane_RetLoc(rloc));
5088 vassert(rloc.pri == RLPri_2Int);
5089 vassert(addToSp == 0);
5090 addInstr(env, mk_iMOVds_RR(r_dstL, hregMIPS_GPR2(False)));
5091 addInstr(env, mk_iMOVds_RR(r_dstH, hregMIPS_GPR3(False)));
5092 *rHi = r_dstH;
5093 *rLo = r_dstL;
5094 return;
5097 /* --------- BINARY ops --------- */
5098 if (e->tag == Iex_Binop) {
5099 IROp op_binop = e->Iex.Binop.op;
5100 switch (op_binop) {
5101 /* 32 x 32 -> 64 multiply */
5102 /* Add64 */
5103 case Iop_Add64: {
5104 HReg xLo, xHi, yLo, yHi, carryBit;
5106 HReg tHi = newVRegI(env);
5107 HReg tHi1 = newVRegI(env);
5108 HReg tLo = newVRegI(env);
5110 carryBit = newVRegI(env);
5112 Bool size32 = True;
5113 MIPSCondCode cc = MIPScc_LO;
5115 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
5116 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
5117 addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo)));
5119 /* Check carry. */
5120 addInstr(env, MIPSInstr_Cmp(False, size32, carryBit, tLo, xLo, cc));
5122 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi1, xHi, MIPSRH_Reg(yHi)));
5123 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, tHi1,
5124 MIPSRH_Reg(carryBit)));
5126 *rHi = tHi;
5127 *rLo = tLo;
5128 return;
5130 case Iop_Sub64: {
5131 HReg xLo, xHi, yLo, yHi, borrow;
5132 Bool size32 = True;
5133 MIPSCondCode cc = MIPScc_LO;
5135 HReg tHi = newVRegI(env);
5136 HReg tLo = newVRegI(env);
5138 borrow = newVRegI(env);
5140 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
5141 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
5143 addInstr(env, MIPSInstr_Alu(Malu_SUB, tLo, xLo, MIPSRH_Reg(yLo)));
5145 /* Check if borrow is nedded. */
5146 addInstr(env, MIPSInstr_Cmp(False, size32, borrow, xLo, yLo, cc));
5148 addInstr(env, MIPSInstr_Alu(Malu_ADD, yHi, yHi,
5149 MIPSRH_Reg(borrow)));
5150 addInstr(env, MIPSInstr_Alu(Malu_SUB, tHi, xHi, MIPSRH_Reg(yHi)));
5152 *rHi = tHi;
5153 *rLo = tLo;
5154 return;
5156 case Iop_MullU32:
5157 case Iop_MullS32: {
5158 HReg tLo = newVRegI(env);
5159 HReg tHi = newVRegI(env);
5160 Bool syned = toBool(op_binop == Iop_MullS32);
5161 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
5162 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
5163 #if (__mips_isa_rev >= 6)
5164 addInstr(env, MIPSInstr_Mulr6(syned, True, True,
5165 tLo, r_srcL, r_srcR));
5166 addInstr(env, MIPSInstr_Mulr6(syned, True, False,
5167 tHi, r_srcL, r_srcR));
5168 #else
5169 addInstr(env, MIPSInstr_Mult(syned, r_srcL, r_srcR));
5170 addInstr(env, MIPSInstr_Mfhi(tHi));
5171 addInstr(env, MIPSInstr_Mflo(tLo));
5172 #endif
5173 *rHi = tHi;
5174 *rLo = tLo;
5176 return;
5179 case Iop_DivModU32to32:
5180 case Iop_DivModS32to32: {
5181 HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
5182 HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
5183 HReg tLo = newVRegI(env);
5184 HReg tHi = newVRegI(env);
5185 Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS32to32);
5187 #if (__mips_isa_rev >= 6)
5188 addInstr(env, MIPSInstr_Divr6(syned /*Unsigned or Signed */ ,
5189 True /*32bit or 64bit div */ ,
5190 False /*mod*/,
5191 tLo, r_srcL, r_srcR));
5192 addInstr(env, MIPSInstr_Divr6(syned /*Unsigned or Signed */ ,
5193 True /*32bit or 64bit div */ ,
5194 True /*mod*/,
5195 tHi, r_srcL, r_srcR));
5196 #else
5197 addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
5198 addInstr(env, MIPSInstr_Mfhi(tHi));
5199 addInstr(env, MIPSInstr_Mflo(tLo));
5200 #endif
5201 *rHi = tHi;
5202 *rLo = tLo;
5203 return;
5206 /* 32HLto64(e1,e2) */
5207 case Iop_32HLto64:
5208 *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
5209 *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
5211 return;
5212 /* Or64/And64/Xor64 */
5213 case Iop_Or64:
5214 case Iop_And64:
5215 case Iop_Xor64: {
5216 HReg xLo, xHi, yLo, yHi;
5217 HReg tLo = newVRegI(env);
5218 HReg tHi = newVRegI(env);
5219 MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR :
5220 (op_binop == Iop_And64) ? Malu_AND : Malu_XOR;
5221 iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
5222 iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
5223 addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi)));
5224 addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo)));
5225 *rHi = tHi;
5226 *rLo = tLo;
5227 return;
5230 case Iop_Shr64: {
5231 /* 64-bit logical shift right based on what gcc generates:
5232 <shift>:
5233 nor v0, zero, a2
5234 sll a3, a1, 0x1
5235 sllv a3, a3, v0
5236 srlv v0, a0, a2
5237 srlv v1, a1, a2
5238 andi a0, a2, 0x20
5239 or v0, a3, v0
5240 movn v0, v1, a0
5241 jr ra
5242 movn v1, zero, a0
5244 HReg r_srcLo, r_srcHi;
5245 HReg r_srcLotmp = newVRegI(env);
5246 HReg shift = newVRegI(env);
5247 HReg a3 = newVRegI(env);
5248 HReg r_dstLo = newVRegI(env);
5249 HReg r_dstHi = newVRegI(env);
5250 HReg zero = hregMIPS_GPR0(env->mode64);
5251 MIPSRH *sa = NULL;
5253 iselInt64Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1);
5254 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
5256 if (sa->tag == Mrh_Imm) {
5257 addInstr(env, MIPSInstr_LI(shift, sa->Mrh.Imm.imm16));
5259 else {
5260 addInstr(env, MIPSInstr_Alu(Malu_AND, shift, sa->Mrh.Reg.reg,
5261 MIPSRH_Imm(False, 0x3f)));
5263 /* nor r_dstLo, zero, shift */
5264 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dstLo, zero, MIPSRH_Reg(shift)));
5265 /* sll a3, r_srcHi, 0x1 */
5266 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
5267 a3, r_srcHi, MIPSRH_Imm(False, 0x1)));
5268 /* sllv a3, a3, r_dstLo */
5269 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
5270 a3, a3, MIPSRH_Reg(r_dstLo)));
5271 /* srlv r_dstLo, r_srcLo, shift */
5272 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
5273 r_dstLo, r_srcLo, MIPSRH_Reg(shift)));
5274 /* srlv r_dstHi, r_srcHi, shift */
5275 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
5276 r_dstHi, r_srcHi, MIPSRH_Reg(shift)));
5277 /* andi r_srcLo, shift, 0x20 */
5278 addInstr(env, MIPSInstr_Alu(Malu_AND, r_srcLotmp, shift,
5279 MIPSRH_Imm(False, 0x20)));
5280 /* or r_dstLo, a3, r_dstLo */
5281 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, a3, MIPSRH_Reg(r_dstLo)));
5282 #if (__mips_isa_rev >= 6)
5283 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstLo, r_dstLo, r_srcLotmp));
5284 addInstr(env, MIPSInstr_MoveCond(MSelnez, a3, r_dstHi, r_srcLotmp));
5285 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, r_dstLo, MIPSRH_Reg(a3)));
5287 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstHi, r_dstHi, r_srcLotmp));
5288 #else
5289 /* movn r_dstLo, r_dstHi, r_srcLo */
5290 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstLo, r_dstHi, r_srcLotmp));
5291 /* movn r_dstHi, zero, r_srcLo */
5292 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstHi, zero, r_srcLotmp));
5293 #endif
5294 *rHi = r_dstHi;
5295 *rLo = r_dstLo;
5296 return;
5299 case Iop_Shl64: {
5300 /* 64-bit shift left based on what gcc generates:
5301 <shift>:
5302 nor v0,zero,a2
5303 srl a3,a0,0x1
5304 srlv a3,a3,v0
5305 sllv v1,a1,a2
5306 andi v0,a2,0x20
5307 or v1,a3,v1
5308 sllv a2,a0,a2
5309 movn v1,a2,v0
5310 movn a2,zero,v0
5311 jr ra
5312 move v0,a2
5314 HReg r_srcLo, r_srcHi;
5315 HReg r_shift = newVRegI(env);
5316 HReg a3 = newVRegI(env);
5317 HReg r_dstLo = newVRegI(env);
5318 HReg r_dstHi = newVRegI(env);
5319 HReg zero = hregMIPS_GPR0(env->mode64);
5320 MIPSRH *sa = NULL;
5322 iselInt64Expr(&r_srcHi, &r_srcLo, env, e->Iex.Binop.arg1);
5323 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
5325 if (sa->tag == Mrh_Imm) {
5326 addInstr(env, MIPSInstr_LI(r_shift, sa->Mrh.Imm.imm16));
5328 else {
5329 addInstr(env, MIPSInstr_Alu(Malu_AND, r_shift, sa->Mrh.Reg.reg,
5330 MIPSRH_Imm(False, 0x3f)));
5332 /* nor r_dstLo, zero, r_shift */
5333 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dstLo, zero, MIPSRH_Reg(r_shift)));
5334 /* srl a3, r_srcLo, 0x1 */
5335 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
5336 a3, r_srcLo, MIPSRH_Imm(False, 0x1)));
5337 /* srlv a3, a3, r_dstLo */
5338 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
5339 a3, a3, MIPSRH_Reg(r_dstLo)));
5340 /* sllv r_dstHi, r_srcHi, r_shift */
5341 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
5342 r_dstHi, r_srcHi, MIPSRH_Reg(r_shift)));
5343 /* or r_dstHi, a3, r_dstHi */
5344 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstHi, a3, MIPSRH_Reg(r_dstHi)));
5345 /* andi a3, r_shift, 0x20 */
5346 addInstr(env, MIPSInstr_Alu(Malu_AND, a3, r_shift,
5347 MIPSRH_Imm(False, 0x20)));
5348 /* sllv r_dstLo, r_srcLo, r_shift */
5349 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
5350 r_dstLo, r_srcLo, MIPSRH_Reg(r_shift)));
5351 #if (__mips_isa_rev >= 6)
5352 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstHi, r_dstHi, a3));
5353 addInstr(env, MIPSInstr_MoveCond(MSelnez, r_shift, r_dstLo, a3));
5354 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstHi, r_dstHi, MIPSRH_Reg(r_shift)));
5356 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstLo, r_dstLo, a3));
5357 #else
5358 /* movn r_dstHi, r_dstLo, a3 */
5359 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstHi, r_dstLo, a3));
5360 /* movn r_dstLo, zero, a3 */
5361 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstLo, zero, a3));
5362 #endif
5363 *rHi = r_dstHi;
5364 *rLo = r_dstLo;
5365 return;
5368 case Iop_Sar64: {
5369 /* 64-bit arithmetic shift right based on what gcc generates:
5370 <shift>:
5371 nor v0, zero, a2
5372 sll a3, a1, 0x1
5373 sllv a3, a3, v0
5374 srlv v0, a0, a2
5375 srav v1, a1, a2
5376 andi a0, a2, 0x20
5377 sra a1, a1, 0x1f
5378 or v0, a3, v0
5379 movn v0, v1, a0
5380 jr ra
5381 movn v1, a1, a0
5383 HReg r_srcHi, r_srcLo;
5384 HReg r_srcHitmp = newVRegI(env);
5385 HReg r_srcLotmp = newVRegI(env);
5386 HReg r_shift = newVRegI(env);
5387 HReg a3 = newVRegI(env);
5388 HReg r_dstLo = newVRegI(env);
5389 HReg r_dstHi = newVRegI(env);
5390 HReg zero = hregMIPS_GPR0(env->mode64);
5391 MIPSRH *sa = NULL;
5393 iselInt64Expr(&r_srcLo, &r_srcHi, env, e->Iex.Binop.arg1);
5394 sa = iselWordExpr_RH6u(env, e->Iex.Binop.arg2);
5396 if (sa->tag == Mrh_Imm) {
5397 addInstr(env, MIPSInstr_LI(r_shift, sa->Mrh.Imm.imm16));
5399 else {
5400 addInstr(env, MIPSInstr_Alu(Malu_AND, r_shift, sa->Mrh.Reg.reg,
5401 MIPSRH_Imm(False, 0x3f)));
5403 /* nor r_dstLo, zero, r_shift */
5404 addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dstLo, zero, MIPSRH_Reg(r_shift)));
5405 /* sll a3, r_srcLo, 0x1 */
5406 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
5407 a3, r_srcLo, MIPSRH_Imm(False, 0x1)));
5408 /* sllv a3, a3, r_dstLo */
5409 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True /* 32bit shift */,
5410 a3, a3, MIPSRH_Reg(r_dstLo)));
5411 /* srlv r_dstLo, r_srcHi, r_shift */
5412 addInstr(env, MIPSInstr_Shft(Mshft_SRL, True /* 32bit shift */,
5413 r_dstLo, r_srcHi, MIPSRH_Reg(r_shift)));
5414 /* srav r_dstHi, r_srcLo, r_shift */
5415 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
5416 r_dstHi, r_srcLo, MIPSRH_Reg(r_shift)));
5417 /* andi r_srcHi, r_shift, 0x20 */
5418 addInstr(env, MIPSInstr_Alu(Malu_AND, r_srcHitmp, r_shift,
5419 MIPSRH_Imm(False, 0x20)));
5420 /* sra r_srcLo, r_srcLo, 0x1f */
5421 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True /* 32bit shift */,
5422 r_srcLotmp, r_srcLo, MIPSRH_Imm(False, 0x1f)));
5423 /* or r_dstLo, a3, r_dstLo */
5424 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, a3, MIPSRH_Reg(r_dstLo)));
5425 #if (__mips_isa_rev >= 6)
5426 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstLo, r_dstLo, r_srcHitmp));
5427 addInstr(env, MIPSInstr_MoveCond(MSelnez, a3, r_dstHi, r_srcHitmp));
5428 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstLo, r_dstLo, MIPSRH_Reg(a3)));
5430 addInstr(env, MIPSInstr_MoveCond(MSeleqz, r_dstHi, r_dstHi, r_srcHitmp));
5431 addInstr(env, MIPSInstr_MoveCond(MSelnez, a3, r_srcLotmp, r_srcHitmp));
5432 addInstr(env, MIPSInstr_Alu(Malu_OR, r_dstHi, r_dstHi, MIPSRH_Reg(a3)));
5433 #else
5434 /* movn r_dstLo, r_dstHi, r_srcHi */
5435 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstLo, r_dstHi, r_srcHitmp));
5436 /* movn r_dstHi, r_srcLo, r_srcHi */
5437 addInstr(env, MIPSInstr_MoveCond(MMoveCond_movn, r_dstHi, r_srcLotmp, r_srcHitmp));
5438 #endif
5439 *rHi = r_dstHi;
5440 *rLo = r_dstLo;
5441 return;
5444 case Iop_F32toI64S: {
5445 HReg tmpD = newVRegD(env);
5446 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
5447 HReg tLo = newVRegI(env);
5448 HReg tHi = newVRegI(env);
5449 MIPSAMode *am_addr;
5451 /* CVTLS tmpD, valF */
5452 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
5453 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLS, tmpD, valF));
5454 set_MIPS_rounding_default(env);
5456 sub_from_sp(env, 16); /* Move SP down 16 bytes */
5457 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
5459 /* store as F64 */
5460 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
5461 am_addr));
5462 /* load as 2xI32 */
5463 #if defined (_MIPSEL)
5464 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
5465 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
5466 mode64));
5467 #elif defined (_MIPSEB)
5468 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
5469 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
5470 mode64));
5471 #endif
5473 /* Reset SP */
5474 add_to_sp(env, 16);
5476 *rHi = tHi;
5477 *rLo = tLo;
5479 return;
5481 case Iop_F64toI64U: {
5482 HReg r_src;
5483 HReg tmp = newVRegV(env);
5484 vassert(has_msa);
5485 r_src = iselDblExpr( env, e->Iex.Binop.arg2);
5486 set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
5487 addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_U, MSA_F_DW, tmp, r_src));
5488 HReg r_dsth = newVRegI(env);
5489 HReg r_dstl = newVRegI(env);
5490 addInstr(env,
5491 MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_dstl, MSA_DFN_W | 0));
5492 addInstr(env,
5493 MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_dsth, MSA_DFN_W | 1));
5494 *rHi = r_dsth;
5495 *rLo = r_dstl;
5496 set_MIPS_rounding_default_MSA(env);
5497 return;
5500 case Iop_GetElem64x2: {
5501 vassert(has_msa);
5502 HReg v_src = iselV128Expr(env, e->Iex.Binop.arg1);
5503 HReg r_dstHI = newVRegI(env);
5504 HReg r_dstLO = newVRegI(env);
5505 MIPSRH *tmp = iselWordExpr_RH(env, False, e->Iex.Binop.arg2);
5507 switch (tmp->tag) {
5508 case Mrh_Imm:
5509 addInstr(env,
5510 MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dstHI,
5511 MSA_DFN_W |
5512 (((tmp->Mrh.Imm.imm16 & 0x01) << 1)
5513 + 1)));
5514 addInstr(env,
5515 MIPSInstr_MsaElm(MSA_COPY_S, v_src, r_dstLO,
5516 MSA_DFN_W |
5517 ((tmp->Mrh.Imm.imm16 & 0x01) << 1)));
5518 break;
5520 case Mrh_Reg: {
5521 HReg v_tmp = newVRegV(env);
5522 addInstr(env,
5523 MIPSInstr_Msa3R(MSA_SPLAT, MSA_D, v_tmp, v_src,
5524 tmp->Mrh.Reg.reg));
5525 addInstr(env,
5526 MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dstHI,
5527 MSA_DFN_W | 1));
5528 addInstr(env,
5529 MIPSInstr_MsaElm(MSA_COPY_S, v_tmp, r_dstLO,
5530 MSA_DFN_W));
5531 break;
5535 *rHi = r_dstHI;
5536 *rLo = r_dstLO;
5537 return;
5540 case Iop_Mul64: {
5541 HReg a_L, a_H, b_L, b_H;
5542 HReg dst_L = newVRegI(env);
5543 HReg dst_H = newVRegI(env);
5545 iselInt64Expr(&a_H, &a_L, env, e->Iex.Binop.arg1);
5546 iselInt64Expr(&b_H, &b_L, env, e->Iex.Binop.arg2);
5547 #if (__mips_isa_rev >= 6)
5548 addInstr(env, MIPSInstr_Mulr6(True, True, True,
5549 dst_H, a_H, b_L));
5550 addInstr(env, MIPSInstr_Mulr6(True, True, True,
5551 dst_L, b_H, a_L));
5552 addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H,
5553 MIPSRH_Reg(dst_L)));
5554 addInstr(env, MIPSInstr_Mulr6(False, True, False,
5555 dst_L, a_L, b_L));
5557 addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H,
5558 MIPSRH_Reg(dst_L)));
5559 addInstr(env, MIPSInstr_Mulr6(False, True, True,
5560 dst_L, a_L, b_L));
5561 #else
5562 addInstr(env, MIPSInstr_Mul(dst_H, a_H, b_L));
5563 addInstr(env, MIPSInstr_Mult(True, b_H, a_L));
5564 addInstr(env, MIPSInstr_Mflo(dst_L));
5565 addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H,
5566 MIPSRH_Reg(dst_L)));
5567 addInstr(env, MIPSInstr_Mult(False, a_L, b_L));
5568 addInstr(env, MIPSInstr_Mfhi(dst_L));
5570 addInstr(env, MIPSInstr_Alu(Malu_ADD, dst_H, dst_H,
5571 MIPSRH_Reg(dst_L)));
5572 addInstr(env, MIPSInstr_Mflo(dst_L));
5573 #endif
5574 *rHi = dst_H;
5575 *rLo = dst_L;
5576 return;
5579 case Iop_DivS64: {
5580 HReg src1_L, src1_H, src2_L, src2_H;
5581 HReg dst_L = newVRegI(env);
5582 HReg dst_H = newVRegI(env);
5583 HReg tmp1 = newVRegV(env);
5584 HReg tmp2 = newVRegV(env);
5585 vassert(has_msa);
5586 iselInt64Expr(&src1_H, &src1_L, env, e->Iex.Binop.arg1);
5587 iselInt64Expr(&src2_H, &src2_L, env, e->Iex.Binop.arg2);
5588 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src1_L, tmp1));
5589 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src1_H, tmp1, MSA_DFN_W | 1));
5590 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src2_L, tmp2));
5591 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src2_H, tmp2, MSA_DFN_W | 1));
5592 addInstr(env, MIPSInstr_Msa3R(MSA_DIVS, MSA_D, tmp1, tmp1, tmp2));
5593 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_H, MSA_DFN_W | 1));
5594 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_L, MSA_DFN_W | 0));
5595 *rHi = dst_H;
5596 *rLo = dst_L;
5597 return;
5600 case Iop_DivU64: {
5601 HReg src1_L, src1_H, src2_L, src2_H;
5602 HReg dst_L = newVRegI(env);
5603 HReg dst_H = newVRegI(env);
5604 HReg tmp1 = newVRegV(env);
5605 HReg tmp2 = newVRegV(env);
5606 vassert(has_msa);
5607 iselInt64Expr(&src1_H, &src1_L, env, e->Iex.Binop.arg1);
5608 iselInt64Expr(&src2_H, &src2_L, env, e->Iex.Binop.arg2);
5609 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src1_L, tmp1));
5610 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src1_H, tmp1, MSA_DFN_W | 1));
5611 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, src2_L, tmp2));
5612 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, src2_H, tmp2, MSA_DFN_W | 1));
5613 addInstr(env, MIPSInstr_Msa3R(MSA_DIVU, MSA_D, tmp1, tmp1, tmp2));
5614 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_H, MSA_DFN_W | 1));
5615 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp1, dst_L, MSA_DFN_W | 0));
5616 *rHi = dst_H;
5617 *rLo = dst_L;
5618 return;
5621 case Iop_F64toI64S: {
5622 HReg tmpD = newVRegD(env);
5623 HReg valF;
5624 HReg tLo = newVRegI(env);
5625 HReg tHi = newVRegI(env);
5626 MIPSAMode *am_addr;
5628 if(mode64){
5629 valF = iselFltExpr(env, e->Iex.Binop.arg2);
5630 } else {
5631 valF = iselDblExpr(env, e->Iex.Binop.arg2);
5634 /* CVTLS tmpD, valF */
5635 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
5636 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, tmpD, valF));
5637 set_MIPS_rounding_default(env);
5639 sub_from_sp(env, 16); /* Move SP down 16 bytes */
5640 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
5642 /* store as F64 */
5643 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, tmpD,
5644 am_addr));
5645 /* load as 2xI32 */
5646 #if defined (_MIPSEL)
5647 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
5648 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
5649 mode64));
5650 #elif defined (_MIPSEB)
5651 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
5652 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
5653 mode64));
5654 #endif
5656 /* Reset SP */
5657 add_to_sp(env, 16);
5659 *rHi = tHi;
5660 *rLo = tLo;
5662 return;
5665 default:
5666 break;
5670 /* --------- UNARY ops --------- */
5671 if (e->tag == Iex_Unop) {
5672 switch (e->Iex.Unop.op) {
5673 case Iop_1Sto64: {
5674 HReg tLo = newVRegI(env);
5675 HReg tHi = newVRegI(env);
5676 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
5677 HReg tmp = newVRegI(env);
5679 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src,
5680 MIPSRH_Imm(False, 31)));
5681 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
5682 MIPSRH_Imm(False, 31)));
5684 addInstr(env, mk_iMOVds_RR(tHi, tmp));
5685 addInstr(env, mk_iMOVds_RR(tLo, tmp));
5687 *rHi = tHi;
5688 *rLo = tLo;
5689 return;
5692 case Iop_8Sto64:
5693 case Iop_16Sto64: {
5694 HReg tLo = newVRegI(env);
5695 HReg tHi = newVRegI(env);
5696 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
5697 UInt no_bits = (e->Iex.Unop.op == Iop_8Sto64) ? 24 : 16;
5698 addInstr(env, mk_iMOVds_RR(tLo, src));
5699 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tLo, tLo,
5700 MIPSRH_Imm(False, no_bits)));
5701 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tLo,
5702 MIPSRH_Imm(False, 31)));
5703 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tLo, tLo,
5704 MIPSRH_Imm(False, no_bits)));
5705 addInstr(env, mk_iMOVds_RR(tHi, tLo));
5706 *rHi = tHi;
5707 *rLo = tLo;
5708 return;
5711 /* 32Sto64(e) */
5712 case Iop_32Sto64: {
5713 HReg tLo = newVRegI(env);
5714 HReg tHi = newVRegI(env);
5715 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
5716 addInstr(env, mk_iMOVds_RR(tHi, src));
5717 addInstr(env, mk_iMOVds_RR(tLo, src));
5718 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi,
5719 MIPSRH_Imm(False, 31)));
5720 *rHi = tHi;
5721 *rLo = tLo;
5722 return;
5725 case Iop_8Uto64:
5726 case Iop_16Uto64: {
5727 HReg tLo = newVRegI(env);
5728 HReg tHi = newVRegI(env);
5729 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
5730 UInt mask = (e->Iex.Unop.op == Iop_8Sto64) ? 0xFF : 0xFFFF;
5731 addInstr(env, MIPSInstr_Alu(Malu_AND, tLo, src,
5732 MIPSRH_Imm(False, mask)));
5733 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
5734 MIPSRH_Reg(hregMIPS_GPR0(mode64))));
5735 *rHi = tHi;
5736 *rLo = tLo;
5737 return;
5740 /* 32Uto64(e) */
5741 case Iop_32Uto64: {
5742 HReg tLo = newVRegI(env);
5743 HReg tHi = newVRegI(env);
5744 HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
5745 addInstr(env, mk_iMOVds_RR(tLo, src));
5746 addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
5747 MIPSRH_Reg(hregMIPS_GPR0(mode64))));
5748 *rHi = tHi;
5749 *rLo = tLo;
5750 return;
5753 case Iop_Left64: {
5754 HReg yHi, yLo;
5755 HReg tHi = newVRegI(env);
5756 HReg tLo = newVRegI(env);
5757 HReg tmp = newVRegI(env);
5758 HReg tmp1 = newVRegI(env);
5759 HReg tmp2 = newVRegI(env);
5760 HReg zero = newVRegI(env);
5761 MIPSCondCode cc = MIPScc_LO;
5763 /* yHi:yLo = arg */
5764 iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
5765 /* zero = 0 */
5766 addInstr(env, MIPSInstr_LI(zero, 0x00000000));
5768 /* tmp2:tmp1 = 0 - (yHi:yLo)*/
5769 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, zero, MIPSRH_Reg(yLo)));
5770 addInstr(env, MIPSInstr_Cmp(False, True, tmp1, zero, tmp2, cc));
5771 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, zero, MIPSRH_Reg(yHi)));
5772 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp1, tmp, MIPSRH_Reg(tmp1)));
5774 /* So now we have tmp2:tmp1 = -arg. To finish off, or 'arg'
5775 back in, so as to give the final result
5776 tHi:tLo = arg | -arg. */
5777 addInstr(env, MIPSInstr_Alu(Malu_OR, tHi, yHi, MIPSRH_Reg(tmp1)));
5778 addInstr(env, MIPSInstr_Alu(Malu_OR, tLo, yLo, MIPSRH_Reg(tmp2)));
5779 *rHi = tHi;
5780 *rLo = tLo;
5781 return;
5784 case Iop_CmpwNEZ64: {
5785 HReg srcLo, srcHi;
5786 HReg tmp1 = newVRegI(env);
5787 HReg tmp2 = newVRegI(env);
5788 /* srcHi:srcLo = arg */
5789 iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
5790 /* tmp1 = srcHi | srcLo */
5791 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo,
5792 MIPSRH_Reg(srcHi)));
5793 /* tmp2 = (tmp1 | -tmp1) >>s 31 */
5795 addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
5796 MIPSRH_Reg(tmp1)));
5798 addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
5799 addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2,
5800 MIPSRH_Imm(False, 31)));
5801 *rHi = tmp2;
5802 *rLo = tmp2;
5803 return;
5806 case Iop_ReinterpF64asI64: {
5807 HReg tLo = newVRegI(env);
5808 HReg tHi = newVRegI(env);
5809 MIPSAMode *am_addr;
5810 HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
5812 sub_from_sp(env, 16); /* Move SP down 16 bytes */
5813 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
5815 /* store as F64 */
5816 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
5817 am_addr));
5818 /* load as 2xI32 */
5819 #if defined (_MIPSEL)
5820 addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
5821 addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
5822 mode64));
5823 #elif defined (_MIPSEB)
5824 addInstr(env, MIPSInstr_Load(4, tHi, am_addr, mode64));
5825 addInstr(env, MIPSInstr_Load(4, tLo, nextMIPSAModeFloat(am_addr),
5826 mode64));
5827 #endif
5829 /* Reset SP */
5830 add_to_sp(env, 16);
5832 *rHi = tHi;
5833 *rLo = tLo;
5834 return;
5837 case Iop_Not64: {
5838 HReg tLo = newVRegI(env);
5839 HReg tHi = newVRegI(env);
5840 iselInt64Expr(&tHi, &tLo, env, e->Iex.Unop.arg);
5841 addInstr(env, MIPSInstr_Alu(Malu_NOR, tLo, tLo, MIPSRH_Reg(tLo)));
5842 addInstr(env, MIPSInstr_Alu(Malu_NOR, tHi, tHi, MIPSRH_Reg(tHi)));
5844 *rHi = tHi;
5845 *rLo = tLo;
5846 return;
5849 case Iop_V128HIto64: {
5850 vassert(has_msa);
5851 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
5852 HReg tLo = newVRegI(env);
5853 HReg tHi = newVRegI(env);
5854 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tLo, MSA_DFN_W | 2));
5855 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tHi, MSA_DFN_W | 3));
5856 *rLo = tLo;
5857 *rHi = tHi;
5858 return;
5861 case Iop_V128to64: {
5862 vassert(has_msa);
5863 HReg v_src = iselV128Expr(env, e->Iex.Unop.arg);
5864 HReg tLo = newVRegI(env);
5865 HReg tHi = newVRegI(env);
5866 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tLo, MSA_DFN_W | 0));
5867 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tHi, MSA_DFN_W | 1));
5868 *rLo = tLo;
5869 *rHi = tHi;
5870 return;
5873 case Iop_F32toF16x4_DEP: {
5874 vassert(has_msa);
5875 HReg v_arg = iselV128Expr(env, e->Iex.Unop.arg);
5876 HReg v_src = newVRegV(env);
5877 set_guest_MIPS_rounding_mode_MSA(env);
5878 addInstr(env, MIPSInstr_Msa3RF(MSA_FEXDO, MSA_F_WH, v_src, v_arg, v_arg));
5879 set_MIPS_rounding_default_MSA(env);
5880 HReg tLo = newVRegI(env);
5881 HReg tHi = newVRegI(env);
5882 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tLo, MSA_DFN_W | 0));
5883 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, v_src, tHi, MSA_DFN_W | 1));
5884 *rLo = tLo;
5885 *rHi = tHi;
5886 return;
5889 default:
5890 vex_printf("UNARY: No such op: ");
5891 ppIROp(e->Iex.Unop.op);
5892 vex_printf("\n");
5893 break;
5897 vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag);
5898 ppIRExpr(e);
5899 vpanic("iselInt64Expr(mips)");
5902 /*---------------------------------------------------------*/
5903 /*--- ISEL: Floating point expressions (32 bit) ---*/
5904 /*---------------------------------------------------------*/
5906 /* Nothing interesting here; really just wrappers for
5907 64-bit stuff. */
5908 static HReg iselFltExpr(ISelEnv * env, IRExpr * e)
5910 HReg r;
5911 IRType ty = typeOfIRExpr(env->type_env, e);
5912 if (ty == Ity_F32 || (ty == Ity_F64 && fp_mode64)) {
5913 r = iselFltExpr_wrk(env, e);
5914 } else {
5915 r = iselDblExpr_wrk(env, e);
5916 vassert(hregClass(r) == HRcFlt64);
5918 return r;
5921 /* DO NOT CALL THIS DIRECTLY */
5922 static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
5924 IRType ty = typeOfIRExpr(env->type_env, e);
5925 vassert(ty == Ity_F32 || (ty == Ity_F64 && fp_mode64));
5927 if (e->tag == Iex_RdTmp) {
5928 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
5931 if (e->tag == Iex_Load) {
5932 vassert(e->Iex.Load.ty == Ity_F32
5933 || (e->Iex.Load.ty == Ity_F64 && fp_mode64));
5934 HReg r_dst;
5935 MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
5936 if (e->Iex.Load.ty == Ity_F64) {
5937 r_dst = newVRegD(env);
5938 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
5939 } else {
5940 r_dst = newVRegF(env);
5941 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
5943 return r_dst;
5946 if (e->tag == Iex_Get) {
5947 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
5948 GuestStatePointer(mode64));
5949 HReg r_dst;
5950 if (e->Iex.Load.ty == Ity_F64) {
5951 r_dst = newVRegD(env);
5952 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
5953 } else {
5954 r_dst = newVRegF(env);
5955 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 4, r_dst, am_addr));
5957 return r_dst;
5960 if (e->tag == Iex_Unop) {
5961 switch (e->Iex.Unop.op) {
5962 case Iop_ReinterpI32asF32: {
5963 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
5964 HReg r_dst = newVRegF(env);
5966 /* Move Word to Floating Point
5967 mtc1 r_dst, valS */
5968 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, fr_src));
5970 return r_dst;
5972 case Iop_F32toF64: {
5973 vassert(fp_mode64);
5974 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
5975 HReg dst = newVRegD(env);
5977 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
5978 return dst;
5980 case Iop_ReinterpI64asF64: {
5981 HReg r_dst;
5982 if (mode64) {
5983 HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
5984 r_dst = newVRegF(env);
5985 /* Move Doubleword to Floating Point
5986 dmtc1 r_dst, fr_src */
5987 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_dmtc1, r_dst, fr_src));
5988 } else {
5989 HReg Hi, Lo;
5990 r_dst = newVRegD(env);
5991 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
5992 r_dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
5994 return r_dst;
5996 case Iop_I32StoF64: {
5997 vassert(fp_mode64);
5998 HReg dst = newVRegF(env);
5999 HReg tmp = newVRegF(env);
6000 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
6002 /* Move Word to Floating Point
6003 mtc1 tmp, r_src */
6004 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
6006 /* and do convert */
6007 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
6009 return dst;
6011 case Iop_AbsF32:
6012 case Iop_AbsF64: {
6013 Bool sz32 = e->Iex.Unop.op == Iop_AbsF32;
6014 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6015 HReg dst = newVRegF(env);
6016 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src));
6017 return dst;
6019 case Iop_NegF32:
6020 case Iop_NegF64: {
6021 Bool sz32 = e->Iex.Unop.op == Iop_NegF32;
6022 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6023 HReg dst = newVRegF(env);
6024 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src));
6025 return dst;
6027 case Iop_RoundF64toF64_ZERO: {
6028 vassert(mode64);
6029 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6030 HReg dst = newVRegF(env);
6031 addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, dst, src));
6032 return dst;
6034 case Iop_RoundF64toF64_NEAREST: {
6035 vassert(mode64);
6036 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6037 HReg dst = newVRegF(env);
6038 addInstr(env, MIPSInstr_FpConvert(Mfp_ROUNDLD, dst, src));
6039 return dst;
6041 case Iop_RoundF64toF64_NegINF: {
6042 vassert(mode64);
6043 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6044 HReg dst = newVRegF(env);
6045 addInstr(env, MIPSInstr_FpConvert(Mfp_FLOORLD, dst, src));
6046 return dst;
6048 case Iop_RoundF64toF64_PosINF: {
6049 vassert(mode64);
6050 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6051 HReg dst = newVRegF(env);
6052 addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, dst, src));
6053 return dst;
6056 default:
6057 break;
6061 if (e->tag == Iex_Triop) {
6062 switch (e->Iex.Triop.details->op) {
6063 case Iop_DivF32:
6064 case Iop_DivF64:
6065 case Iop_MulF32:
6066 case Iop_MulF64:
6067 case Iop_AddF32:
6068 case Iop_AddF64:
6069 case Iop_SubF32:
6070 case Iop_SubF64: {
6071 MIPSFpOp op = 0;
6072 HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2);
6073 HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3);
6074 HReg dst = newVRegF(env);
6075 switch (e->Iex.Triop.details->op) {
6076 case Iop_DivF32:
6077 op = Mfp_DIVS;
6078 break;
6079 case Iop_DivF64:
6080 vassert(fp_mode64);
6081 op = Mfp_DIVD;
6082 break;
6083 case Iop_MulF32:
6084 op = Mfp_MULS;
6085 break;
6086 case Iop_MulF64:
6087 vassert(fp_mode64);
6088 op = Mfp_MULD;
6089 break;
6090 case Iop_AddF32:
6091 op = Mfp_ADDS;
6092 break;
6093 case Iop_AddF64:
6094 vassert(fp_mode64);
6095 op = Mfp_ADDD;
6096 break;
6097 case Iop_SubF32:
6098 op = Mfp_SUBS;
6099 break;
6100 case Iop_SubF64:
6101 vassert(fp_mode64);
6102 op = Mfp_SUBD;
6103 break;
6104 default:
6105 vassert(0);
6107 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
6108 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
6109 set_MIPS_rounding_default(env);
6110 return dst;
6112 case Iop_ScaleF64: {
6113 HReg src1 = iselFltExpr(env, e->Iex.Triop.details->arg2);
6114 HReg src2 = iselFltExpr(env, e->Iex.Triop.details->arg3);
6115 HReg v_help = newVRegV(env);
6116 HReg dst = newVRegF(env);
6117 vassert(has_msa);
6118 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
6119 addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_S, MSA_F_DW, v_help, src2));
6120 addInstr(env, MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_DW, dst, src1, v_help));
6121 set_MIPS_rounding_default_MSA(env);
6123 return dst;
6125 default:
6126 break;
6130 if (e->tag == Iex_Binop) {
6131 switch (e->Iex.Binop.op) {
6132 case Iop_F64toF32: {
6133 HReg valD;
6134 if (mode64)
6135 valD = iselFltExpr(env, e->Iex.Binop.arg2);
6136 else
6137 valD = iselDblExpr(env, e->Iex.Binop.arg2);
6138 HReg valS = newVRegF(env);
6140 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6141 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD));
6142 set_MIPS_rounding_default(env);
6143 return valS;
6146 case Iop_RoundF32toInt: {
6147 HReg valS = newVRegF(env);
6148 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
6150 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6151 #if (__mips_isa_rev >= 6)
6152 addInstr(env, MIPSInstr_FpConvert(Mfp_RINTS, valS, valF));
6153 #else
6154 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
6155 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, valS, valS));
6156 #endif
6157 set_MIPS_rounding_default(env);
6158 return valS;
6161 case Iop_RoundF64toInt: {
6162 HReg valS = newVRegF(env);
6163 HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
6165 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6166 #if (__mips_isa_rev >= 6)
6167 addInstr(env, MIPSInstr_FpConvert(Mfp_RINTD, valS, valF));
6168 #else
6169 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, valS, valF));
6170 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, valS, valS));
6172 #endif
6173 set_MIPS_rounding_default(env);
6174 return valS;
6177 case Iop_I32StoF32: {
6178 HReg r_dst = newVRegF(env);
6179 HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
6180 HReg tmp = newVRegF(env);
6182 /* Move Word to Floating Point
6183 mtc1 tmp, fr_src */
6184 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, fr_src));
6186 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6187 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp));
6188 set_MIPS_rounding_default(env);
6190 return r_dst;
6193 case Iop_I64StoF64: {
6194 HReg r_dst = newVRegF(env);
6195 MIPSAMode *am_addr;
6196 HReg tmp, fr_src;
6197 if (mode64) {
6198 tmp = newVRegF(env);
6199 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
6200 /* Move SP down 8 bytes */
6201 sub_from_sp(env, 8);
6202 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
6204 /* store as I64 */
6205 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
6207 /* load as Ity_F64 */
6208 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
6210 /* Reset SP */
6211 add_to_sp(env, 8);
6212 } else {
6213 HReg Hi, Lo;
6214 tmp = newVRegD(env);
6215 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
6216 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
6219 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6220 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
6221 set_MIPS_rounding_default(env);
6223 return r_dst;
6226 case Iop_I64StoF32: {
6227 HReg r_dst = newVRegF(env);
6228 MIPSAMode *am_addr;
6229 HReg fr_src, tmp;
6230 if (mode64) {
6231 tmp = newVRegF(env);
6232 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
6233 /* Move SP down 8 bytes */
6234 sub_from_sp(env, 8);
6235 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
6237 /* store as I64 */
6238 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
6240 /* load as Ity_F64 */
6241 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
6243 /* Reset SP */
6244 add_to_sp(env, 8);
6245 } else {
6246 HReg Hi, Lo;
6247 tmp = newVRegD(env);
6248 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
6249 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
6252 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6253 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSL, r_dst, tmp));
6254 set_MIPS_rounding_default(env);
6256 return r_dst;
6259 case Iop_SqrtF32:
6260 case Iop_SqrtF64: {
6261 Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32;
6262 HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
6263 HReg dst = newVRegF(env);
6264 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6265 addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst,
6266 src));
6267 set_MIPS_rounding_default(env);
6268 return dst;
6271 case Iop_I64UtoF64: {
6272 vassert(mode64);
6273 HReg r_dst = newVRegF(env);
6274 HReg tmp = newVRegV(env);
6275 HReg r_src;
6276 vassert(has_msa);
6277 r_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
6278 set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
6279 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_D, r_src, tmp));
6280 HReg r_srch = newVRegI(env);
6281 addInstr(env, MIPSInstr_Msa2RF(MSA_FFINT_U, MSA_F_DW, tmp, tmp));
6282 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_srch, MSA_DFN_D | 0));
6283 sub_from_sp(env, 8);
6284 MIPSAMode *am_addr = MIPSAMode_IR(0, StackPointer(mode64));
6286 /* store as I64 */
6287 addInstr(env, MIPSInstr_Store(8, am_addr, r_srch, mode64));
6289 /* load as Ity_F64 */
6290 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, r_dst, am_addr));
6292 /* Reset SP */
6293 add_to_sp(env, 8);
6294 set_MIPS_rounding_default_MSA(env);
6295 return r_dst;
6298 #if (__mips_isa_rev >= 6)
6299 case Iop_MaxNumF32: {
6300 HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1);
6301 HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2);
6302 HReg dst = newVRegF(env);
6303 addInstr(env, MIPSInstr_FpMinMax(Mfp_MAXS, dst,
6304 src1, src2));
6305 return dst;
6308 case Iop_MaxNumF64: {
6309 HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1);
6310 HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2);
6311 HReg dst = newVRegF(env);
6312 addInstr(env, MIPSInstr_FpMinMax(Mfp_MAXD, dst,
6313 src1, src2));
6314 return dst;
6317 case Iop_MinNumF32: {
6318 HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1);
6319 HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2);
6320 HReg dst = newVRegF(env);
6321 addInstr(env, MIPSInstr_FpMinMax(Mfp_MINS, dst,
6322 src1, src2));
6323 return dst;
6326 case Iop_MinNumF64: {
6327 HReg src1 = iselFltExpr(env, e->Iex.Binop.arg1);
6328 HReg src2 = iselFltExpr(env, e->Iex.Binop.arg2);
6329 HReg dst = newVRegF(env);
6330 addInstr(env, MIPSInstr_FpMinMax(Mfp_MIND, dst,
6331 src1, src2));
6332 return dst;
6334 #endif
6335 default:
6336 break;
6340 if (e->tag == Iex_Qop) {
6341 switch (e->Iex.Qop.details->op) {
6342 case Iop_MAddF32:
6343 case Iop_MAddF64:
6344 case Iop_MSubF32:
6345 case Iop_MSubF64: {
6346 Int op = 0;
6347 #if (__mips_isa_rev < 6)
6348 MSADFFlx type = 0;
6349 #endif
6350 switch (e->Iex.Qop.details->op) {
6351 #if (__mips_isa_rev >= 6)
6352 case Iop_MAddF32:
6353 op = Mfp_MADDS;
6354 break;
6355 case Iop_MAddF64:
6356 op = Mfp_MADDD;
6357 break;
6358 case Iop_MSubF32:
6359 op = Mfp_MSUBS;
6360 break;
6361 case Iop_MSubF64:
6362 op = Mfp_MSUBD;
6363 break;
6364 #else
6365 case Iop_MAddF32:
6366 op = has_msa ? MSA_FMADD : Mfp_MADDS;
6367 type = MSA_F_WH;
6368 break;
6369 case Iop_MAddF64:
6370 op = has_msa ? MSA_FMADD : Mfp_MADDD;
6371 type = MSA_F_DW;
6372 break;
6373 case Iop_MSubF32:
6374 op = has_msa ? MSA_FMSUB : Mfp_MSUBS;
6375 type = MSA_F_WH;
6376 break;
6377 case Iop_MSubF64:
6378 op = has_msa ? MSA_FMSUB : Mfp_MSUBD;
6379 type = MSA_F_DW;
6380 break;
6381 #endif
6382 default:
6383 vassert(0);
6386 HReg dst = newVRegF(env);
6387 HReg src1 = iselFltExpr(env, e->Iex.Qop.details->arg2);
6388 HReg src2 = iselFltExpr(env, e->Iex.Qop.details->arg3);
6389 HReg src3 = iselFltExpr(env, e->Iex.Qop.details->arg4);
6390 #if (__mips_isa_rev >= 6)
6391 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
6392 addInstr(env, MIPSInstr_FpTernary(op, dst,
6393 src3, src1, src2));
6394 set_MIPS_rounding_default(env);
6395 #else
6396 if (has_msa) {
6397 addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, src3, dst, 0));
6398 set_MIPS_rounding_mode_MSA(env, e->Iex.Qop.details->arg1);
6399 addInstr(env, MIPSInstr_Msa3RF(op, type, dst, src1, src2));
6400 set_MIPS_rounding_default_MSA(env);
6401 } else {
6402 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
6403 addInstr(env, MIPSInstr_FpTernary(op, dst,
6404 src1, src2, src3));
6405 set_MIPS_rounding_default(env);
6407 #endif
6408 return dst;
6411 default:
6412 break;
6416 if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
6417 /* This is quite subtle. The only way to do the relevant
6418 truncation is to do a single-precision store and then a
6419 double precision load to get it back into a register. The
6420 problem is, if the data is then written to memory a second
6421 time, as in
6423 STbe(...) = TruncF64asF32(...)
6425 then will the second truncation further alter the value? The
6426 answer is no: flds (as generated here) followed by fsts
6427 (generated for the STbe) is the identity function on 32-bit
6428 floats, so we are safe.
6430 Another upshot of this is that if iselStmt can see the
6431 entirety of
6433 STbe(...) = TruncF64asF32(arg)
6435 then it can short circuit having to deal with TruncF64asF32
6436 individually; instead just compute arg into a 64-bit FP
6437 register and do 'fsts' (since that itself does the
6438 truncation).
6440 We generate pretty poor code here (should be ok both for
6441 32-bit and 64-bit mode); but it is expected that for the most
6442 part the latter optimisation will apply and hence this code
6443 will not often be used.
6445 HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
6446 HReg fdst = newVRegF(env);
6447 MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64));
6449 sub_from_sp(env, 16);
6450 /* store as F32, hence truncating */
6451 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1));
6452 /* and reload. Good huh?! (sigh) */
6453 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1));
6454 add_to_sp(env, 16);
6455 return fdst;
6458 /* --------- ITE --------- */
6459 if (e->tag == Iex_ITE) {
6460 vassert(typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1);
6461 HReg r0 = iselFltExpr(env, e->Iex.ITE.iffalse);
6462 HReg r1 = iselFltExpr(env, e->Iex.ITE.iftrue);
6463 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
6464 HReg r_dst = newVRegF(env);
6465 #if (__mips_isa_rev >= 6)
6466 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, r_cond));
6467 addInstr(env, MIPSInstr_MoveCond(MFpSeld, r_dst, r0, r1));
6468 #else
6469 addInstr(env, MIPSInstr_FpUnary((ty == Ity_F64) ? Mfp_MOVD : Mfp_MOVS,
6470 r_dst, r0));
6471 addInstr(env, MIPSInstr_MoveCond((ty == Ity_F64) ? MFpMoveCond_movnd :
6472 MFpMoveCond_movns,
6473 r_dst, r1, r_cond));
6474 #endif
6475 return r_dst;
6478 vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag);
6479 ppIRExpr(e);
6480 vpanic("iselFltExpr_wrk(mips)");
6483 static HReg iselDblExpr(ISelEnv * env, IRExpr * e)
6485 HReg r = iselDblExpr_wrk(env, e);
6486 vassert(hregClass(r) == HRcFlt64);
6487 vassert(hregIsVirtual(r));
6488 return r;
6491 /* DO NOT CALL THIS DIRECTLY */
6492 static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e)
6494 IRType ty = typeOfIRExpr(env->type_env, e);
6495 vassert(e);
6496 vassert(ty == Ity_F64);
6498 if (e->tag == Iex_RdTmp) {
6499 return lookupIRTemp(env, e->Iex.RdTmp.tmp);
6502 /* --------- LOAD --------- */
6503 if (e->tag == Iex_Load) {
6504 HReg r_dst = newVRegD(env);
6505 MIPSAMode *am_addr;
6506 vassert(e->Iex.Load.ty == Ity_F64);
6507 am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
6508 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
6509 return r_dst;
6512 /* --------- GET --------- */
6513 if (e->tag == Iex_Get) {
6515 HReg r_dst = newVRegD(env);
6516 MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
6517 GuestStatePointer(mode64));
6518 addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
6519 return r_dst;
6522 if (e->tag == Iex_Unop) {
6523 MIPSFpOp fpop = Mfp_INVALID;
6524 switch (e->Iex.Unop.op) {
6525 case Iop_NegF64:
6526 fpop = Mfp_NEGD;
6527 break;
6528 case Iop_AbsF64:
6529 fpop = Mfp_ABSD;
6530 break;
6531 case Iop_F32toF64: {
6532 vassert(!mode64);
6533 HReg src = iselFltExpr(env, e->Iex.Unop.arg);
6534 HReg dst = newVRegD(env);
6536 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDS, dst, src));
6537 return dst;
6539 case Iop_ReinterpI64asF64: {
6540 HReg Hi, Lo;
6541 HReg dst = newVRegD(env);
6543 iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
6545 dst = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
6546 return dst;
6548 case Iop_I32StoF64: {
6549 vassert(!mode64);
6550 HReg dst = newVRegD(env);
6551 HReg tmp = newVRegF(env);
6552 HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
6554 /* Move Word to Floating Point
6555 mtc1 tmp, r_src */
6556 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, tmp, r_src));
6558 /* and do convert */
6559 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp));
6561 return dst;
6563 default:
6564 break;
6567 if (fpop != Mfp_INVALID) {
6568 HReg src = iselDblExpr(env, e->Iex.Unop.arg);
6569 HReg dst = newVRegD(env);
6570 addInstr(env, MIPSInstr_FpUnary(fpop, dst, src));
6571 return dst;
6575 if (e->tag == Iex_Binop) {
6576 switch (e->Iex.Binop.op) {
6577 case Iop_RoundF64toInt: {
6578 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
6579 HReg dst = newVRegD(env);
6581 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6582 #if (__mips_isa_rev >= 6)
6583 addInstr(env, MIPSInstr_FpConvert(Mfp_RINTD, dst, src));
6584 #else
6585 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTLD, dst, src));
6586 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, dst, dst));
6588 #endif
6589 set_MIPS_rounding_default(env);
6591 return dst;
6594 case Iop_SqrtF64: {
6595 HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
6596 HReg dst = newVRegD(env);
6597 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6598 addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src));
6599 set_MIPS_rounding_default(env);
6600 return dst;
6603 case Iop_I64StoF64: {
6604 HReg r_dst = newVRegD(env);
6605 MIPSAMode *am_addr;
6606 HReg tmp, fr_src;
6607 if (mode64) {
6608 tmp = newVRegD(env);
6609 fr_src = iselDblExpr(env, e->Iex.Binop.arg2);
6610 /* Move SP down 8 bytes */
6611 sub_from_sp(env, 8);
6612 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
6614 /* store as I64 */
6615 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
6617 /* load as Ity_F64 */
6618 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
6620 /* Reset SP */
6621 add_to_sp(env, 8);
6622 } else {
6623 HReg Hi, Lo;
6624 tmp = newVRegD(env);
6625 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
6626 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
6629 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6630 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
6631 set_MIPS_rounding_default(env);
6633 return r_dst;
6636 case Iop_I64UtoF64: {
6637 HReg r_dst;
6638 HReg tmp = newVRegV(env);
6639 HReg r_src2h, r_src2l;
6640 vassert(has_msa);
6641 iselInt64Expr(&r_src2h, &r_src2l, env, e->Iex.Binop.arg2);
6642 set_MIPS_rounding_mode_MSA(env, e->Iex.Binop.arg1);
6643 addInstr(env, MIPSInstr_Msa2R(MSA_FILL, MSA_W, r_src2l, tmp));
6644 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_src2h, tmp, MSA_DFN_W | 1));
6645 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_src2l, tmp, MSA_DFN_W | 2));
6646 addInstr(env, MIPSInstr_MsaElm(MSA_INSERT, r_src2h, tmp, MSA_DFN_W | 3));
6647 HReg r_srchh = newVRegI(env);
6648 HReg r_srchl = newVRegI(env);
6649 addInstr(env, MIPSInstr_Msa2RF(MSA_FFINT_U, MSA_F_DW, tmp, tmp));
6650 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_srchl, MSA_DFN_W | 0));
6651 addInstr(env, MIPSInstr_MsaElm(MSA_COPY_S, tmp, r_srchh, MSA_DFN_W | 1));
6652 r_dst = mk_LoadRR32toFPR(env, r_srchh, r_srchl);
6653 set_MIPS_rounding_default_MSA(env);
6654 return r_dst;
6656 #if (__mips_isa_rev >= 6)
6657 case Iop_MaxNumF64: {
6658 HReg src1 = iselDblExpr(env, e->Iex.Binop.arg1);
6659 HReg src2 = iselDblExpr(env, e->Iex.Binop.arg2);
6660 HReg dst = newVRegD(env);
6661 addInstr(env, MIPSInstr_FpMinMax(Mfp_MAXD, dst,
6662 src1, src2));
6663 return dst;
6666 case Iop_MinNumF64: {
6667 HReg src1 = iselDblExpr(env, e->Iex.Binop.arg1);
6668 HReg src2 = iselDblExpr(env, e->Iex.Binop.arg2);
6669 HReg dst = newVRegD(env);
6670 addInstr(env, MIPSInstr_FpMinMax(Mfp_MIND, dst,
6671 src1, src2));
6672 return dst;
6674 #endif
6676 default:
6677 break;
6682 if (e->tag == Iex_Triop) {
6683 switch (e->Iex.Triop.details->op) {
6684 case Iop_DivF64:
6685 case Iop_DivF32:
6686 case Iop_MulF64:
6687 case Iop_AddF64:
6688 case Iop_SubF64: {
6689 MIPSFpOp op = 0;
6690 HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2);
6691 HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3);
6692 HReg dst = newVRegD(env);
6693 switch (e->Iex.Triop.details->op) {
6694 case Iop_DivF64:
6695 op = Mfp_DIVD;
6696 break;
6697 case Iop_DivF32:
6698 op = Mfp_DIVS;
6699 break;
6700 case Iop_MulF64:
6701 op = Mfp_MULD;
6702 break;
6703 case Iop_AddF64:
6704 op = Mfp_ADDD;
6705 break;
6706 case Iop_SubF64:
6707 op = Mfp_SUBD;
6708 break;
6709 default:
6710 vassert(0);
6712 set_MIPS_rounding_mode(env, e->Iex.Triop.details->arg1);
6713 addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
6714 set_MIPS_rounding_default(env);
6715 return dst;
6718 case Iop_ScaleF64: {
6719 HReg src1 = iselDblExpr(env, e->Iex.Triop.details->arg2);
6720 HReg src2 = iselDblExpr(env, e->Iex.Triop.details->arg3);
6721 HReg v_help = newVRegV(env);
6722 HReg dst = newVRegD(env);
6723 vassert(has_msa);
6724 set_MIPS_rounding_mode_MSA(env, e->Iex.Triop.details->arg1);
6725 addInstr(env, MIPSInstr_Msa2RF(MSA_FTINT_S, MSA_F_DW, v_help, src2));
6726 addInstr(env, MIPSInstr_Msa3RF(MSA_FEXP2, MSA_F_DW, dst, src1, v_help));
6727 set_MIPS_rounding_default_MSA(env);
6728 return dst;
6730 default:
6731 break;
6735 if (e->tag == Iex_Qop) {
6736 switch (e->Iex.Qop.details->op) {
6737 case Iop_MAddF64:
6738 case Iop_MSubF64: {
6739 MSA3RFOp op = 0;
6740 switch (e->Iex.Qop.details->op) {
6741 #if (__mips_isa_rev >= 6)
6742 case Iop_MAddF64:
6743 op = Mfp_MADDD;
6744 break;
6745 case Iop_MSubF64:
6746 op = Mfp_MSUBD;
6747 break;
6748 #else
6749 case Iop_MAddF64:
6750 op = MSA_FMADD;
6751 break;
6752 case Iop_MSubF64:
6753 op = MSA_FMSUB;
6754 break;
6755 #endif
6756 default:
6757 vassert(0);
6759 HReg dst = newVRegD(env);
6760 HReg src1 = iselDblExpr(env, e->Iex.Qop.details->arg2);
6761 HReg src2 = iselDblExpr(env, e->Iex.Qop.details->arg3);
6762 HReg src3 = iselDblExpr(env, e->Iex.Qop.details->arg4);
6763 #if (__mips_isa_rev >= 6)
6764 set_MIPS_rounding_mode(env, e->Iex.Qop.details->arg1);
6765 addInstr(env, MIPSInstr_FpTernary(op, dst,
6766 src3, src1, src2));
6767 set_MIPS_rounding_default(env);
6768 #else
6769 vassert(has_msa);
6770 addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, src3, dst, 0));
6771 set_MIPS_rounding_mode_MSA(env, e->Iex.Qop.details->arg1);
6772 addInstr(env, MIPSInstr_Msa3RF(op, MSA_F_DW, dst, src1, src2));
6773 set_MIPS_rounding_default_MSA(env);
6774 #endif
6775 return dst;
6777 case Iop_I64StoF64: {
6778 HReg r_dst = newVRegD(env);
6779 MIPSAMode *am_addr;
6780 HReg tmp, fr_src;
6781 if (mode64) {
6782 tmp = newVRegF(env);
6783 fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
6784 /* Move SP down 8 bytes */
6785 sub_from_sp(env, 8);
6786 am_addr = MIPSAMode_IR(0, StackPointer(mode64));
6788 /* store as I64 */
6789 addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
6791 /* load as Ity_F64 */
6792 addInstr(env, MIPSInstr_FpLdSt(True /*load */, 8, tmp, am_addr));
6794 /* Reset SP */
6795 add_to_sp(env, 8);
6796 } else {
6797 HReg Hi, Lo;
6798 tmp = newVRegD(env);
6799 iselInt64Expr(&Hi, &Lo, env, e->Iex.Binop.arg2);
6800 tmp = mk_LoadRR32toFPR(env, Hi, Lo); /* 2*I32 -> F64 */
6803 set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
6804 addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDL, r_dst, tmp));
6805 set_MIPS_rounding_default(env);
6807 return r_dst;
6810 default:
6811 break;
6815 /* --------- ITE --------- */
6816 if (e->tag == Iex_ITE) {
6817 if (ty == Ity_F64
6818 && typeOfIRExpr(env->type_env, e->Iex.ITE.cond) == Ity_I1) {
6819 HReg r0 = iselDblExpr(env, e->Iex.ITE.iffalse);
6820 HReg r1 = iselDblExpr(env, e->Iex.ITE.iftrue);
6821 HReg r_cond = iselWordExpr_R(env, e->Iex.ITE.cond);
6822 HReg r_dst = newVRegD(env);
6823 #if (__mips_isa_rev >= 6)
6824 addInstr(env, MIPSInstr_FpGpMove(MFpGpMove_mtc1, r_dst, r_cond));
6825 addInstr(env, MIPSInstr_MoveCond(MFpSeld, r_dst, r0, r1));
6826 #else
6827 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, r_dst, r0));
6828 addInstr(env, MIPSInstr_MoveCond(MFpMoveCond_movnd, r_dst, r1,
6829 r_cond));
6830 #endif
6831 return r_dst;
6835 vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag);
6836 ppIRExpr(e);
6837 vpanic("iselDblExpr_wrk(mips)");
6840 /*---------------------------------------------------------*/
6841 /*--- ISEL: Statements ---*/
6842 /*---------------------------------------------------------*/
6844 static void iselStmt(ISelEnv * env, IRStmt * stmt)
6846 if (vex_traceflags & VEX_TRACE_VCODE) {
6847 vex_printf("\n-- ");
6849 ppIRStmt(stmt);
6850 vex_printf("\n");
6853 switch (stmt->tag) {
6854 /* --------- STORE --------- */
6855 case Ist_Store: {
6856 MIPSAMode *am_addr;
6857 IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
6859 if (tyd == Ity_V128) {
6860 vassert(has_msa);
6861 HReg res = iselV128Expr(env, stmt->Ist.Store.data);
6862 HReg addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
6863 addInstr(env, MIPSInstr_MsaMi10(MSA_ST, 0, addr, res, MSA_B));
6864 return;
6867 /*constructs addressing mode from address provided */
6868 am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
6870 if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
6871 (mode64 && (tyd == Ity_I64))) {
6872 HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
6873 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)),
6874 am_addr, r_src, mode64));
6875 return;
6877 if (!mode64 && (tyd == Ity_I64)) {
6878 HReg vHi, vLo;
6879 HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
6881 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
6883 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
6884 MIPSAMode_IR(0, r_addr), vHi, mode64));
6885 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
6886 MIPSAMode_IR(4, r_addr), vLo, mode64));
6887 return;
6889 if (tyd == Ity_F32) {
6890 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
6891 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
6892 am_addr));
6893 return;
6895 if (tyd == Ity_F64 && mode64) {
6896 HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
6897 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
6898 am_addr));
6899 return;
6901 if (!mode64 && (tyd == Ity_F64)) {
6902 HReg fr_src = iselDblExpr(env, stmt->Ist.Store.data);
6903 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
6904 am_addr));
6905 return;
6908 break;
6911 /* --------- PUT --------- */
6912 case Ist_Put: {
6913 IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
6915 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
6916 (ty == Ity_I64 && mode64)) {
6917 HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
6918 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
6919 GuestStatePointer(mode64));
6920 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)),
6921 am_addr, r_src, mode64));
6922 return;
6925 if (ty == Ity_I64 && !mode64) {
6926 HReg vHi, vLo;
6927 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
6928 GuestStatePointer(mode64));
6929 MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4,
6930 GuestStatePointer(mode64));
6931 iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
6932 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
6933 am_addr, vLo, mode64));
6934 addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
6935 am_addr4, vHi, mode64));
6936 return;
6940 if (ty == Ity_F32) {
6941 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
6942 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
6943 GuestStatePointer(mode64));
6944 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
6945 am_addr));
6946 return;
6949 if (ty == Ity_F64) {
6950 if (mode64) {
6951 HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
6952 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
6953 GuestStatePointer(mode64));
6954 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
6955 am_addr));
6956 } else {
6957 HReg fr_src = iselDblExpr(env, stmt->Ist.Put.data);
6958 MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
6959 GuestStatePointer(mode64));
6960 addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
6961 am_addr));
6963 return;
6965 if (ty == Ity_V128) {
6966 vassert(has_msa);
6967 HReg v_src = iselV128Expr(env, stmt->Ist.Put.data);
6968 #if defined(_MIPSEB)
6969 vassert(!(stmt->Ist.Put.offset & ~0x7FFF));
6970 HReg r_addr = newVRegI(env);
6971 addInstr(env, MIPSInstr_Alu(mode64 ? Malu_DADD : Malu_ADD, r_addr, GuestStatePointer(mode64),
6972 MIPSRH_Imm(True, stmt->Ist.Put.offset)));
6973 addInstr(env, MIPSInstr_MsaMi10(MSA_ST, 0, r_addr, v_src, MSA_B));
6974 #else
6975 vassert(!(stmt->Ist.Put.offset & 7));
6976 addInstr(env, MIPSInstr_MsaMi10(MSA_ST, stmt->Ist.Put.offset >> 3,
6977 GuestStatePointer(mode64), v_src, MSA_D));
6978 #endif
6979 return;
6981 break;
6984 /* --------- TMP --------- */
6985 case Ist_WrTmp: {
6986 IRTemp tmp = stmt->Ist.WrTmp.tmp;
6987 IRType ty = typeOfIRTemp(env->type_env, tmp);
6989 if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) {
6990 HReg r_dst = lookupIRTemp(env, tmp);
6991 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
6992 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
6993 return;
6996 if (ty == Ity_I64) {
6997 if (mode64) {
6998 HReg r_dst = lookupIRTemp(env, tmp);
6999 HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
7000 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
7001 return;
7002 } else {
7003 HReg rHi, rLo, dstHi, dstLo;
7004 iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
7005 lookupIRTemp64(&dstHi, &dstLo, env, tmp);
7006 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
7007 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
7008 return;
7012 if (mode64 && ty == Ity_I128) {
7013 HReg rHi, rLo, dstHi, dstLo;
7014 iselInt128Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
7015 lookupIRTempPair(&dstHi, &dstLo, env, tmp);
7016 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
7017 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
7018 return;
7021 if (ty == Ity_F32) {
7022 HReg fr_dst = lookupIRTemp(env, tmp);
7023 HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
7024 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src));
7025 return;
7028 if (ty == Ity_F64) {
7029 if (mode64) {
7030 HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
7031 HReg dst = lookupIRTemp(env, tmp);
7032 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
7033 return;
7034 } else {
7035 HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
7036 HReg dst = lookupIRTemp(env, tmp);
7037 addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
7038 return;
7042 if (ty == Ity_V128) {
7043 vassert(has_msa);
7044 HReg v_dst = lookupIRTemp(env, tmp);
7045 HReg v_src = iselV128Expr(env, stmt->Ist.WrTmp.data);
7046 addInstr(env, MIPSInstr_MsaElm(MSA_MOVE, v_src, v_dst, 0));
7047 return;
7049 break;
7052 /* --------- Call to DIRTY helper --------- */
7053 case Ist_Dirty: {
7054 IRDirty *d = stmt->Ist.Dirty.details;
7056 /* Figure out the return type, if any. */
7057 IRType retty = Ity_INVALID;
7058 if (d->tmp != IRTemp_INVALID)
7059 retty = typeOfIRTemp(env->type_env, d->tmp);
7061 /* Throw out any return types we don't know about. */
7062 Bool retty_ok = False;
7063 switch (retty) {
7064 case Ity_INVALID: /* Function doesn't return anything. */
7065 case Ity_V128:
7066 case Ity_I64: case Ity_I32: case Ity_I16: case Ity_I8:
7067 retty_ok = True; break;
7068 default:
7069 break;
7072 if (!retty_ok)
7073 break; /* will go to stmt_fail: */
7075 /* Marshal args, do the call, clear stack, set the return value
7076 to 0x555..555 if this is a conditional call that returns a
7077 value and the call is skipped. */
7078 UInt addToSp = 0;
7079 RetLoc rloc = mk_RetLoc_INVALID();
7080 doHelperCall( &addToSp, &rloc, env, d->guard, d->cee, retty, d->args );
7081 vassert(is_sane_RetLoc(rloc));
7083 /* Now figure out what to do with the returned value, if any. */
7084 switch (retty) {
7085 case Ity_INVALID: {
7086 /* No return value. Nothing to do. */
7087 vassert(d->tmp == IRTemp_INVALID);
7088 vassert(rloc.pri == RLPri_None);
7089 vassert(addToSp == 0);
7090 return;
7092 case Ity_I32: case Ity_I16: case Ity_I8: {
7093 /* The returned value is in $v0. Park it in the register
7094 associated with tmp. */
7095 HReg r_dst = lookupIRTemp(env, d->tmp);
7096 addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_dst,
7097 hregMIPS_GPR2(mode64),
7098 MIPSRH_Imm(False, 0)));
7099 vassert(rloc.pri == RLPri_Int);
7100 vassert(addToSp == 0);
7101 return;
7103 case Ity_I64: {
7104 if (mode64) {
7105 /* The returned value is in $v0. Park it in the register
7106 associated with tmp. */
7107 HReg r_dst = lookupIRTemp(env, d->tmp);
7108 addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
7109 vassert(rloc.pri == RLPri_Int);
7110 vassert(addToSp == 0);
7111 return;
7112 } else {
7113 HReg rHi = newVRegI(env);
7114 HReg rLo = newVRegI(env);
7115 HReg dstHi, dstLo;
7116 addInstr(env, mk_iMOVds_RR(rLo, hregMIPS_GPR2(mode64)));
7117 addInstr(env, mk_iMOVds_RR(rHi, hregMIPS_GPR3(mode64)));
7118 lookupIRTemp64(&dstHi, &dstLo, env, d->tmp);
7119 addInstr(env, mk_iMOVds_RR(dstHi, rHi));
7120 addInstr(env, mk_iMOVds_RR(dstLo, rLo));
7121 return;
7124 case Ity_V128: {
7125 vassert(has_msa);
7126 vassert(rloc.pri == RLPri_V128SpRel);
7127 vassert((rloc.spOff < 512) && (rloc.spOff > -512));
7128 vassert(addToSp >= 16);
7129 HReg dst = lookupIRTemp(env, d->tmp);
7130 addInstr(env, MIPSInstr_MsaMi10(MSA_LD, rloc.spOff, StackPointer(mode64), dst, MSA_B));
7131 add_to_sp(env, addToSp);
7132 return;
7135 default:
7136 /*NOTREACHED*/
7137 vassert(0);
7141 /* --------- Load Linked or Store Conditional --------- */
7142 case Ist_LLSC: {
7143 /* Temporary solution; this need to be rewritten again for MIPS.
7144 On MIPS you can not read from address that is locked with LL
7145 before SC. If you read from address that is locked than SC will
7146 fall. */
7147 IRTemp res = stmt->Ist.LLSC.result;
7148 IRType tyRes = typeOfIRTemp(env->type_env, res);
7149 IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
7151 if (!mode64 && (tyAddr != Ity_I32))
7152 goto stmt_fail;
7154 if (stmt->Ist.LLSC.storedata == NULL) {
7155 /* LL */
7156 MIPSAMode *r_addr;
7157 /* constructs addressing mode from address provided */
7158 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
7160 HReg r_dst = lookupIRTemp(env, res);
7161 if (tyRes == Ity_I32) {
7162 addInstr(env, MIPSInstr_LoadL(4, r_dst, r_addr, mode64));
7163 return;
7164 } else if (tyRes == Ity_I64 && mode64) {
7165 addInstr(env, MIPSInstr_LoadL(8, r_dst, r_addr, mode64));
7166 return;
7168 } else {
7169 /* SC */
7170 MIPSAMode *r_addr;
7171 r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
7172 HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
7173 HReg r_dst = lookupIRTemp(env, res);
7174 IRType tyData = typeOfIRExpr(env->type_env,
7175 stmt->Ist.LLSC.storedata);
7177 if (tyData == Ity_I32) {
7178 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
7179 addInstr(env, MIPSInstr_StoreC(4, r_addr, r_dst, mode64));
7180 return;
7181 } else if (tyData == Ity_I64 && mode64) {
7182 addInstr(env, mk_iMOVds_RR(r_dst, r_src));
7183 addInstr(env, MIPSInstr_StoreC(8, r_addr, r_dst, mode64));
7184 return;
7187 goto stmt_fail;
7188 /* NOTREACHED */}
7190 case Ist_CAS:
7191 if (stmt->Ist.CAS.details->oldHi == IRTemp_INVALID) {
7192 IRCAS *cas = stmt->Ist.CAS.details;
7193 HReg old = lookupIRTemp(env, cas->oldLo);
7194 HReg addr = iselWordExpr_R(env, cas->addr);
7195 HReg expd = iselWordExpr_R(env, cas->expdLo);
7196 HReg data = iselWordExpr_R(env, cas->dataLo);
7197 if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I64) {
7198 addInstr(env, MIPSInstr_Cas(8, old, addr, expd, data, mode64));
7199 } else if (typeOfIRTemp(env->type_env, cas->oldLo) == Ity_I32) {
7200 addInstr(env, MIPSInstr_Cas(4, old, addr, expd, data, mode64));
7203 return;
7205 /* --------- INSTR MARK --------- */
7206 /* Doesn't generate any executable code ... */
7207 case Ist_IMark:
7208 return;
7210 /* --------- ABI HINT --------- */
7211 /* These have no meaning (denotation in the IR) and so we ignore
7212 them ... if any actually made it this far. */
7213 case Ist_AbiHint:
7214 return;
7216 /* --------- NO-OP --------- */
7217 /* Fairly self-explanatory, wouldn't you say? */
7218 case Ist_NoOp:
7219 return;
7221 /* --------- EXIT --------- */
7222 case Ist_Exit: {
7223 IRConst* dst = stmt->Ist.Exit.dst;
7224 if (!mode64 && dst->tag != Ico_U32)
7225 vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value");
7226 if (mode64 && dst->tag != Ico_U64)
7227 vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value");
7229 MIPSCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
7230 MIPSAMode* amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP,
7231 GuestStatePointer(mode64));
7233 /* Case: boring transfer to known address */
7234 if (stmt->Ist.Exit.jk == Ijk_Boring
7235 || stmt->Ist.Exit.jk == Ijk_Call
7236 /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
7237 if (env->chainingAllowed) {
7238 /* .. almost always true .. */
7239 /* Skip the event check at the dst if this is a forwards
7240 edge. */
7241 Bool toFastEP
7242 = mode64
7243 ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
7244 : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
7245 if (0) vex_printf("%s", toFastEP ? "Y" : ",");
7246 addInstr(env, MIPSInstr_XDirect(
7247 mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
7248 : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
7249 amPC, cc, toFastEP));
7250 } else {
7251 /* .. very occasionally .. */
7252 /* We can't use chaining, so ask for an assisted transfer,
7253 as that's the only alternative that is allowable. */
7254 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
7255 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring));
7257 return;
7260 /* Case: assisted transfer to arbitrary address */
7261 switch (stmt->Ist.Exit.jk) {
7262 /* Keep this list in sync with that in iselNext below */
7263 case Ijk_ClientReq:
7264 case Ijk_EmFail:
7265 case Ijk_EmWarn:
7266 case Ijk_NoDecode:
7267 case Ijk_NoRedir:
7268 case Ijk_SigBUS:
7269 case Ijk_Yield:
7270 case Ijk_SigTRAP:
7271 case Ijk_SigFPE_IntDiv:
7272 case Ijk_SigFPE_IntOvf:
7273 case Ijk_Sys_syscall:
7274 case Ijk_InvalICache:
7276 HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
7277 addInstr(env, MIPSInstr_XAssisted(r, amPC, cc,
7278 stmt->Ist.Exit.jk));
7279 return;
7281 default:
7282 break;
7285 /* Do we ever expect to see any other kind? */
7286 goto stmt_fail;
7289 default:
7290 break;
7293 stmt_fail:
7294 vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
7295 ppIRStmt(stmt);
7296 vpanic("iselStmt:\n");
7299 /*---------------------------------------------------------*/
7300 /*--- ISEL: Basic block terminators (Nexts) ---*/
7301 /*---------------------------------------------------------*/
7303 static void iselNext ( ISelEnv* env,
7304 IRExpr* next, IRJumpKind jk, Int offsIP )
7306 if (vex_traceflags & VEX_TRACE_VCODE) {
7307 vex_printf( "\n-- PUT(%d) = ", offsIP);
7308 ppIRExpr( next );
7309 vex_printf( "; exit-");
7310 ppIRJumpKind(jk);
7311 vex_printf( "\n");
7314 /* Case: boring transfer to known address */
7315 if (next->tag == Iex_Const) {
7316 IRConst* cdst = next->Iex.Const.con;
7317 vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
7318 if (jk == Ijk_Boring || jk == Ijk_Call) {
7319 /* Boring transfer to known address */
7320 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
7321 if (env->chainingAllowed) {
7322 /* .. almost always true .. */
7323 /* Skip the event check at the dst if this is a forwards
7324 edge. */
7325 Bool toFastEP
7326 = env->mode64
7327 ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
7328 : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
7329 if (0) vex_printf("%s", toFastEP ? "X" : ".");
7330 addInstr(env, MIPSInstr_XDirect(
7331 env->mode64 ? (Addr64)cdst->Ico.U64
7332 : (Addr64)cdst->Ico.U32,
7333 amPC, MIPScc_AL, toFastEP));
7334 } else {
7335 /* .. very occasionally .. */
7336 /* We can't use chaining, so ask for an assisted transfer,
7337 as that's the only alternative that is allowable. */
7338 HReg r = iselWordExpr_R(env, next);
7339 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
7340 Ijk_Boring));
7342 return;
7346 /* Case: call/return (==boring) transfer to any address */
7347 switch (jk) {
7348 case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
7349 HReg r = iselWordExpr_R(env, next);
7350 MIPSAMode* amPC = MIPSAMode_IR(offsIP,
7351 GuestStatePointer(env->mode64));
7352 if (env->chainingAllowed) {
7353 addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL));
7354 } else {
7355 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
7356 Ijk_Boring));
7358 return;
7360 default:
7361 break;
7364 /* Case: assisted transfer to arbitrary address */
7365 switch (jk) {
7366 /* Keep this list in sync with that for Ist_Exit above */
7367 case Ijk_ClientReq:
7368 case Ijk_EmFail:
7369 case Ijk_EmWarn:
7370 case Ijk_NoDecode:
7371 case Ijk_NoRedir:
7372 case Ijk_SigBUS:
7373 case Ijk_SigILL:
7374 case Ijk_SigTRAP:
7375 case Ijk_SigFPE_IntDiv:
7376 case Ijk_SigFPE_IntOvf:
7377 case Ijk_Sys_syscall:
7378 case Ijk_InvalICache: {
7379 HReg r = iselWordExpr_R(env, next);
7380 MIPSAMode* amPC = MIPSAMode_IR(offsIP, GuestStatePointer(env->mode64));
7381 addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk));
7382 return;
7384 default:
7385 break;
7388 vex_printf("\n-- PUT(%d) = ", offsIP);
7389 ppIRExpr(next );
7390 vex_printf("; exit-");
7391 ppIRJumpKind(jk);
7392 vex_printf("\n");
7393 vassert(0); /* are we expecting any other kind? */
7396 /*---------------------------------------------------------*/
7397 /*--- Insn selector top-level ---*/
7398 /*---------------------------------------------------------*/
7400 /* Translate an entire BB to mips code. */
7401 HInstrArray *iselSB_MIPS ( const IRSB* bb,
7402 VexArch arch_host,
7403 const VexArchInfo* archinfo_host,
7404 const VexAbiInfo* vbi,
7405 Int offs_Host_EvC_Counter,
7406 Int offs_Host_EvC_FailAddr,
7407 Bool chainingAllowed,
7408 Bool addProfInc,
7409 Addr max_ga )
7411 Int i, j;
7412 HReg hreg, hregHI;
7413 ISelEnv* env;
7414 MIPSAMode *amCounter, *amFailAddr;
7416 hwcaps_host = archinfo_host->hwcaps;
7418 /* sanity ... */
7419 vassert(arch_host == VexArchMIPS32 || arch_host == VexArchMIPS64);
7420 vassert(VEX_PRID_COMP_MIPS == VEX_MIPS_COMP_ID(hwcaps_host)
7421 || VEX_PRID_COMP_CAVIUM == VEX_MIPS_COMP_ID(hwcaps_host)
7422 || VEX_PRID_COMP_BROADCOM == VEX_MIPS_COMP_ID(hwcaps_host)
7423 || VEX_PRID_COMP_NETLOGIC == VEX_MIPS_COMP_ID(hwcaps_host)
7424 || VEX_PRID_COMP_INGENIC_E1 == VEX_MIPS_COMP_ID(hwcaps_host)
7425 || VEX_PRID_COMP_LEGACY == VEX_MIPS_COMP_ID(hwcaps_host));
7427 /* Check that the host's endianness is as expected. */
7428 vassert(archinfo_host->endness == VexEndnessLE
7429 || archinfo_host->endness == VexEndnessBE);
7431 mode64 = arch_host != VexArchMIPS32;
7432 fp_mode64 = VEX_MIPS_HOST_FP_MODE(hwcaps_host);
7433 has_msa = VEX_MIPS_PROC_MSA(archinfo_host->hwcaps);
7435 /* Make up an initial environment to use. */
7436 env = LibVEX_Alloc_inline(sizeof(ISelEnv));
7437 env->vreg_ctr = 0;
7438 env->mode64 = mode64;
7439 env->fp_mode64 = fp_mode64;
7441 /* Set up output code array. */
7442 env->code = newHInstrArray();
7444 /* Copy BB's type env. */
7445 env->type_env = bb->tyenv;
7447 /* Make up an IRTemp -> virtual HReg mapping. This doesn't
7448 change as we go along. */
7449 env->n_vregmap = bb->tyenv->types_used;
7450 env->vregmap = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
7451 env->vregmapHI = LibVEX_Alloc_inline(env->n_vregmap * sizeof(HReg));
7453 /* and finally ... */
7454 env->hwcaps = hwcaps_host;
7455 env->chainingAllowed = chainingAllowed;
7456 env->hwcaps = hwcaps_host;
7457 env->max_ga = max_ga;
7459 /* For each IR temporary, allocate a suitably-kinded virtual
7460 register. */
7461 j = 0;
7462 for (i = 0; i < env->n_vregmap; i++) {
7463 hregHI = hreg = INVALID_HREG;
7464 switch (bb->tyenv->types[i]) {
7465 case Ity_I1:
7466 case Ity_I8:
7467 case Ity_I16:
7468 case Ity_I32:
7469 if (mode64) {
7470 hreg = mkHReg(True, HRcInt64, 0, j++);
7471 break;
7472 } else {
7473 hreg = mkHReg(True, HRcInt32, 0, j++);
7474 break;
7476 case Ity_I64:
7477 if (mode64) {
7478 hreg = mkHReg(True, HRcInt64, 0, j++);
7479 break;
7480 } else {
7481 hreg = mkHReg(True, HRcInt32, 0, j++);
7482 hregHI = mkHReg(True, HRcInt32, 0, j++);
7483 break;
7485 case Ity_I128:
7486 vassert(mode64);
7487 hreg = mkHReg(True, HRcInt64, 0, j++);
7488 hregHI = mkHReg(True, HRcInt64, 0, j++);
7489 break;
7490 case Ity_F32:
7491 if (mode64) {
7492 hreg = mkHReg(True, HRcFlt64, 0, j++);
7493 break;
7494 } else {
7495 hreg = mkHReg(True, HRcFlt32, 0, j++);
7496 break;
7498 case Ity_F64:
7499 hreg = mkHReg(True, HRcFlt64, 0, j++);
7500 break;
7501 case Ity_V128:
7502 hreg = mkHReg(True, HRcVec128, 0, j++);
7503 break;
7504 default:
7505 ppIRType(bb->tyenv->types[i]);
7506 vpanic("iselBB(mips): IRTemp type");
7507 break;
7509 env->vregmap[i] = hreg;
7510 env->vregmapHI[i] = hregHI;
7512 env->vreg_ctr = j;
7514 /* The very first instruction must be an event check. */
7515 amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, GuestStatePointer(mode64));
7516 amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, GuestStatePointer(mode64));
7517 addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr));
7519 /* Possibly a block counter increment (for profiling). At this
7520 point we don't know the address of the counter, so just pretend
7521 it is zero. It will have to be patched later, but before this
7522 translation is used, by a call to LibVEX_patchProfCtr. */
7523 if (addProfInc) {
7524 addInstr(env, MIPSInstr_ProfInc());
7527 /* Ok, finally we can iterate over the statements. */
7528 for (i = 0; i < bb->stmts_used; i++)
7529 iselStmt(env, bb->stmts[i]);
7531 iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
7533 /* record the number of vregs we used. */
7534 env->code->n_vregs = env->vreg_ctr;
7535 return env->code;
7539 /*---------------------------------------------------------------*/
7540 /*--- end host_mips_isel.c ---*/
7541 /*---------------------------------------------------------------*/