/*--------------------------------------------------------------------*/
/*--- begin guest_mips_toIR.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2010-2017 RT-RK
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, see .
The GNU General Public License is contained in the file COPYING.
*/
/* Translates MIPS code to IR. */
#include "libvex_basictypes.h"
#include "libvex_ir.h"
#include "libvex.h"
#include "libvex_guest_mips32.h"
#include "libvex_guest_mips64.h"
#include "main_util.h"
#include "main_globals.h"
#include "guest_generic_bb_to_IR.h"
#include "guest_mips_defs.h"
#include "mips_defs.h"
/*------------------------------------------------------------*/
/*--- Globals ---*/
/*------------------------------------------------------------*/
/* These are set at the start of the translation of a instruction, so
that we don't have to pass them around endlessly. CONST means does
not change during translation of the instruction. */
/* CONST: what is the host's endianness? This has to do with float vs
double register accesses on VFP, but it's complex and not properly
thought out. */
static VexEndness host_endness;
/* Pointer to the guest code area. */
const UChar *guest_code;
/* CONST: The guest address for the instruction currently being
translated. */
#if defined(VGP_mips32_linux)
static Addr32 guest_PC_curr_instr;
#else
static Addr64 guest_PC_curr_instr;
#endif
/* MOD: The IRSB* into which we're generating code. */
IRSB *irsb;
/* Is our guest binary 32 or 64bit? Set at each call to
disInstr_MIPS below. */
Bool mode64 = False;
/* CPU has FPU and 32 dbl. prec. FP registers. */
static Bool fp_mode64 = False;
/* FPU works in FRE mode */
static Bool fp_mode64_fre = False;
/* CPU has MSA unit */
static Bool has_msa = False;
/* Define 1.0 in single and double precision. */
#define ONE_SINGLE 0x3F800000
#define ONE_DOUBLE 0x3FF0000000000000ULL
/*------------------------------------------------------------*/
/*--- Helper bits and pieces for deconstructing the ---*/
/*--- mips insn stream. ---*/
/*------------------------------------------------------------*/
/* ---------------- Integer registers ---------------- */
static UInt integerGuestRegOffset(UInt iregNo)
{
/* Do we care about endianness here? We do if sub-parts of integer
registers are accessed, but I don't think that ever happens on
MIPS. */
UInt ret;
if (!mode64)
switch (iregNo) {
case 0:
ret = offsetof(VexGuestMIPS32State, guest_r0);
break;
case 1:
ret = offsetof(VexGuestMIPS32State, guest_r1);
break;
case 2:
ret = offsetof(VexGuestMIPS32State, guest_r2);
break;
case 3:
ret = offsetof(VexGuestMIPS32State, guest_r3);
break;
case 4:
ret = offsetof(VexGuestMIPS32State, guest_r4);
break;
case 5:
ret = offsetof(VexGuestMIPS32State, guest_r5);
break;
case 6:
ret = offsetof(VexGuestMIPS32State, guest_r6);
break;
case 7:
ret = offsetof(VexGuestMIPS32State, guest_r7);
break;
case 8:
ret = offsetof(VexGuestMIPS32State, guest_r8);
break;
case 9:
ret = offsetof(VexGuestMIPS32State, guest_r9);
break;
case 10:
ret = offsetof(VexGuestMIPS32State, guest_r10);
break;
case 11:
ret = offsetof(VexGuestMIPS32State, guest_r11);
break;
case 12:
ret = offsetof(VexGuestMIPS32State, guest_r12);
break;
case 13:
ret = offsetof(VexGuestMIPS32State, guest_r13);
break;
case 14:
ret = offsetof(VexGuestMIPS32State, guest_r14);
break;
case 15:
ret = offsetof(VexGuestMIPS32State, guest_r15);
break;
case 16:
ret = offsetof(VexGuestMIPS32State, guest_r16);
break;
case 17:
ret = offsetof(VexGuestMIPS32State, guest_r17);
break;
case 18:
ret = offsetof(VexGuestMIPS32State, guest_r18);
break;
case 19:
ret = offsetof(VexGuestMIPS32State, guest_r19);
break;
case 20:
ret = offsetof(VexGuestMIPS32State, guest_r20);
break;
case 21:
ret = offsetof(VexGuestMIPS32State, guest_r21);
break;
case 22:
ret = offsetof(VexGuestMIPS32State, guest_r22);
break;
case 23:
ret = offsetof(VexGuestMIPS32State, guest_r23);
break;
case 24:
ret = offsetof(VexGuestMIPS32State, guest_r24);
break;
case 25:
ret = offsetof(VexGuestMIPS32State, guest_r25);
break;
case 26:
ret = offsetof(VexGuestMIPS32State, guest_r26);
break;
case 27:
ret = offsetof(VexGuestMIPS32State, guest_r27);
break;
case 28:
ret = offsetof(VexGuestMIPS32State, guest_r28);
break;
case 29:
ret = offsetof(VexGuestMIPS32State, guest_r29);
break;
case 30:
ret = offsetof(VexGuestMIPS32State, guest_r30);
break;
case 31:
ret = offsetof(VexGuestMIPS32State, guest_r31);
break;
default:
vassert(0);
break;
}
else
switch (iregNo) {
case 0:
ret = offsetof(VexGuestMIPS64State, guest_r0);
break;
case 1:
ret = offsetof(VexGuestMIPS64State, guest_r1);
break;
case 2:
ret = offsetof(VexGuestMIPS64State, guest_r2);
break;
case 3:
ret = offsetof(VexGuestMIPS64State, guest_r3);
break;
case 4:
ret = offsetof(VexGuestMIPS64State, guest_r4);
break;
case 5:
ret = offsetof(VexGuestMIPS64State, guest_r5);
break;
case 6:
ret = offsetof(VexGuestMIPS64State, guest_r6);
break;
case 7:
ret = offsetof(VexGuestMIPS64State, guest_r7);
break;
case 8:
ret = offsetof(VexGuestMIPS64State, guest_r8);
break;
case 9:
ret = offsetof(VexGuestMIPS64State, guest_r9);
break;
case 10:
ret = offsetof(VexGuestMIPS64State, guest_r10);
break;
case 11:
ret = offsetof(VexGuestMIPS64State, guest_r11);
break;
case 12:
ret = offsetof(VexGuestMIPS64State, guest_r12);
break;
case 13:
ret = offsetof(VexGuestMIPS64State, guest_r13);
break;
case 14:
ret = offsetof(VexGuestMIPS64State, guest_r14);
break;
case 15:
ret = offsetof(VexGuestMIPS64State, guest_r15);
break;
case 16:
ret = offsetof(VexGuestMIPS64State, guest_r16);
break;
case 17:
ret = offsetof(VexGuestMIPS64State, guest_r17);
break;
case 18:
ret = offsetof(VexGuestMIPS64State, guest_r18);
break;
case 19:
ret = offsetof(VexGuestMIPS64State, guest_r19);
break;
case 20:
ret = offsetof(VexGuestMIPS64State, guest_r20);
break;
case 21:
ret = offsetof(VexGuestMIPS64State, guest_r21);
break;
case 22:
ret = offsetof(VexGuestMIPS64State, guest_r22);
break;
case 23:
ret = offsetof(VexGuestMIPS64State, guest_r23);
break;
case 24:
ret = offsetof(VexGuestMIPS64State, guest_r24);
break;
case 25:
ret = offsetof(VexGuestMIPS64State, guest_r25);
break;
case 26:
ret = offsetof(VexGuestMIPS64State, guest_r26);
break;
case 27:
ret = offsetof(VexGuestMIPS64State, guest_r27);
break;
case 28:
ret = offsetof(VexGuestMIPS64State, guest_r28);
break;
case 29:
ret = offsetof(VexGuestMIPS64State, guest_r29);
break;
case 30:
ret = offsetof(VexGuestMIPS64State, guest_r30);
break;
case 31:
ret = offsetof(VexGuestMIPS64State, guest_r31);
break;
default:
vassert(0);
break;
}
return ret;
}
#if defined(VGP_mips32_linux)
#define OFFB_PC offsetof(VexGuestMIPS32State, guest_PC)
#else
#define OFFB_PC offsetof(VexGuestMIPS64State, guest_PC)
#endif
/* ---------------- Floating point registers ---------------- */
static UInt floatGuestRegOffset(UInt fregNo)
{
vassert(fregNo < 32);
UInt ret;
if (!mode64)
switch (fregNo) {
case 0:
ret = offsetof(VexGuestMIPS32State, guest_f0);
break;
case 1:
ret = offsetof(VexGuestMIPS32State, guest_f1);
break;
case 2:
ret = offsetof(VexGuestMIPS32State, guest_f2);
break;
case 3:
ret = offsetof(VexGuestMIPS32State, guest_f3);
break;
case 4:
ret = offsetof(VexGuestMIPS32State, guest_f4);
break;
case 5:
ret = offsetof(VexGuestMIPS32State, guest_f5);
break;
case 6:
ret = offsetof(VexGuestMIPS32State, guest_f6);
break;
case 7:
ret = offsetof(VexGuestMIPS32State, guest_f7);
break;
case 8:
ret = offsetof(VexGuestMIPS32State, guest_f8);
break;
case 9:
ret = offsetof(VexGuestMIPS32State, guest_f9);
break;
case 10:
ret = offsetof(VexGuestMIPS32State, guest_f10);
break;
case 11:
ret = offsetof(VexGuestMIPS32State, guest_f11);
break;
case 12:
ret = offsetof(VexGuestMIPS32State, guest_f12);
break;
case 13:
ret = offsetof(VexGuestMIPS32State, guest_f13);
break;
case 14:
ret = offsetof(VexGuestMIPS32State, guest_f14);
break;
case 15:
ret = offsetof(VexGuestMIPS32State, guest_f15);
break;
case 16:
ret = offsetof(VexGuestMIPS32State, guest_f16);
break;
case 17:
ret = offsetof(VexGuestMIPS32State, guest_f17);
break;
case 18:
ret = offsetof(VexGuestMIPS32State, guest_f18);
break;
case 19:
ret = offsetof(VexGuestMIPS32State, guest_f19);
break;
case 20:
ret = offsetof(VexGuestMIPS32State, guest_f20);
break;
case 21:
ret = offsetof(VexGuestMIPS32State, guest_f21);
break;
case 22:
ret = offsetof(VexGuestMIPS32State, guest_f22);
break;
case 23:
ret = offsetof(VexGuestMIPS32State, guest_f23);
break;
case 24:
ret = offsetof(VexGuestMIPS32State, guest_f24);
break;
case 25:
ret = offsetof(VexGuestMIPS32State, guest_f25);
break;
case 26:
ret = offsetof(VexGuestMIPS32State, guest_f26);
break;
case 27:
ret = offsetof(VexGuestMIPS32State, guest_f27);
break;
case 28:
ret = offsetof(VexGuestMIPS32State, guest_f28);
break;
case 29:
ret = offsetof(VexGuestMIPS32State, guest_f29);
break;
case 30:
ret = offsetof(VexGuestMIPS32State, guest_f30);
break;
case 31:
ret = offsetof(VexGuestMIPS32State, guest_f31);
break;
default:
vassert(0);
break;
}
else
switch (fregNo) {
case 0:
ret = offsetof(VexGuestMIPS64State, guest_f0);
break;
case 1:
ret = offsetof(VexGuestMIPS64State, guest_f1);
break;
case 2:
ret = offsetof(VexGuestMIPS64State, guest_f2);
break;
case 3:
ret = offsetof(VexGuestMIPS64State, guest_f3);
break;
case 4:
ret = offsetof(VexGuestMIPS64State, guest_f4);
break;
case 5:
ret = offsetof(VexGuestMIPS64State, guest_f5);
break;
case 6:
ret = offsetof(VexGuestMIPS64State, guest_f6);
break;
case 7:
ret = offsetof(VexGuestMIPS64State, guest_f7);
break;
case 8:
ret = offsetof(VexGuestMIPS64State, guest_f8);
break;
case 9:
ret = offsetof(VexGuestMIPS64State, guest_f9);
break;
case 10:
ret = offsetof(VexGuestMIPS64State, guest_f10);
break;
case 11:
ret = offsetof(VexGuestMIPS64State, guest_f11);
break;
case 12:
ret = offsetof(VexGuestMIPS64State, guest_f12);
break;
case 13:
ret = offsetof(VexGuestMIPS64State, guest_f13);
break;
case 14:
ret = offsetof(VexGuestMIPS64State, guest_f14);
break;
case 15:
ret = offsetof(VexGuestMIPS64State, guest_f15);
break;
case 16:
ret = offsetof(VexGuestMIPS64State, guest_f16);
break;
case 17:
ret = offsetof(VexGuestMIPS64State, guest_f17);
break;
case 18:
ret = offsetof(VexGuestMIPS64State, guest_f18);
break;
case 19:
ret = offsetof(VexGuestMIPS64State, guest_f19);
break;
case 20:
ret = offsetof(VexGuestMIPS64State, guest_f20);
break;
case 21:
ret = offsetof(VexGuestMIPS64State, guest_f21);
break;
case 22:
ret = offsetof(VexGuestMIPS64State, guest_f22);
break;
case 23:
ret = offsetof(VexGuestMIPS64State, guest_f23);
break;
case 24:
ret = offsetof(VexGuestMIPS64State, guest_f24);
break;
case 25:
ret = offsetof(VexGuestMIPS64State, guest_f25);
break;
case 26:
ret = offsetof(VexGuestMIPS64State, guest_f26);
break;
case 27:
ret = offsetof(VexGuestMIPS64State, guest_f27);
break;
case 28:
ret = offsetof(VexGuestMIPS64State, guest_f28);
break;
case 29:
ret = offsetof(VexGuestMIPS64State, guest_f29);
break;
case 30:
ret = offsetof(VexGuestMIPS64State, guest_f30);
break;
case 31:
ret = offsetof(VexGuestMIPS64State, guest_f31);
break;
default:
vassert(0);
break;
}
return ret;
}
/* ---------------- MIPS32 DSP ASE(r2) accumulators ---------------- */
UInt accumulatorGuestRegOffset(UInt acNo)
{
vassert(!mode64);
vassert(acNo <= 3);
UInt ret;
switch (acNo) {
case 0:
ret = offsetof(VexGuestMIPS32State, guest_ac0);
break;
case 1:
ret = offsetof(VexGuestMIPS32State, guest_ac1);
break;
case 2:
ret = offsetof(VexGuestMIPS32State, guest_ac2);
break;
case 3:
ret = offsetof(VexGuestMIPS32State, guest_ac3);
break;
default:
vassert(0);
break;
}
return ret;
}
/* ---------------- MIPS32 MSA registers ---------------- */
static UInt msaGuestRegOffset(UInt msaRegNo)
{
vassert(msaRegNo <= 31);
UInt ret;
if (mode64) {
switch (msaRegNo) {
case 0:
ret = offsetof(VexGuestMIPS64State, guest_w0);
break;
case 1:
ret = offsetof(VexGuestMIPS64State, guest_w1);
break;
case 2:
ret = offsetof(VexGuestMIPS64State, guest_w2);
break;
case 3:
ret = offsetof(VexGuestMIPS64State, guest_w3);
break;
case 4:
ret = offsetof(VexGuestMIPS64State, guest_w4);
break;
case 5:
ret = offsetof(VexGuestMIPS64State, guest_w5);
break;
case 6:
ret = offsetof(VexGuestMIPS64State, guest_w6);
break;
case 7:
ret = offsetof(VexGuestMIPS64State, guest_w7);
break;
case 8:
ret = offsetof(VexGuestMIPS64State, guest_w8);
break;
case 9:
ret = offsetof(VexGuestMIPS64State, guest_w9);
break;
case 10:
ret = offsetof(VexGuestMIPS64State, guest_w10);
break;
case 11:
ret = offsetof(VexGuestMIPS64State, guest_w11);
break;
case 12:
ret = offsetof(VexGuestMIPS64State, guest_w12);
break;
case 13:
ret = offsetof(VexGuestMIPS64State, guest_w13);
break;
case 14:
ret = offsetof(VexGuestMIPS64State, guest_w14);
break;
case 15:
ret = offsetof(VexGuestMIPS64State, guest_w15);
break;
case 16:
ret = offsetof(VexGuestMIPS64State, guest_w16);
break;
case 17:
ret = offsetof(VexGuestMIPS64State, guest_w17);
break;
case 18:
ret = offsetof(VexGuestMIPS64State, guest_w18);
break;
case 19:
ret = offsetof(VexGuestMIPS64State, guest_w19);
break;
case 20:
ret = offsetof(VexGuestMIPS64State, guest_w20);
break;
case 21:
ret = offsetof(VexGuestMIPS64State, guest_w21);
break;
case 22:
ret = offsetof(VexGuestMIPS64State, guest_w22);
break;
case 23:
ret = offsetof(VexGuestMIPS64State, guest_w23);
break;
case 24:
ret = offsetof(VexGuestMIPS64State, guest_w24);
break;
case 25:
ret = offsetof(VexGuestMIPS64State, guest_w25);
break;
case 26:
ret = offsetof(VexGuestMIPS64State, guest_w26);
break;
case 27:
ret = offsetof(VexGuestMIPS64State, guest_w27);
break;
case 28:
ret = offsetof(VexGuestMIPS64State, guest_w28);
break;
case 29:
ret = offsetof(VexGuestMIPS64State, guest_w29);
break;
case 30:
ret = offsetof(VexGuestMIPS64State, guest_w30);
break;
case 31:
ret = offsetof(VexGuestMIPS64State, guest_w31);
break;
default:
vassert(0);
break;
}
} else {
switch (msaRegNo) {
case 0:
ret = offsetof(VexGuestMIPS32State, guest_w0);
break;
case 1:
ret = offsetof(VexGuestMIPS32State, guest_w1);
break;
case 2:
ret = offsetof(VexGuestMIPS32State, guest_w2);
break;
case 3:
ret = offsetof(VexGuestMIPS32State, guest_w3);
break;
case 4:
ret = offsetof(VexGuestMIPS32State, guest_w4);
break;
case 5:
ret = offsetof(VexGuestMIPS32State, guest_w5);
break;
case 6:
ret = offsetof(VexGuestMIPS32State, guest_w6);
break;
case 7:
ret = offsetof(VexGuestMIPS32State, guest_w7);
break;
case 8:
ret = offsetof(VexGuestMIPS32State, guest_w8);
break;
case 9:
ret = offsetof(VexGuestMIPS32State, guest_w9);
break;
case 10:
ret = offsetof(VexGuestMIPS32State, guest_w10);
break;
case 11:
ret = offsetof(VexGuestMIPS32State, guest_w11);
break;
case 12:
ret = offsetof(VexGuestMIPS32State, guest_w12);
break;
case 13:
ret = offsetof(VexGuestMIPS32State, guest_w13);
break;
case 14:
ret = offsetof(VexGuestMIPS32State, guest_w14);
break;
case 15:
ret = offsetof(VexGuestMIPS32State, guest_w15);
break;
case 16:
ret = offsetof(VexGuestMIPS32State, guest_w16);
break;
case 17:
ret = offsetof(VexGuestMIPS32State, guest_w17);
break;
case 18:
ret = offsetof(VexGuestMIPS32State, guest_w18);
break;
case 19:
ret = offsetof(VexGuestMIPS32State, guest_w19);
break;
case 20:
ret = offsetof(VexGuestMIPS32State, guest_w20);
break;
case 21:
ret = offsetof(VexGuestMIPS32State, guest_w21);
break;
case 22:
ret = offsetof(VexGuestMIPS32State, guest_w22);
break;
case 23:
ret = offsetof(VexGuestMIPS32State, guest_w23);
break;
case 24:
ret = offsetof(VexGuestMIPS32State, guest_w24);
break;
case 25:
ret = offsetof(VexGuestMIPS32State, guest_w25);
break;
case 26:
ret = offsetof(VexGuestMIPS32State, guest_w26);
break;
case 27:
ret = offsetof(VexGuestMIPS32State, guest_w27);
break;
case 28:
ret = offsetof(VexGuestMIPS32State, guest_w28);
break;
case 29:
ret = offsetof(VexGuestMIPS32State, guest_w29);
break;
case 30:
ret = offsetof(VexGuestMIPS32State, guest_w30);
break;
case 31:
ret = offsetof(VexGuestMIPS32State, guest_w31);
break;
default:
vassert(0);
break;
}
}
return ret;
}
/* Do a endian load of a 32-bit word, regardless of the endianness of the
underlying host. */
static inline UInt getUInt(const UChar * p)
{
UInt w = 0;
#if defined (_MIPSEL)
w = (w << 8) | p[3];
w = (w << 8) | p[2];
w = (w << 8) | p[1];
w = (w << 8) | p[0];
#elif defined (_MIPSEB)
w = (w << 8) | p[0];
w = (w << 8) | p[1];
w = (w << 8) | p[2];
w = (w << 8) | p[3];
#endif
return w;
}
#define BITS2(_b1,_b0) \
(((_b1) << 1) | (_b0))
#define BITS3(_b2,_b1,_b0) \
(((_b2) << 2) | ((_b1) << 1) | (_b0))
#define BITS4(_b3,_b2,_b1,_b0) \
(((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
#define BITS5(_b4,_b3,_b2,_b1,_b0) \
(((_b4) << 4) | BITS4((_b3),(_b2),(_b1),(_b0)))
#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \
((BITS2((_b5),(_b4)) << 4) \
| BITS4((_b3),(_b2),(_b1),(_b0)))
#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
| BITS4((_b3),(_b2),(_b1),(_b0)))
#define LOAD_STORE_PATTERN \
t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
if(!mode64) \
assign(t1, binop(Iop_Add32, getIReg(rs), \
mkU32(extend_s_16to32(imm)))); \
else \
assign(t1, binop(Iop_Add64, getIReg(rs), \
mkU64(extend_s_16to64(imm)))); \
#define LOAD_STORE_PATTERN_MSA(imm) \
t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
if (!mode64) \
assign(t1, binop(Iop_Add32, getIReg(ws), \
mkU32(extend_s_10to32(imm)))); \
else \
assign(t1, binop(Iop_Add64, getIReg(ws), \
mkU64(extend_s_10to64(imm)))); \
#define LOADX_STORE_PATTERN \
t1 = newTemp(mode64 ? Ity_I64 : Ity_I32); \
if(!mode64) \
assign(t1, binop(Iop_Add32, getIReg(regRs), getIReg(regRt))); \
else \
assign(t1, binop(Iop_Add64, getIReg(regRs), getIReg(regRt)));
#define LWX_SWX_PATTERN64 \
t2 = newTemp(Ity_I64); \
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL))); \
t4 = newTemp(Ity_I32); \
assign(t4, mkNarrowTo32( ty, binop(Iop_And64, \
mkexpr(t1), mkU64(0x3))));
#define LWX_SWX_PATTERN64_1 \
t2 = newTemp(Ity_I64); \
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL))); \
t4 = newTemp(Ity_I64); \
assign(t4, binop(Iop_And64, mkexpr(t1), mkU64(0x7)));
#define LWX_SWX_PATTERN \
t2 = newTemp(Ity_I32); \
assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFC))); \
t4 = newTemp(Ity_I32); \
assign(t4, binop(Iop_And32, mkexpr(t1), mkU32(0x00000003)))
#define SXXV_PATTERN(op) \
putIReg(rd, binop(op, \
getIReg(rt), \
unop(Iop_32to8, \
binop(Iop_And32, \
getIReg(rs), \
mkU32(0x0000001F) \
) \
) \
) \
)
#define SXXV_PATTERN64(op) \
putIReg(rd, mkWidenFrom32(ty, binop(op, \
mkNarrowTo32(ty, getIReg(rt)), \
unop(Iop_32to8, \
binop(Iop_And32, \
mkNarrowTo32(ty, getIReg(rs)), \
mkU32(0x0000001F) \
) \
) \
), True \
))
#define SXX_PATTERN(op) \
putIReg(rd, binop(op, getIReg(rt), mkU8(sa)));
#define ALU_PATTERN(op) \
putIReg(rd, binop(op, getIReg(rs), getIReg(rt)));
#define ALUI_PATTERN(op) \
putIReg(rt, binop(op, getIReg(rs), mkU32(imm)));
#define ALUI_PATTERN64(op) \
putIReg(rt, binop(op, getIReg(rs), mkU64(imm)));
#define ALU_PATTERN64(op) \
putIReg(rd, mkWidenFrom32(ty, binop(op, \
mkNarrowTo32(ty, getIReg(rs)), \
mkNarrowTo32(ty, getIReg(rt))), True));
#define FP_CONDITIONAL_CODE \
t3 = newTemp(Ity_I32); \
assign(t3, binop(Iop_And32, \
IRExpr_ITE( binop(Iop_CmpEQ32, mkU32(cc), mkU32(0)), \
binop(Iop_Shr32, getFCSR(), mkU8(23)), \
binop(Iop_Shr32, getFCSR(), mkU8(24+cc))), \
mkU32(0x1)));
#define ILLEGAL_INSTRUCTON \
putPC(mkU32(guest_PC_curr_instr + 4)); \
dres->jk_StopHere = Ijk_SigILL; \
dres->whatNext = Dis_StopHere;
#define LLADDR_INVALID \
(mode64 ? mkU64(0xFFFFFFFFFFFFFFFFULL) : mkU32(0xFFFFFFFF))
/*------------------------------------------------------------*/
/*--- Field helpers ---*/
/*------------------------------------------------------------*/
static Bool branch_or_jump(const UChar * addr)
{
UInt fmt;
UInt cins = getUInt(addr);
UInt opcode = get_opcode(cins);
UInt rt = get_rt(cins);
UInt function = get_function(cins);
/* bgtz, blez, bne, beq, jal */
if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04
|| opcode == 0x03 || opcode == 0x02) {
return True;
}
/* bgez */
if (opcode == 0x01 && rt == 0x01) {
return True;
}
/* bgezal */
if (opcode == 0x01 && rt == 0x11) {
return True;
}
/* bltzal */
if (opcode == 0x01 && rt == 0x10) {
return True;
}
/* bltz */
if (opcode == 0x01 && rt == 0x00) {
return True;
}
/* jalr */
if (opcode == 0x00 && function == 0x09) {
return True;
}
/* jr */
if (opcode == 0x00 && function == 0x08) {
return True;
}
if (opcode == 0x11) {
/* bc1f & bc1t */
fmt = get_fmt(cins);
if (fmt == 0x08) {
return True;
}
/* MSA branches */
/* bnz.df, bz.df */
if (fmt >= 0x18) {
return True;
}
/* bnz.v */
if (fmt == 0x0f) {
return True;
}
/* bz.v */
if (fmt == 0x0b) {
return True;
}
/* R6 branches */
/* bc1eqz */
if (fmt == 0x09) {
return True;
}
/* bc1nez */
if (fmt == 0x0D) {
return True;
}
}
/* bposge32 */
if (opcode == 0x01 && rt == 0x1c) {
return True;
}
/* Cavium Specific instructions. */
if (opcode == 0x32 || opcode == 0x3A || opcode == 0x36 || opcode == 0x3E) {
/* BBIT0, BBIT1, BBIT032, BBIT132 */
return True;
}
return False;
}
static Bool is_Branch_or_Jump_and_Link(const UChar * addr)
{
UInt cins = getUInt(addr);
UInt opcode = get_opcode(cins);
UInt rt = get_rt(cins);
UInt function = get_function(cins);
/* jal */
if (opcode == 0x02) {
return True;
}
/* bgezal or bal(r6) */
if (opcode == 0x01 && rt == 0x11) {
return True;
}
/* bltzal */
if (opcode == 0x01 && rt == 0x10) {
return True;
}
/* jalr */
if (opcode == 0x00 && function == 0x09) {
return True;
}
return False;
}
static Bool branch_or_link_likely(const UChar * addr)
{
UInt cins = getUInt(addr);
UInt opcode = get_opcode(cins);
UInt rt = get_rt(cins);
/* bgtzl, blezl, bnel, beql */
if (opcode == 0x17 || opcode == 0x16 || opcode == 0x15 || opcode == 0x14)
return True;
/* bgezl */
if (opcode == 0x01 && rt == 0x03)
return True;
/* bgezall */
if (opcode == 0x01 && rt == 0x13)
return True;
/* bltzall */
if (opcode == 0x01 && rt == 0x12)
return True;
/* bltzl */
if (opcode == 0x01 && rt == 0x02)
return True;
return False;
}
/*------------------------------------------------------------*/
/*--- Helper bits and pieces for creating IR fragments. ---*/
/*------------------------------------------------------------*/
/* Generate an expression for SRC rotated right by ROT. */
static IRExpr *genROR32(IRExpr * src, Int rot)
{
vassert(rot >= 0 && rot < 32);
if (rot == 0)
return src;
return binop(Iop_Or32, binop(Iop_Shl32, src, mkU8(32 - rot)),
binop(Iop_Shr32, src, mkU8(rot)));
}
static IRExpr *genRORV32(IRExpr * src, IRExpr * rs)
{
IRTemp t0 = newTemp(Ity_I8);
IRTemp t1 = newTemp(Ity_I8);
assign(t0, unop(Iop_32to8, binop(Iop_And32, rs, mkU32(0x0000001F))));
assign(t1, binop(Iop_Sub8, mkU8(32), mkexpr(t0)));
return binop(Iop_Or32, binop(Iop_Shl32, src, mkexpr(t1)),
binop(Iop_Shr32, src, mkexpr(t0)));
}
static void jmp_lit32 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr32 d32 )
{
vassert(dres->whatNext == Dis_Continue);
vassert(dres->len == 0);
vassert(dres->jk_StopHere == Ijk_INVALID);
dres->whatNext = Dis_StopHere;
dres->jk_StopHere = kind;
stmt( IRStmt_Put( OFFB_PC, mkU32(d32) ) );
}
static void jmp_lit64 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr64 d64 )
{
vassert(dres->whatNext == Dis_Continue);
vassert(dres->len == 0);
vassert(dres->jk_StopHere == Ijk_INVALID);
dres->whatNext = Dis_StopHere;
dres->jk_StopHere = kind;
stmt(IRStmt_Put(OFFB_PC, mkU64(d64)));
}
/* Get value from accumulator (helper function for MIPS32 DSP ASE instructions).
This function should be called before any other operation if widening
multiplications are used. */
IRExpr *getAcc(UInt acNo)
{
vassert(!mode64);
vassert(acNo <= 3);
return IRExpr_Get(accumulatorGuestRegOffset(acNo), Ity_I64);
}
/* Get value from DSPControl register (helper function for MIPS32 DSP ASE
instructions). */
IRExpr *getDSPControl(void)
{
vassert(!mode64);
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_DSPControl), Ity_I32);
}
/* Fetch a byte from the guest insn stream. */
static UChar getIByte(Int delta)
{
return guest_code[delta];
}
IRExpr *getIReg(UInt iregNo)
{
if (0 == iregNo) {
return mode64 ? mkU64(0x0) : mkU32(0x0);
} else {
IRType ty = mode64 ? Ity_I64 : Ity_I32;
vassert(iregNo < 32);
return IRExpr_Get(integerGuestRegOffset(iregNo), ty);
}
}
static IRExpr *getWReg(UInt wregNo)
{
vassert(wregNo <= 31);
return IRExpr_Get(msaGuestRegOffset(wregNo), Ity_V128);
}
static IRExpr *getHI(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_HI), Ity_I64);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_HI), Ity_I32);
}
static IRExpr *getLO(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LO), Ity_I64);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LO), Ity_I32);
}
static IRExpr *getFCSR(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_FCSR), Ity_I32);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_FCSR), Ity_I32);
}
static IRExpr *getLLaddr(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LLaddr), Ity_I64);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLaddr), Ity_I32);
}
static IRExpr *getLLdata(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LLdata), Ity_I64);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLdata), Ity_I32);
}
static IRExpr *getMSACSR(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_MSACSR), Ity_I32);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_MSACSR), Ity_I32);
}
/* Get byte from register reg, byte pos from 0 to 3 (or 7 for MIPS64) . */
static IRExpr *getByteFromReg(UInt reg, UInt byte_pos)
{
UInt pos = byte_pos * 8;
if (mode64)
return unop(Iop_64to8, binop(Iop_And64,
binop(Iop_Shr64, getIReg(reg), mkU8(pos)),
mkU64(0xFF)));
else
return unop(Iop_32to8, binop(Iop_And32,
binop(Iop_Shr32, getIReg(reg), mkU8(pos)),
mkU32(0xFF)));
}
static void putFCSR(IRExpr * e)
{
if (mode64)
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_FCSR), e));
else
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_FCSR), e));
}
static void putLLaddr(IRExpr * e)
{
if (mode64)
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLaddr), e));
else
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLaddr), e));
}
static void putLLdata(IRExpr * e)
{
if (mode64)
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLdata), e));
else
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata), e));
}
static void putMSACSR(IRExpr * e)
{
if (mode64)
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_MSACSR), e));
else
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_MSACSR), e));
}
/* fs - fpu source register number.
inst - fpu instruction that needs to be executed.
sz32 - size of source register.
opN - number of operads:
1 - unary operation.
2 - binary operation. */
static void calculateFCSR(UInt fs, UInt ft, UInt inst, Bool sz32, UInt opN)
{
IRDirty *d;
IRTemp fcsr = newTemp(Ity_I32);
/* IRExpr_GSPTR() => Need to pass pointer to guest state to helper. */
if (fp_mode64)
d = unsafeIRDirty_1_N(fcsr, 0,
"mips_dirtyhelper_calculate_FCSR_fp64",
&mips_dirtyhelper_calculate_FCSR_fp64,
mkIRExprVec_4(IRExpr_GSPTR(),
mkU32(fs),
mkU32(ft),
mkU32(inst)));
else
d = unsafeIRDirty_1_N(fcsr, 0,
"mips_dirtyhelper_calculate_FCSR_fp32",
&mips_dirtyhelper_calculate_FCSR_fp32,
mkIRExprVec_4(IRExpr_GSPTR(),
mkU32(fs),
mkU32(ft),
mkU32(inst)));
if (opN == 1) { /* Unary operation. */
/* Declare we're reading guest state. */
if (sz32 || fp_mode64)
d->nFxState = 2;
else
d->nFxState = 3;
vex_bzero(&d->fxState, sizeof(d->fxState));
d->fxState[0].fx = Ifx_Read; /* read */
if (mode64)
d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_FCSR);
else
d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_FCSR);
d->fxState[0].size = sizeof(UInt);
d->fxState[1].fx = Ifx_Read; /* read */
d->fxState[1].offset = floatGuestRegOffset(fs);
d->fxState[1].size = sizeof(ULong);
if (!(sz32 || fp_mode64)) {
d->fxState[2].fx = Ifx_Read; /* read */
d->fxState[2].offset = floatGuestRegOffset(fs + 1);
d->fxState[2].size = sizeof(ULong);
}
} else if (opN == 2) { /* Binary operation. */
/* Declare we're reading guest state. */
if (sz32 || fp_mode64)
d->nFxState = 3;
else
d->nFxState = 5;
vex_bzero(&d->fxState, sizeof(d->fxState));
d->fxState[0].fx = Ifx_Read; /* read */
if (mode64)
d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_FCSR);
else
d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_FCSR);
d->fxState[0].size = sizeof(UInt);
d->fxState[1].fx = Ifx_Read; /* read */
d->fxState[1].offset = floatGuestRegOffset(fs);
d->fxState[1].size = sizeof(ULong);
d->fxState[2].fx = Ifx_Read; /* read */
d->fxState[2].offset = floatGuestRegOffset(ft);
d->fxState[2].size = sizeof(ULong);
if (!(sz32 || fp_mode64)) {
d->fxState[3].fx = Ifx_Read; /* read */
d->fxState[3].offset = floatGuestRegOffset(fs + 1);
d->fxState[3].size = sizeof(ULong);
d->fxState[4].fx = Ifx_Read; /* read */
d->fxState[4].offset = floatGuestRegOffset(ft + 1);
d->fxState[4].size = sizeof(ULong);
}
}
stmt(IRStmt_Dirty(d));
putFCSR(mkexpr(fcsr));
}
/* ws, wt - source MSA register numbers.
inst - MSA fp instruction that needs to be executed.
opN - number of operads:
1 - unary operation.
2 - binary operation. */
static void calculateMSACSR(UInt ws, UInt wt, UInt inst, UInt opN)
{
IRDirty *d;
IRTemp msacsr = newTemp(Ity_I32);
/* IRExpr_BBPTR() => Need to pass pointer to guest state to helper. */
d = unsafeIRDirty_1_N(msacsr, 0,
"mips_dirtyhelper_calculate_MSACSR",
&mips_dirtyhelper_calculate_MSACSR,
mkIRExprVec_4(IRExpr_GSPTR(),
mkU32(ws),
mkU32(wt),
mkU32(inst)));
if (opN == 1) { /* Unary operation. */
/* Declare we're reading guest state. */
d->nFxState = 2;
vex_bzero(&d->fxState, sizeof(d->fxState));
d->fxState[0].fx = Ifx_Read; /* read */
if (mode64)
d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_MSACSR);
else
d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_MSACSR);
d->fxState[0].size = sizeof(UInt);
d->fxState[1].fx = Ifx_Read; /* read */
d->fxState[1].offset = msaGuestRegOffset(ws);
d->fxState[1].size = sizeof(ULong);
} else if (opN == 2) { /* Binary operation. */
/* Declare we're reading guest state. */
d->nFxState = 3;
vex_bzero(&d->fxState, sizeof(d->fxState));
d->fxState[0].fx = Ifx_Read; /* read */
if (mode64)
d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_MSACSR);
else
d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_MSACSR);
d->fxState[0].size = sizeof(UInt);
d->fxState[1].fx = Ifx_Read; /* read */
d->fxState[1].offset = msaGuestRegOffset(ws);
d->fxState[1].size = sizeof(ULong);
d->fxState[2].fx = Ifx_Read; /* read */
d->fxState[2].offset = msaGuestRegOffset(wt);
d->fxState[2].size = sizeof(ULong);
}
stmt(IRStmt_Dirty(d));
putMSACSR(mkexpr(msacsr));
}
static IRExpr *getULR(void)
{
if (mode64)
return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_ULR), Ity_I64);
else
return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR), Ity_I32);
}
void putIReg(UInt archreg, IRExpr * e)
{
IRType ty = mode64 ? Ity_I64 : Ity_I32;
vassert(archreg < 32);
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
if (archreg != 0)
stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
}
static void putWReg(UInt wregNo, IRExpr * e)
{
vassert(wregNo <= 31);
vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_V128);
stmt(IRStmt_Put(msaGuestRegOffset(wregNo), e));
stmt(IRStmt_Put(floatGuestRegOffset(wregNo),
unop(Iop_ReinterpI64asF64, unop(Iop_V128to64, e))));
}
IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
{
vassert(ty == Ity_I32 || ty == Ity_I64);
return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
}
void putLO(IRExpr * e)
{
if (mode64) {
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LO), e));
} else {
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LO), e));
/* Add value to lower 32 bits of ac0 to maintain compatibility between
regular MIPS32 instruction set and MIPS DSP ASE. Keep higher 32bits
unchanged. */
IRTemp t_lo = newTemp(Ity_I32);
IRTemp t_hi = newTemp(Ity_I32);
assign(t_lo, e);
assign(t_hi, unop(Iop_64HIto32, getAcc(0)));
stmt(IRStmt_Put(accumulatorGuestRegOffset(0),
binop(Iop_32HLto64, mkexpr(t_hi), mkexpr(t_lo))));
}
}
void putHI(IRExpr * e)
{
if (mode64) {
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_HI), e));
} else {
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_HI), e));
/* Add value to higher 32 bits of ac0 to maintain compatibility between
regular MIPS32 instruction set and MIPS DSP ASE. Keep lower 32bits
unchanged. */
IRTemp t_lo = newTemp(Ity_I32);
IRTemp t_hi = newTemp(Ity_I32);
assign(t_hi, e);
assign(t_lo, unop(Iop_64to32, getAcc(0)));
stmt(IRStmt_Put(accumulatorGuestRegOffset(0),
binop(Iop_32HLto64, mkexpr(t_hi), mkexpr(t_lo))));
}
}
static IRExpr *mkNarrowTo8 ( IRType ty, IRExpr * src )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
return ty == Ity_I64 ? unop(Iop_64to8, src) : unop(Iop_32to8, src);
}
static IRExpr *mkNarrowTo16 ( IRType ty, IRExpr * src )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
return ty == Ity_I64 ? unop(Iop_64to16, src) : unop(Iop_32to16, src);
}
static void putPC(IRExpr * e)
{
stmt(IRStmt_Put(OFFB_PC, e));
}
static IRExpr *mkWidenFrom32(IRType ty, IRExpr * src, Bool sined)
{
vassert(ty == Ity_I32 || ty == Ity_I64);
if (ty == Ity_I32)
return src;
return (sined) ? unop(Iop_32Sto64, src) : unop(Iop_32Uto64, src);
}
/* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some
of these combinations make sense. */
static IRExpr *narrowTo(IRType dst_ty, IRExpr * e)
{
IRType src_ty = typeOfIRExpr(irsb->tyenv, e);
if (src_ty == dst_ty)
return e;
if (src_ty == Ity_I32 && dst_ty == Ity_I16)
return unop(Iop_32to16, e);
if (src_ty == Ity_I32 && dst_ty == Ity_I8)
return unop(Iop_32to8, e);
if (src_ty == Ity_I64 && dst_ty == Ity_I8) {
vassert(mode64);
return unop(Iop_64to8, e);
}
if (src_ty == Ity_I64 && dst_ty == Ity_I16) {
vassert(mode64);
return unop(Iop_64to16, e);
}
vpanic("narrowTo(mips)");
return 0;
}
static IRExpr *getLoFromF64(IRType ty, IRExpr * src)
{
vassert(ty == Ity_F32 || ty == Ity_F64);
if (ty == Ity_F64) {
IRTemp t0, t1;
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
assign(t0, unop(Iop_ReinterpF64asI64, src));
assign(t1, unop(Iop_64to32, mkexpr(t0)));
return unop(Iop_ReinterpI32asF32, mkexpr(t1));
} else
return src;
}
static inline IRExpr *getHiFromF64(IRExpr * src)
{
vassert(typeOfIRExpr(irsb->tyenv, src) == Ity_F64);
return unop(Iop_ReinterpI32asF32, unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64, src)));
}
static IRExpr *mkWidenFromF32(IRType ty, IRExpr * src)
{
vassert(ty == Ity_F32 || ty == Ity_F64);
if (ty == Ity_F64) {
IRTemp t0 = newTemp(Ity_I32);
IRTemp t1 = newTemp(Ity_I64);
assign(t0, unop(Iop_ReinterpF32asI32, src));
assign(t1, binop(Iop_32HLto64, mkU32(0x0), mkexpr(t0)));
return unop(Iop_ReinterpI64asF64, mkexpr(t1));
} else
return src;
}
/* Convenience function to move to next instruction on condition. */
static void mips_next_insn_if(IRExpr *condition)
{
vassert(typeOfIRExpr(irsb->tyenv, condition) == Ity_I1);
stmt(IRStmt_Exit(condition, Ijk_Boring,
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm)
{
ULong branch_offset;
IRTemp t0;
/* PC = PC + (SignExtend(signed_immed_24) << 2)
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following
the branch (not the branch itself), in the branch delay slot, to form
a PC-relative effective target address. */
if (mode64)
branch_offset = extend_s_18to64(imm << 2);
else
branch_offset = extend_s_18to32(imm << 2);
t0 = newTemp(Ity_I1);
assign(t0, guard);
if (mode64)
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U64(guest_PC_curr_instr + 8), OFFB_PC));
else
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U32(guest_PC_curr_instr + 8), OFFB_PC));
irsb->jumpkind = Ijk_Boring;
if (mode64)
return mkU64(guest_PC_curr_instr + 4 + branch_offset);
else
return mkU32(guest_PC_curr_instr + 4 + branch_offset);
}
static void dis_branch(Bool link, IRExpr * guard, UInt imm, IRStmt ** set)
{
ULong branch_offset;
IRTemp t0;
if (link) { /* LR (GPR31) = addr of the 2nd instr after branch instr */
if (mode64)
putIReg(31, mkU64(guest_PC_curr_instr + 8));
else
putIReg(31, mkU32(guest_PC_curr_instr + 8));
}
/* PC = PC + (SignExtend(signed_immed_24) << 2)
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following
the branch (not the branch itself), in the branch delay slot, to form
a PC-relative effective target address. */
if (mode64)
branch_offset = extend_s_18to64(imm << 2);
else
branch_offset = extend_s_18to32(imm << 2);
t0 = newTemp(Ity_I1);
assign(t0, guard);
if (mode64)
*set = IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
IRConst_U64(guest_PC_curr_instr + 4 + branch_offset),
OFFB_PC);
else
*set = IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
IRConst_U32(guest_PC_curr_instr + 4 +
(UInt) branch_offset), OFFB_PC);
}
static void dis_branch_compact(Bool link, IRExpr * guard, UInt imm,
DisResult *dres)
{
ULong branch_offset;
IRTemp t0;
if (link) { /* LR (GPR31) = addr of the instr after branch instr */
if (mode64)
putIReg(31, mkU64(guest_PC_curr_instr + 4));
else
putIReg(31, mkU32(guest_PC_curr_instr + 4));
dres->jk_StopHere = Ijk_Call;
} else {
dres->jk_StopHere = Ijk_Boring;
}
dres->whatNext = Dis_StopHere;
/* PC = PC + (SignExtend(signed_immed_24) << 2)
An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
is added to the address of the instruction following
the branch (not the branch itself), in the branch delay slot, to form
a PC-relative effective target address. */
if (mode64)
branch_offset = extend_s_18to64(imm << 2);
else
branch_offset = extend_s_18to32(imm << 2);
t0 = newTemp(Ity_I1);
assign(t0, guard);
if (mode64) {
stmt(IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
IRConst_U64(guest_PC_curr_instr + 4 + branch_offset),
OFFB_PC));
putPC(mkU64(guest_PC_curr_instr + 4));
} else {
stmt(IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
IRConst_U32(guest_PC_curr_instr + 4 +
(UInt) branch_offset), OFFB_PC));
putPC(mkU32(guest_PC_curr_instr + 4));
}
}
static IRExpr *getFReg(UInt fregNo)
{
vassert(fregNo < 32);
IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
return IRExpr_Get(floatGuestRegOffset(fregNo), ty);
}
static IRExpr *getDReg(UInt dregNo)
{
vassert(dregNo < 32);
if (fp_mode64) {
return IRExpr_Get(floatGuestRegOffset(dregNo), Ity_F64);
} else {
/* Read a floating point register pair and combine their contents into a
64-bit value */
IRTemp t0 = newTemp(Ity_F32);
IRTemp t1 = newTemp(Ity_F32);
IRTemp t2 = newTemp(Ity_F64);
IRTemp t3 = newTemp(Ity_I32);
IRTemp t4 = newTemp(Ity_I32);
IRTemp t5 = newTemp(Ity_I64);
assign(t0, getFReg(dregNo & (~1)));
assign(t1, getFReg(dregNo | 1));
assign(t3, unop(Iop_ReinterpF32asI32, mkexpr(t0)));
assign(t4, unop(Iop_ReinterpF32asI32, mkexpr(t1)));
assign(t5, binop(Iop_32HLto64, mkexpr(t4), mkexpr(t3)));
assign(t2, unop(Iop_ReinterpI64asF64, mkexpr(t5)));
return mkexpr(t2);
}
}
static void putFReg(UInt dregNo, IRExpr * e)
{
vassert(dregNo < 32);
IRType ty = fp_mode64 ? Ity_F64 : Ity_F32;
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
if (fp_mode64_fre) {
IRTemp t0 = newTemp(Ity_F32);
assign(t0, getLoFromF64(ty, e));
#if defined (_MIPSEL)
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), mkexpr(t0)));
if (dregNo & 1)
stmt(IRStmt_Put(floatGuestRegOffset(dregNo) - 4, mkexpr(t0)));
#else
stmt(IRStmt_Put(floatGuestRegOffset(dregNo) + 4, mkexpr(t0)));
if (dregNo & 1)
stmt(IRStmt_Put(floatGuestRegOffset(dregNo & (~1)), mkexpr(t0)));
#endif
} else {
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
}
if (has_msa && fp_mode64) {
stmt(IRStmt_Put(msaGuestRegOffset(dregNo),
binop(Iop_64HLtoV128,
unop(Iop_ReinterpF64asI64, e),
unop(Iop_ReinterpF64asI64, e))));
}
}
static void putDReg(UInt dregNo, IRExpr * e)
{
if (fp_mode64) {
vassert(dregNo < 32);
IRType ty = Ity_F64;
vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
if (fp_mode64_fre) {
IRTemp t0 = newTemp(Ity_F32);
if (dregNo & 1) {
assign(t0, getLoFromF64(ty, e));
#if defined (_MIPSEL)
stmt(IRStmt_Put(floatGuestRegOffset(dregNo) - 4, mkexpr(t0)));
#else
stmt(IRStmt_Put(floatGuestRegOffset(dregNo & (~1)), mkexpr(t0)));
#endif
} else {
assign(t0, getHiFromF64(e));
#if defined (_MIPSEL)
stmt(IRStmt_Put(floatGuestRegOffset(dregNo | 1), mkexpr(t0)));
#else
stmt(IRStmt_Put(floatGuestRegOffset(dregNo | 1) + 4, mkexpr(t0)));
#endif
}
}
if (has_msa)
stmt(IRStmt_Put(msaGuestRegOffset(dregNo),
binop(Iop_64HLtoV128,
unop(Iop_ReinterpF64asI64, e),
unop(Iop_ReinterpF64asI64, e))));
} else {
vassert(dregNo < 32);
vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
IRTemp t1 = newTemp(Ity_F64);
IRTemp t4 = newTemp(Ity_I32);
IRTemp t5 = newTemp(Ity_I32);
IRTemp t6 = newTemp(Ity_I64);
assign(t1, e);
assign(t6, unop(Iop_ReinterpF64asI64, mkexpr(t1)));
assign(t4, unop(Iop_64HIto32, mkexpr(t6))); /* hi */
assign(t5, unop(Iop_64to32, mkexpr(t6))); /* lo */
putFReg(dregNo & (~1), unop(Iop_ReinterpI32asF32, mkexpr(t5)));
putFReg(dregNo | 1, unop(Iop_ReinterpI32asF32, mkexpr(t4)));
}
}
static void setFPUCondCode(IRExpr * e, UInt cc)
{
if (cc == 0) {
putFCSR(binop(Iop_And32, getFCSR(), mkU32(0xFF7FFFFF)));
putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(23))));
} else {
putFCSR(binop(Iop_And32, getFCSR(), unop(Iop_Not32,
binop(Iop_Shl32, mkU32(0x01000000), mkU8(cc)))));
putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(24 + cc))));
}
}
static IRExpr* get_IR_roundingmode ( void )
{
/*
rounding mode | MIPS | IR
------------------------
to nearest | 00 | 00
to zero | 01 | 11
to +infinity | 10 | 10
to -infinity | 11 | 01
*/
IRTemp rm_MIPS = newTemp(Ity_I32);
/* Last two bits in FCSR are rounding mode. */
if (mode64)
assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS64State,
guest_FCSR), Ity_I32), mkU32(3)));
else
assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS32State,
guest_FCSR), Ity_I32), mkU32(3)));
/* rm_IR = XOR( rm_MIPS32, (rm_MIPS32 << 1) & 2) */
return binop(Iop_Xor32, mkexpr(rm_MIPS), binop(Iop_And32,
binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2)));
}
static IRExpr* get_IR_roundingmode_MSA ( void )
{
/*
rounding mode | MIPS | IR
------------------------
to nearest | 00 | 00
to zero | 01 | 11
to +infinity | 10 | 10
to -infinity | 11 | 01
*/
IRTemp rm_MIPS = newTemp(Ity_I32);
/* Last two bits in MSACSR are rounding mode. */
if (mode64)
assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS64State,
guest_MSACSR), Ity_I32), mkU32(3)));
else
assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS32State,
guest_MSACSR), Ity_I32), mkU32(3)));
/* rm_IR = XOR( rm_MIPS32, (rm_MIPS32 << 1) & 2) */
return binop(Iop_Xor32, mkexpr(rm_MIPS), binop(Iop_And32,
binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2)));
}
/* sz, ULong -> IRExpr */
static IRExpr *mkSzImm ( IRType ty, ULong imm64 )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
return ty == Ity_I64 ? mkU64(imm64) : mkU32((UInt) imm64);
}
static IRConst *mkSzConst ( IRType ty, ULong imm64 )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
return (ty == Ity_I64 ? IRConst_U64(imm64) : IRConst_U32((UInt) imm64));
}
/* Make sure we get valid 32 and 64bit addresses */
static Addr64 mkSzAddr ( IRType ty, Addr64 addr )
{
vassert(ty == Ity_I32 || ty == Ity_I64);
return (ty == Ity_I64 ? (Addr64) addr :
(Addr64) extend_s_32to64(toUInt(addr)));
}
/* Shift and Rotate instructions for MIPS64 */
static Bool dis_instr_shrt ( UInt theInstr )
{
UInt opc2 = get_function(theInstr);
UChar regRs = get_rs(theInstr);
UChar regRt = get_rt(theInstr);
UChar regRd = get_rd(theInstr);
UChar uImmsa = get_sa(theInstr);
Long sImmsa = extend_s_16to64(uImmsa);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp tmp = newTemp(ty);
IRTemp tmpOr = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRd = newTemp(ty);
assign(tmpRs, getIReg(regRs));
assign(tmpRt, getIReg(regRt));
switch (opc2) {
case 0x3A:
if ((regRs & 0x01) == 0) {
/* Doubleword Shift Right Logical - DSRL; MIPS64 */
DIP("dsrl r%u, r%u, %lld", regRd, regRt, sImmsa);
assign(tmpRd, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa)));
putIReg(regRd, mkexpr(tmpRd));
} else if ((regRs & 0x01) == 1) {
/* Doubleword Rotate Right - DROTR; MIPS64r2 */
vassert(mode64);
DIP("drotr r%u, r%u, %lld", regRd, regRt, sImmsa);
IRTemp tmpL = newTemp(ty);
IRTemp tmpR = newTemp(ty);
assign(tmpR, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa)));
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(63 - uImmsa)));
assign(tmpL, binop(Iop_Shl64, mkexpr(tmp), mkU8(1)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpL), mkexpr(tmpR)));
putIReg(regRd, mkexpr(tmpRd));
} else
return False;
break;
case 0x3E:
if ((regRs & 0x01) == 0) {
/* Doubleword Shift Right Logical Plus 32 - DSRL32; MIPS64 */
DIP("dsrl32 r%u, r%u, %lld", regRd, regRt, sImmsa + 32);
assign(tmpRd, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
putIReg(regRd, mkexpr(tmpRd));
} else if ((regRs & 0x01) == 1) {
/* Doubleword Rotate Right Plus 32 - DROTR32; MIPS64r2 */
DIP("drotr32 r%u, r%u, %lld", regRd, regRt, sImmsa);
vassert(mode64);
IRTemp tmpL = newTemp(ty);
IRTemp tmpR = newTemp(ty);
/* (tmpRt >> sa) | (tmpRt << (64 - sa)) */
assign(tmpR, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRt),
mkU8(63 - (uImmsa + 32))));
assign(tmpL, binop(Iop_Shl64, mkexpr(tmp), mkU8(1)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpL), mkexpr(tmpR)));
putIReg(regRd, mkexpr(tmpRd));
} else
return False;
break;
case 0x16:
if ((uImmsa & 0x01) == 0) {
/* Doubleword Shift Right Logical Variable - DSRLV; MIPS64 */
DIP("dsrlv r%u, r%u, r%u", regRd, regRt, regRs);
IRTemp tmpRs8 = newTemp(Ity_I8);
/* s = tmpRs[5..0] */
assign(tmp, binop(Iop_And64, mkexpr(tmpRs), mkU64(63)));
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
assign(tmpRd, binop(Iop_Shr64, mkexpr(tmpRt), mkexpr(tmpRs8)));
putIReg(regRd, mkexpr(tmpRd));
} else if ((uImmsa & 0x01) == 1) {
/* Doubleword Rotate Right Variable - DROTRV; MIPS64r2 */
DIP("drotrv r%u, r%u, r%u", regRd, regRt, regRs);
IRTemp tmpL = newTemp(ty);
IRTemp tmpR = newTemp(ty);
IRTemp tmpRs8 = newTemp(Ity_I8);
IRTemp tmpLs8 = newTemp(Ity_I8);
IRTemp tmp64 = newTemp(ty);
/* s = tmpRs[5...0]
m = 64 - s
(tmpRt << s) | (tmpRt >> m) */
assign(tmp64, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63)));
assign(tmp, binop(Iop_Sub64, mkU64(63), mkexpr(tmp64)));
assign(tmpLs8, mkNarrowTo8(ty, mkexpr(tmp)));
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp64)));
assign(tmpR, binop(Iop_Shr64, mkexpr(tmpRt), mkexpr(tmpRs8)));
assign(tmpL, binop(Iop_Shl64, mkexpr(tmpRt), mkexpr(tmpLs8)));
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpL), mkU8(1)));
assign(tmpOr, binop(Iop_Or64, mkexpr(tmpRd), mkexpr(tmpR)));
putIReg(regRd, mkexpr(tmpOr));
} else
return False;
break;
case 0x38: /* Doubleword Shift Left Logical - DSLL; MIPS64 */
DIP("dsll r%u, r%u, %lld", regRd, regRt, sImmsa);
vassert(mode64);
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(uImmsa)));
putIReg(regRd, mkexpr(tmpRd));
break;
case 0x3C: /* Doubleword Shift Left Logical Plus 32 - DSLL32; MIPS64 */
DIP("dsll32 r%u, r%u, %lld", regRd, regRt, sImmsa);
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
putIReg(regRd, mkexpr(tmpRd));
break;
case 0x14: { /* Doubleword Shift Left Logical Variable - DSLLV; MIPS64 */
DIP("dsllv r%u, r%u, r%u", regRd, regRt, regRs);
IRTemp tmpRs8 = newTemp(Ity_I8);
assign(tmp, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63)));
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
assign(tmpRd, binop(Iop_Shl64, mkexpr(tmpRt), mkexpr(tmpRs8)));
putIReg(regRd, mkexpr(tmpRd));
break;
}
case 0x3B: /* Doubleword Shift Right Arithmetic - DSRA; MIPS64 */
DIP("dsra r%u, r%u, %lld", regRd, regRt, sImmsa);
assign(tmpRd, binop(Iop_Sar64, mkexpr(tmpRt), mkU8(uImmsa)));
putIReg(regRd, mkexpr(tmpRd));
break;
case 0x3F: /* Doubleword Shift Right Arithmetic Plus 32 - DSRA32;
MIPS64 */
DIP("dsra32 r%u, r%u, %lld", regRd, regRt, sImmsa);
assign(tmpRd, binop(Iop_Sar64, mkexpr(tmpRt), mkU8(uImmsa + 32)));
putIReg(regRd, mkexpr(tmpRd));
break;
case 0x17: {
/* Doubleword Shift Right Arithmetic Variable - DSRAV;
MIPS64 */
DIP("dsrav r%u, r%u, r%u", regRd, regRt, regRs);
IRTemp tmpRs8 = newTemp(Ity_I8);
assign(tmp, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63)));
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
assign(tmpRd, binop(Iop_Sar64, mkexpr(tmpRt), mkexpr(tmpRs8)));
putIReg(regRd, mkexpr(tmpRd));
break;
}
default:
return False;
}
return True;
}
static IROp mkSzOp ( IRType ty, IROp op8 )
{
Int adj;
vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I64);
vassert(op8 == Iop_Add8 || op8 == Iop_Sub8 || op8 == Iop_Mul8
|| op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
|| op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
|| op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8 || op8 == Iop_Not8);
adj = ty == Ity_I8 ? 0 : (ty == Ity_I16 ? 1 : (ty == Ity_I32 ? 2 : 3));
return adj + op8;
}
/*********************************************************/
/*--- Floating Point Compare ---*/
/*********************************************************/
/* Function that returns a string that represent mips cond
mnemonic for the input code. */
static const HChar* showCondCode(UInt code)
{
const HChar* ret;
switch (code) {
case 0:
ret = "f";
break;
case 1:
ret = "un";
break;
case 2:
ret = "eq";
break;
case 3:
ret = "ueq";
break;
case 4:
ret = "olt";
break;
case 5:
ret = "ult";
break;
case 6:
ret = "ole";
break;
case 7:
ret = "ule";
break;
case 8:
ret = "sf";
break;
case 9:
ret = "ngle";
break;
case 10:
ret = "seq";
break;
case 11:
ret = "ngl";
break;
case 12:
ret = "lt";
break;
case 13:
ret = "nge";
break;
case 14:
ret = "le";
break;
case 15:
ret = "ngt";
break;
default:
vpanic("showCondCode");
break;
}
return ret;
}
static Bool dis_instr_CCondFmt ( UInt cins )
{
IRTemp t0, t1, t2, t3, tmp5, tmp6;
IRTemp ccIR = newTemp(Ity_I32);
IRTemp ccMIPS = newTemp(Ity_I32);
UInt FC = get_FC(cins);
UInt fmt = get_fmt(cins);
UInt fs = get_fs(cins);
UInt ft = get_ft(cins);
UInt cond = get_cond(cins);
if (FC == 0x3) { /* C.cond.fmt */
UInt fpc_cc = get_fpc_cc(cins);
switch (fmt) {
case 0x10: { /* C.cond.S */
DIP("c.%s.s %u, f%u, f%u", showCondCode(cond), fpc_cc, fs, ft);
if (fp_mode64) {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
tmp5 = newTemp(Ity_F64);
tmp6 = newTemp(Ity_F64);
assign(tmp5, unop(Iop_F32toF64, getLoFromF64(Ity_F64,
getFReg(fs))));
assign(tmp6, unop(Iop_F32toF64, getLoFromF64(Ity_F64,
getFReg(ft))));
assign(ccIR, binop(Iop_CmpF64, mkexpr(tmp5), mkexpr(tmp6)));
putHI(mkWidenFrom32(mode64 ? Ity_I64 : Ity_I32,
mkexpr(ccIR), True));
/* Map compare result from IR to MIPS
FP cmp result | MIPS | IR
--------------------------
UN | 0x1 | 0x45
EQ | 0x2 | 0x40
GT | 0x4 | 0x00
LT | 0x8 | 0x01
*/
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))), mkU32(2)),
binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
putLO(mkWidenFrom32(mode64 ? Ity_I64 : Ity_I32,
mkexpr(ccMIPS), True));
/* UN */
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
/* EQ */
assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
mkU8(0x1)), mkU32(0x1)));
/* NGT */
assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1)));
/* LT */
assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
mkU8(0x3)), mkU32(0x1)));
switch (cond) {
case 0x0:
setFPUCondCode(mkU32(0), fpc_cc);
break;
case 0x1:
setFPUCondCode(mkexpr(t0), fpc_cc);
break;
case 0x2:
setFPUCondCode(mkexpr(t1), fpc_cc);
break;
case 0x3:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
fpc_cc);
break;
case 0x4:
setFPUCondCode(mkexpr(t3), fpc_cc);
break;
case 0x5:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
fpc_cc);
break;
case 0x6:
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
fpc_cc);
break;
case 0x7:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
case 0x8:
setFPUCondCode(mkU32(0), fpc_cc);
break;
case 0x9:
setFPUCondCode(mkexpr(t0), fpc_cc);
break;
case 0xA:
setFPUCondCode(mkexpr(t1), fpc_cc);
break;
case 0xB:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
fpc_cc);
break;
case 0xC:
setFPUCondCode(mkexpr(t3), fpc_cc);
break;
case 0xD:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
fpc_cc);
break;
case 0xE:
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
fpc_cc);
break;
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
default:
return False;
}
} else {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
assign(ccIR, binop(Iop_CmpF64, unop(Iop_F32toF64, getFReg(fs)),
unop(Iop_F32toF64, getFReg(ft))));
/* Map compare result from IR to MIPS
FP cmp result | MIPS | IR
--------------------------
UN | 0x1 | 0x45
EQ | 0x2 | 0x40
GT | 0x4 | 0x00
LT | 0x8 | 0x01
*/
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))),
mkU32(2)), binop(Iop_And32,
binop(Iop_Xor32, mkexpr(ccIR),
binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
/* UN */
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
/* EQ */
assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
mkU8(0x1)), mkU32(0x1)));
/* NGT */
assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1)));
/* LT */
assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
mkU8(0x3)), mkU32(0x1)));
switch (cond) {
case 0x0:
setFPUCondCode(mkU32(0), fpc_cc);
break;
case 0x1:
setFPUCondCode(mkexpr(t0), fpc_cc);
break;
case 0x2:
setFPUCondCode(mkexpr(t1), fpc_cc);
break;
case 0x3:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
fpc_cc);
break;
case 0x4:
setFPUCondCode(mkexpr(t3), fpc_cc);
break;
case 0x5:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
fpc_cc);
break;
case 0x6:
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
fpc_cc);
break;
case 0x7:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
case 0x8:
setFPUCondCode(mkU32(0), fpc_cc);
break;
case 0x9:
setFPUCondCode(mkexpr(t0), fpc_cc);
break;
case 0xA:
setFPUCondCode(mkexpr(t1), fpc_cc);
break;
case 0xB:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
fpc_cc);
break;
case 0xC:
setFPUCondCode(mkexpr(t3), fpc_cc);
break;
case 0xD:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
fpc_cc);
break;
case 0xE:
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
fpc_cc);
break;
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
default:
return False;
}
}
}
break;
case 0x11: { /* C.cond.D */
DIP("c.%s.d %u, f%u, f%u", showCondCode(cond), fpc_cc, fs, ft);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
assign(ccIR, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
/* Map compare result from IR to MIPS
FP cmp result | MIPS | IR
--------------------------
UN | 0x1 | 0x45
EQ | 0x2 | 0x40
GT | 0x4 | 0x00
LT | 0x8 | 0x01
*/
/* ccMIPS = Shl(1, (~(ccIR>>5) & 2) | ((ccIR ^ (ccIR>>6)) & 1) */
assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))), mkU32(2)),
binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
mkU32(1))))));
/* UN */
assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1)));
/* EQ */
assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
mkU8(0x1)), mkU32(0x1)));
/* NGT */
assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1)));
/* LT */
assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
mkU8(0x3)), mkU32(0x1)));
switch (cond) {
case 0x0:
setFPUCondCode(mkU32(0), fpc_cc);
break;
case 0x1:
setFPUCondCode(mkexpr(t0), fpc_cc);
break;
case 0x2:
setFPUCondCode(mkexpr(t1), fpc_cc);
break;
case 0x3:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
fpc_cc);
break;
case 0x4:
setFPUCondCode(mkexpr(t3), fpc_cc);
break;
case 0x5:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
fpc_cc);
break;
case 0x6:
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
fpc_cc);
break;
case 0x7:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
case 0x8:
setFPUCondCode(mkU32(0), fpc_cc);
break;
case 0x9:
setFPUCondCode(mkexpr(t0), fpc_cc);
break;
case 0xA:
setFPUCondCode(mkexpr(t1), fpc_cc);
break;
case 0xB:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
fpc_cc);
break;
case 0xC:
setFPUCondCode(mkexpr(t3), fpc_cc);
break;
case 0xD:
setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
fpc_cc);
break;
case 0xE:
setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
fpc_cc);
break;
case 0xF:
setFPUCondCode(mkexpr(t2), fpc_cc);
break;
default:
return False;
}
}
break;
default:
return False;
}
} else {
return False;
}
return True;
}
/*********************************************************/
/*--- Branch Instructions for mips64 ---*/
/*********************************************************/
static Bool dis_instr_branch ( UInt theInstr, DisResult * dres, IRStmt ** set )
{
UInt jmpKind = 0;
UChar opc1 = get_opcode(theInstr);
UChar regRs = get_rs(theInstr);
UChar regRt = get_rt(theInstr);
UInt offset = get_imm(theInstr);
Long sOffset = extend_s_16to64(offset);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IROp opSlt = mode64 ? Iop_CmpLT64S : Iop_CmpLT32S;
IRTemp tmp = newTemp(ty);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp tmpLt = newTemp(ty);
IRTemp tmpReg0 = newTemp(ty);
UChar regLnk = 31; /* reg 31 is link reg in MIPS */
Addr64 addrTgt = 0;
Addr64 cia = guest_PC_curr_instr;
IRExpr *eConst0 = mkSzImm(ty, (UInt) 0);
IRExpr *eNia = mkSzImm(ty, cia + 8);
IRExpr *eCond = NULL;
assign(tmpRs, getIReg(regRs));
assign(tmpRt, getIReg(regRt));
assign(tmpReg0, getIReg(0));
eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpReg0), mkexpr(tmpReg0));
switch (opc1) {
case 0x01:
switch (regRt) {
case 0x00: { /* BLTZ rs, offset */
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
IRTemp tmpLtRes = newTemp(Ity_I1);
assign(tmp, eConst0);
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp)));
assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) :
unop(Iop_1Uto32, mkexpr(tmpLtRes)));
eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpLt),
mkexpr(tmpReg0));
jmpKind = Ijk_Boring;
break;
}
case 0x01: { /* BGEZ rs, offset */
IRTemp tmpLtRes = newTemp(Ity_I1);
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
assign(tmp, eConst0);
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp)));
assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) :
unop(Iop_1Uto32, mkexpr(tmpLtRes)));
eCond = binop(mkSzOp(ty, Iop_CmpEQ8), mkexpr(tmpLt),
mkexpr(tmpReg0));
jmpKind = Ijk_Boring;
break;
}
case 0x11: { /* BGEZAL rs, offset */
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
putIReg(regLnk, eNia);
IRTemp tmpLtRes = newTemp(Ity_I1);
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), eConst0));
assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) :
unop(Iop_1Uto32, mkexpr(tmpLtRes)));
eCond = binop(mkSzOp(ty, Iop_CmpEQ8), mkexpr(tmpLt),
mkexpr(tmpReg0));
jmpKind = Ijk_Call;
break;
}
case 0x10: { /* BLTZAL rs, offset */
IRTemp tmpLtRes = newTemp(Ity_I1);
IRTemp tmpRes = newTemp(ty);
addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2));
putIReg(regLnk, eNia);
assign(tmp, eConst0);
assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp)));
assign(tmpRes, mode64 ? unop(Iop_1Uto64,
mkexpr(tmpLtRes)) : unop(Iop_1Uto32, mkexpr(tmpLtRes)));
eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpRes),
mkexpr(tmpReg0));
jmpKind = Ijk_Call;
break;
}
}
break;
default:
return False;
}
*set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC);
return True;
}
/*********************************************************/
/*--- Cavium Specific Instructions ---*/
/*********************************************************/
/* Convenience function to yield to thread scheduler */
static void jump_back(IRExpr *condition)
{
stmt( IRStmt_Exit(condition,
Ijk_Yield,
IRConst_U64( guest_PC_curr_instr ),
OFFB_PC) );
}
/* Based on s390_irgen_load_and_add32. */
static void mips_load_store32(IRTemp op1addr, IRTemp new_val,
IRTemp expd, UChar rd, Bool putIntoRd)
{
IRCAS *cas;
IRTemp old_mem = newTemp(Ity_I32);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
cas = mkIRCAS(IRTemp_INVALID, old_mem,
#if defined (_MIPSEL)
Iend_LE, mkexpr(op1addr),
#else /* _MIPSEB */
Iend_BE, mkexpr(op1addr),
#endif
NULL, mkexpr(expd), /* expected value */
NULL, mkexpr(new_val) /* new value */);
stmt(IRStmt_CAS(cas));
/* If old_mem contains the expected value, then the CAS succeeded.
Otherwise, it did not */
jump_back(binop(Iop_CmpNE32, mkexpr(old_mem), mkexpr(expd)));
if (putIntoRd)
putIReg(rd, mkWidenFrom32(ty, mkexpr(old_mem), True));
}
/* Based on s390_irgen_load_and_add64. */
static void mips_load_store64(IRTemp op1addr, IRTemp new_val,
IRTemp expd, UChar rd, Bool putIntoRd)
{
IRCAS *cas;
IRTemp old_mem = newTemp(Ity_I64);
vassert(mode64);
cas = mkIRCAS(IRTemp_INVALID, old_mem,
#if defined (_MIPSEL)
Iend_LE, mkexpr(op1addr),
#else /* _MIPSEB */
Iend_BE, mkexpr(op1addr),
#endif
NULL, mkexpr(expd), /* expected value */
NULL, mkexpr(new_val) /* new value */);
stmt(IRStmt_CAS(cas));
/* If old_mem contains the expected value, then the CAS succeeded.
Otherwise, it did not */
jump_back(binop(Iop_CmpNE64, mkexpr(old_mem), mkexpr(expd)));
if (putIntoRd)
putIReg(rd, mkexpr(old_mem));
}
static Bool dis_instr_CVM ( UInt theInstr )
{
UChar opc2 = get_function(theInstr);
UChar opc1 = get_opcode(theInstr);
UChar regRs = get_rs(theInstr);
UChar regRt = get_rt(theInstr);
UChar regRd = get_rd(theInstr);
/* MIPS trap instructions extract code from theInstr[15:6].
Cavium OCTEON instructions SNEI, SEQI extract immediate operands
from the same bit field [15:6]. */
UInt imm = get_code(theInstr);
UChar lenM1 = get_msb(theInstr);
UChar p = get_lsb(theInstr);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRTemp tmp = newTemp(ty);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp t1 = newTemp(ty);
UInt size;
assign(tmpRs, getIReg(regRs));
switch (opc1) {
case 0x1C: {
switch (opc2) {
case 0x03: { /* DMUL rd, rs, rt */
DIP("dmul r%u, r%u, r%u", regRd, regRs, regRt);
IRTemp t0 = newTemp(Ity_I128);
assign(t0, binop(Iop_MullU64, getIReg(regRs), getIReg(regRt)));
putIReg(regRd, unop(Iop_128to64, mkexpr(t0)));
break;
}
case 0x18: { /* Store Atomic Add Word - SAA; Cavium OCTEON */
DIP("saa r%u, (r%u)", regRt, regRs);
IRTemp addr = newTemp(Ity_I64);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I32, mkexpr(addr)));
assign(new_val, binop(Iop_Add32,
mkexpr(old),
mkNarrowTo32(ty, getIReg(regRt))));
mips_load_store32(addr, new_val, old, 0, False);
break;
}
/* Store Atomic Add Doubleword - SAAD; Cavium OCTEON */
case 0x19: {
DIP( "saad r%u, (r%u)", regRt, regRs);
IRTemp addr = newTemp(Ity_I64);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I64, mkexpr(addr)));
assign(new_val, binop(Iop_Add64,
mkexpr(old),
getIReg(regRt)));
mips_load_store64(addr, new_val, old, 0, False);
break;
}
/* LAI, LAID, LAD, LADD, LAS, LASD,
LAC, LACD, LAA, LAAD, LAW, LAWD */
case 0x1f: {
UInt opc3 = get_sa(theInstr);
IRTemp addr = newTemp(Ity_I64);
switch (opc3) {
/* Load Atomic Increment Word - LAI; Cavium OCTEON2 */
case 0x02: {
DIP("lai r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I32, mkexpr(addr)));
assign(new_val, binop(Iop_Add32,
mkexpr(old),
mkU32(1)));
mips_load_store32(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Increment Doubleword - LAID; Cavium OCTEON2 */
case 0x03: {
DIP("laid r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I64, mkexpr(addr)));
assign(new_val, binop(Iop_Add64,
mkexpr(old),
mkU64(1)));
mips_load_store64(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Decrement Word - LAD; Cavium OCTEON2 */
case 0x06: {
DIP("lad r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I32, mkexpr(addr)));
assign(new_val, binop(Iop_Sub32,
mkexpr(old),
mkU32(1)));
mips_load_store32(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Decrement Doubleword - LADD; Cavium OCTEON2 */
case 0x07: {
DIP("ladd r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I64, mkexpr(addr)));
assign(new_val, binop(Iop_Sub64,
mkexpr(old),
mkU64(1)));
mips_load_store64(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Set Word - LAS; Cavium OCTEON2 */
case 0x0a: {
DIP("las r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(new_val, mkU32(0xffffffff));
assign(old, load(Ity_I32, mkexpr(addr)));
mips_load_store32(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Set Doubleword - LASD; Cavium OCTEON2 */
case 0x0b: {
DIP("lasd r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(new_val, mkU64(0xffffffffffffffffULL));
assign(old, load(Ity_I64, mkexpr(addr)));
mips_load_store64(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Clear Word - LAC; Cavium OCTEON2 */
case 0x0e: {
DIP("lac r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(new_val, mkU32(0));
assign(old, load(Ity_I32, mkexpr(addr)));
mips_load_store32(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Clear Doubleword - LACD; Cavium OCTEON2 */
case 0x0f: {
DIP("lacd r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(new_val, mkU64(0));
assign(old, load(Ity_I64, mkexpr(addr)));
mips_load_store64(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Add Word - LAA; Cavium OCTEON2 */
case 0x12: {
DIP("laa r%u,(r%u),r%u\n", regRd, regRs, regRt);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I32, mkexpr(addr)));
assign(new_val, binop(Iop_Add32,
mkexpr(old),
mkNarrowTo32(ty, getIReg(regRt))));
mips_load_store32(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Add Doubleword - LAAD; Cavium OCTEON2 */
case 0x13: {
DIP("laad r%u,(r%u),r%u\n", regRd, regRs, regRt);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(old, load(Ity_I64, mkexpr(addr)));
assign(new_val, binop(Iop_Add64,
load(Ity_I64, mkexpr(addr)),
getIReg(regRt)));
mips_load_store64(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Swap Word - LAW; Cavium OCTEON2 */
case 0x16: {
DIP("law r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I32);
IRTemp old = newTemp(Ity_I32);
assign(addr, getIReg(regRs));
assign(new_val, mkNarrowTo32(ty, getIReg(regRt)));
assign(old, load(Ity_I32, mkexpr(addr)));
mips_load_store32(addr, new_val, old, regRd, True);
break;
}
/* Load Atomic Swap Doubleword - LAWD; Cavium OCTEON2 */
case 0x17: {
DIP("lawd r%u,(r%u)\n", regRd, regRs);
IRTemp new_val = newTemp(Ity_I64);
IRTemp old = newTemp(Ity_I64);
assign(addr, getIReg(regRs));
assign(new_val, getIReg(regRt));
assign(old, load(Ity_I64, mkexpr(addr)));
mips_load_store64(addr, new_val, old, regRd, True);
break;
}
default:
vex_printf("Unknown laxx instruction, opc3=0x%x\n", opc3);
vex_printf("Instruction=0x%08x\n", theInstr);
return False;
}
break;
}
/* Unsigned Byte Add - BADDU rd, rs, rt; Cavium OCTEON */
case 0x28: {
DIP("BADDU r%u, r%u, r%u", regRs, regRt, regRd);
IRTemp t0 = newTemp(Ity_I8);
assign(t0, binop(Iop_Add8,
mkNarrowTo8(ty, getIReg(regRs)),
mkNarrowTo8(ty, getIReg(regRt))));
if (mode64)
putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
unop(Iop_8Uto64, mkexpr(t0)),
mkSzImm(ty, 0xFF)));
else
putIReg(regRd, binop(mkSzOp(ty, Iop_And8),
unop(Iop_8Uto32, mkexpr(t0)),
mkSzImm(ty, 0xFF)));
break;
}
case 0x2c: { /* Count Ones in a Word - POP; Cavium OCTEON */
int i, shift[5];
IRTemp mask[5];
IRTemp old = newTemp(ty);
IRTemp nyu = IRTemp_INVALID;
assign(old, getIReg(regRs));
DIP("pop r%u, r%u", regRd, regRs);
for (i = 0; i < 5; i++) {
mask[i] = newTemp(ty);
shift[i] = 1 << i;
}
if (mode64) {
assign(mask[0], mkU64(0x0000000055555555));
assign(mask[1], mkU64(0x0000000033333333));
assign(mask[2], mkU64(0x000000000F0F0F0F));
assign(mask[3], mkU64(0x0000000000FF00FF));
assign(mask[4], mkU64(0x000000000000FFFF));
for (i = 0; i < 5; i++) {
nyu = newTemp(ty);
assign(nyu,
binop(Iop_Add64,
binop(Iop_And64,
mkexpr(old), mkexpr(mask[i])),
binop(Iop_And64,
binop(Iop_Shr64,
mkexpr(old), mkU8(shift[i])),
mkexpr(mask[i]))));
old = nyu;
}
} else {
assign(mask[0], mkU32(0x55555555));
assign(mask[1], mkU32(0x33333333));
assign(mask[2], mkU32(0x0F0F0F0F));
assign(mask[3], mkU32(0x00FF00FF));
assign(mask[4], mkU32(0x0000FFFF));
assign(old, getIReg(regRs));
for (i = 0; i < 5; i++) {
nyu = newTemp(ty);
assign(nyu,
binop(Iop_Add32,
binop(Iop_And32,
mkexpr(old), mkexpr(mask[i])),
binop(Iop_And32,
binop(Iop_Shr32,
mkexpr(old), mkU8(shift[i])),
mkexpr(mask[i]))));
old = nyu;
}
}
putIReg(regRd, mkexpr(nyu));
break;
}
/* Count Ones in a Doubleword - DPOP; Cavium OCTEON */
case 0x2d: {
int i, shift[6];
IRTemp mask[6];
IRTemp old = newTemp(ty);
IRTemp nyu = IRTemp_INVALID;
DIP("dpop r%u, r%u", regRd, regRs);
for (i = 0; i < 6; i++) {
mask[i] = newTemp(ty);
shift[i] = 1 << i;
}
vassert(mode64); /*Caution! Only for Mode 64*/
assign(mask[0], mkU64(0x5555555555555555ULL));
assign(mask[1], mkU64(0x3333333333333333ULL));
assign(mask[2], mkU64(0x0F0F0F0F0F0F0F0FULL));
assign(mask[3], mkU64(0x00FF00FF00FF00FFULL));
assign(mask[4], mkU64(0x0000FFFF0000FFFFULL));
assign(mask[5], mkU64(0x00000000FFFFFFFFULL));
assign(old, getIReg(regRs));
for (i = 0; i < 6; i++) {
nyu = newTemp(Ity_I64);
assign(nyu,
binop(Iop_Add64,
binop(Iop_And64,
mkexpr(old), mkexpr(mask[i])),
binop(Iop_And64,
binop(Iop_Shr64,
mkexpr(old), mkU8(shift[i])),
mkexpr(mask[i]))));
old = nyu;
}
putIReg(regRd, mkexpr(nyu));
break;
}
case 0x32: /* 5. CINS rd, rs, p, lenm1 */
DIP("cins r%u, r%u, %u, %u\n", regRt, regRs, p, lenM1);
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
mkU8(64 - ( lenM1 + 1 ))));
assign ( tmpRt, binop(Iop_Shr64, mkexpr( tmp ),
mkU8(64 - (p + lenM1 + 1))));
putIReg( regRt, mkexpr(tmpRt));
break;
case 0x33: /* 6. CINS32 rd, rs, p+32, lenm1 */
DIP("cins32 r%u, r%u, %d, %d\n", regRt, regRs, p + 32, lenM1);
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
mkU8(64 - ( lenM1 + 1 ))));
assign ( tmpRt, binop(Iop_Shr64, mkexpr( tmp ),
mkU8(32 - (p + lenM1 + 1))));
putIReg( regRt, mkexpr(tmpRt));
break;
case 0x3A: /* 3. EXTS rt, rs, p len */
DIP("exts r%u, r%u, %d, %d\n", regRt, regRs, p, lenM1);
size = lenM1 + 1; /* lenm1+1 */
UChar lsAmt = 64 - (p + size); /* p+lenm1+1 */
UChar rsAmt = 64 - size; /* lenm1+1 */
tmp = newTemp(Ity_I64);
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
putIReg(regRt, binop(Iop_Sar64, mkexpr(tmp), mkU8(rsAmt)));
break;
case 0x3B: /* 4. EXTS32 rt, rs, p len */
DIP("exts32 r%u, r%u, %d, %d\n", regRt, regRs, p, lenM1);
assign ( tmp , binop(Iop_Shl64, mkexpr(tmpRs),
mkU8(32 - (p + lenM1 + 1))));
assign ( tmpRt, binop(Iop_Sar64, mkexpr(tmp),
mkU8(64 - (lenM1 + 1))) );
putIReg( regRt, mkexpr(tmpRt));
break;
case 0x2B: /* 20. SNE rd, rs, rt */
DIP("sne r%u, r%u, r%u", regRd, regRs, regRt);
if (mode64)
putIReg(regRd, unop(Iop_1Uto64, binop(Iop_CmpNE64,
getIReg(regRs),
getIReg(regRt))));
else
putIReg(regRd, unop(Iop_1Uto32, binop(Iop_CmpNE32,
getIReg(regRs),
getIReg(regRt))));
break;
case 0x2A: /* Set Equals - SEQ; Cavium OCTEON */
DIP("seq r%u, r%u, %d", regRd, regRs, regRt);
if (mode64)
putIReg(regRd, unop(Iop_1Uto64,
binop(Iop_CmpEQ64, getIReg(regRs),
getIReg(regRt))));
else
putIReg(regRd, unop(Iop_1Uto32,
binop(Iop_CmpEQ32, getIReg(regRs),
getIReg(regRt))));
break;
case 0x2E: /* Set Equals Immediate - SEQI; Cavium OCTEON */
DIP("seqi r%u, r%u, %u", regRt, regRs, imm);
if (mode64)
putIReg(regRt, unop(Iop_1Uto64,
binop(Iop_CmpEQ64, getIReg(regRs),
mkU64(extend_s_10to64(imm)))));
else
putIReg(regRt, unop(Iop_1Uto32,
binop(Iop_CmpEQ32, getIReg(regRs),
mkU32(extend_s_10to32(imm)))));
break;
case 0x2F: /* Set Not Equals Immediate - SNEI; Cavium OCTEON */
DIP("snei r%u, r%u, %u", regRt, regRs, imm);
if (mode64)
putIReg(regRt, unop(Iop_1Uto64,
binop(Iop_CmpNE64,
getIReg(regRs),
mkU64(extend_s_10to64(imm)))));
else
putIReg(regRt, unop(Iop_1Uto32,
binop(Iop_CmpNE32,
getIReg(regRs),
mkU32(extend_s_10to32(imm)))));
break;
default:
return False;
}
break;
} /* opc1 0x1C ends here*/
case 0x1F: {
switch (opc2) {
case 0x0A: { // lx - Load indexed instructions
switch (get_sa(theInstr)) {
case 0x00: { // LWX rd, index(base)
DIP("lwx r%u, r%u(r%u)", regRd, regRt, regRs);
LOADX_STORE_PATTERN;
putIReg(regRd, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)),
True));
break;
}
case 0x04: // LHX rd, index(base)
DIP("lhx r%u, r%u(r%u)", regRd, regRt, regRs);
LOADX_STORE_PATTERN;
if (mode64)
putIReg(regRd, unop(Iop_16Sto64, load(Ity_I16,
mkexpr(t1))));
else
putIReg(regRd, unop(Iop_16Sto32, load(Ity_I16,
mkexpr(t1))));
break;
case 0x08: { // LDX rd, index(base)
DIP("ldx r%u, r%u(r%u)", regRd, regRt, regRs);
vassert(mode64); /* Currently Implemented only for n64 */
LOADX_STORE_PATTERN;
putIReg(regRd, load(Ity_I64, mkexpr(t1)));
break;
}
case 0x06: { // LBUX rd, index(base)
DIP("lbux r%u, r%u(r%u)", regRd, regRt, regRs);
LOADX_STORE_PATTERN;
if (mode64)
putIReg(regRd, unop(Iop_8Uto64, load(Ity_I8,
mkexpr(t1))));
else
putIReg(regRd, unop(Iop_8Uto32, load(Ity_I8,
mkexpr(t1))));
break;
}
case 0x10: { // LWUX rd, index(base) (Cavium OCTEON)
DIP("lwux r%u, r%u(r%u)", regRd, regRt, regRs);
LOADX_STORE_PATTERN; /* same for both 32 and 64 modes*/
putIReg(regRd, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)),
False));
break;
}
case 0x14: { // LHUX rd, index(base) (Cavium OCTEON)
DIP("lhux r%u, r%u(r%u)", regRd, regRt, regRs);
LOADX_STORE_PATTERN;
if (mode64)
putIReg(regRd,
unop(Iop_16Uto64, load(Ity_I16, mkexpr(t1))));
else
putIReg(regRd,
unop(Iop_16Uto32, load(Ity_I16, mkexpr(t1))));
break;
}
case 0x16: { // LBX rd, index(base) (Cavium OCTEON)
DIP("lbx r%u, r%u(r%u)", regRd, regRs, regRt);
LOADX_STORE_PATTERN;
if (mode64)
putIReg(regRd,
unop(Iop_8Sto64, load(Ity_I8, mkexpr(t1))));
else
putIReg(regRd,
unop(Iop_8Sto32, load(Ity_I8, mkexpr(t1))));
break;
}
default:
vex_printf("\nUnhandled LX instruction opc3 = %x\n",
get_sa(theInstr));
return False;
}
break;
}
} /* opc1 = 0x1F & opc2 = 0xA (LX) ends here*/
break;
} /* opc1 = 0x1F ends here*/
default:
return False;
} /* main opc1 switch ends here */
return True;
}
static Int msa_I8_logical(UInt cins, UChar wd, UChar ws)
{
IRTemp t1, t2;
UShort operation;
UChar i8;
operation = (cins >> 24) & 3;
i8 = (cins & 0x00FF0000) >> 16;
switch (operation) {
case 0x00: { /* ANDI.B */
DIP("ANDI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
putWReg(wd, binop(Iop_AndV128, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x01: { /* ORI.B */
DIP("ORI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
putWReg(wd, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x02: { /* NORI.B */
DIP("NORI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
putWReg(wd, unop(Iop_NotV128, binop(Iop_OrV128,
mkexpr(t1), mkexpr(t2))));
break;
}
case 0x03: { /* XORI.B */
DIP("XORI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
putWReg(wd, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
break;
}
default:
return -1;
}
return 0;
}
static Int msa_I8_branch(UInt cins, UChar wd, UChar ws)
{
IRTemp t1, t2, t3, t4;
UShort operation;
UChar i8;
operation = (cins >> 24) & 3;
i8 = (cins & 0x00FF0000) >> 16;
switch (operation) {
case 0x00: { /* BMNZI.B */
DIP("BMNZI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t4, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t1, binop(Iop_AndV128, getWReg(ws), mkexpr(t4)));
assign(t2, binop(Iop_AndV128, getWReg(wd),
unop(Iop_NotV128, mkexpr(t4))));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* BMZI.B */
DIP("BMZI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t4, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t1, binop(Iop_AndV128, getWReg(wd), mkexpr(t4)));
assign(t2, binop(Iop_AndV128, getWReg(ws),
unop(Iop_NotV128, mkexpr(t4))));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* BSELI.B */
DIP("BSELI.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
ULong tmp = i8;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t4, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t1, binop(Iop_AndV128, getWReg(wd), mkexpr(t4)));
assign(t2, binop(Iop_AndV128, getWReg(ws),
unop(Iop_NotV128, getWReg(wd))));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
return 0;
}
static Int msa_I8_shift(UInt cins, UChar wd, UChar ws)
{
IRTemp t1, t2;
UShort operation;
UChar i8;
operation = (cins >> 24) & 3;
i8 = (cins & 0x00FF0000) >> 16;
switch (operation) {
case 0x00: { /* SHF.B */
DIP("SHF.B w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[16];
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I8);
assign(tmp[i],
binop(Iop_GetElem8x16, mkexpr(t2),
mkU8(i - (i % 4) +
((i8 >> (i % 4) * 2) & 0x03))));
}
putWReg(wd, binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[15]),
mkexpr(tmp[14])),
binop(Iop_8HLto16,
mkexpr(tmp[13]),
mkexpr(tmp[12]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[11]),
mkexpr(tmp[10])),
binop(Iop_8HLto16,
mkexpr(tmp[9]),
mkexpr(tmp[8])))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_8HLto16,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_8HLto16,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x01: { /* SHF.H */
DIP("SHF.H w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[8];
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_GetElem16x8, mkexpr(t2),
mkU8(i - (i % 4) +
((i8 >> (i % 4) * 2) & 0x03))));
}
putWReg(wd, binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]), mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]), mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]), mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]), mkexpr(tmp[0])))));
break;
}
case 0x02: { /* SHF.W */
DIP("SHF.W w%d, w%d, %d", wd, ws, i8);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[4];
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_GetElem32x4, mkexpr(t2),
mkU8(i - (i % 4) +
((i8 >> (i % 4) * 2) & 0x03))));
}
putWReg(wd, binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]), mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]), mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
return 0;
}
static Int msa_I5_06(UInt cins, UChar wd, UChar ws) /* I5 (0x06) */
{
IRTemp t1, t2, t3;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* ADDVI */
ULong tmp = wt;
switch (df) {
case 0x00: { /* ADDVI.B */
DIP("ADDVI.B w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Add8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ADDVI.H */
DIP("ADDVI.H w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Add16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ADDVI.W */
DIP("ADDVI.W w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Add32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ADDVI.D */
DIP("ADDVI.D w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Add64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x01: { /* SUBVI */
ULong tmp = wt;
switch (df) {
case 0x00: { /* SUBVI.B */
DIP("SUBVI.B w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Sub8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SUBVI.H */
DIP("SUBVI.H w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Sub16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SUBVI.W */
DIP("SUBVI.W w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Sub32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SUBVI.D */
DIP("SUBVI.D w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Sub64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x02: { /* MAXI_S */
ULong tmp = wt;
switch (df) {
case 0x00: { /* MAXI_S.B */
DIP("MAXI_S.B w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
char stemp = ((int)tmp << 27) >> 27;
tmp = (UChar)stemp;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MAXI_S.H */
DIP("MAXI_S.H w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
short stemp = ((int)tmp << 27) >> 27;
tmp = (UShort)stemp;
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MAXI_S.W */
DIP("MAXI_S.W w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
int stemp = ((int)tmp << 27) >> 27;
tmp = (UInt)stemp;
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MAXI_S.D */
DIP("MAXI_S.D w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
Long stemp = ((Long)tmp << 59) >> 59;
tmp = stemp;
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max64Sx2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x03: { /* MAXI_U */
ULong tmp = wt;
switch (df) {
case 0x00: { /* MAXI_U.B */
DIP("MAXI_U.B w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MAXI_U.H */
DIP("MAXI_U.H w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MAXI_U.W */
DIP("MAXI_U.W w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MAXI_U.D */
DIP("MAXI_U.D w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Max64Ux2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x04: { /* MINI_S */
ULong tmp = wt;
switch (df) {
case 0x00: { /* MINI_S.B */
DIP("MINI_S.B w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
char stemp = ((int)tmp << 27) >> 27;
tmp = (UChar)stemp;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MINI_S.H */
DIP("MINI_S.H w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
short stemp = ((int)tmp << 27) >> 27;
tmp = (UShort)stemp;
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MINI_S.W */
DIP("MINI_S.W w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
int stemp = ((int)tmp << 27) >> 27;
tmp = (UInt)stemp;
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MINI_S.D */
DIP("MINI_S.D w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
Long stemp = ((Long)tmp << 59) >> 59;
tmp = stemp;
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min64Sx2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x05: { /* MINI_U */
ULong tmp = wt;
switch (df) {
case 0x00: { /* MINI_U.B */
DIP("MINI_U.B w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MINI_U.H */
DIP("MINI_U.H w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MINI_U.W */
DIP("MINI_U.W w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MINI_U.D */
DIP("MINI_U.D w%d, w%d, %d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_Min64Ux2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
default: {
return -1;
}
}
return 0;
}
static Int msa_I5_07(UInt cins, UChar wd, UChar ws) /* I5 (0x07) / I10 */
{
IRTemp t1, t2, t3;
UShort operation;
UChar df, i5;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
i5 = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: {
ULong tmp = i5;
switch (df) {
case 0x00: { /* CEQI.B */
DIP("CEQI.B w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
char stemp = ((int)tmp << 27) >> 27;
tmp = (UChar)stemp;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CEQI.H */
DIP("CEQI.H w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
short stemp = ((int)tmp << 27) >> 27;
tmp = (UShort)stemp;
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CEQI.W */
DIP("CEQI.W w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
int stemp = ((int)tmp << 27) >> 27;
tmp = (UInt)stemp;
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CEQI.D */
DIP("CEQI.D w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
Long stemp = ((Long)tmp << 59) >> 59;
tmp = stemp;
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x02: { /* CLTI_S.df */
ULong tmp = i5;
switch (df) {
case 0x00: { /* CLTI_S.B */
DIP("CLTI_S.B w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
char stemp = ((int)tmp << 27) >> 27;
tmp = (UChar)stemp;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT8Sx16, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLTI_S.H */
DIP("CLTI_S.H w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
short stemp = ((int)tmp << 27) >> 27;
tmp = (UShort)stemp;
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT16Sx8, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLTI_S.W */
DIP("CLTI_S.W w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
int stemp = ((int)tmp << 27) >> 27;
tmp = (UInt)stemp;
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT32Sx4, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLTI_S.D */
DIP("CLTI_S.D w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
Long stemp = ((Long)tmp << 59) >> 59;
tmp = stemp;
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT64Sx2, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* CLTI_U.df */
ULong tmp = i5;
switch (df) {
case 0x00: { /* CLTI_U.B */
DIP("CLTI_U.B w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT8Ux16, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLTI_U.H */
DIP("CLTI_U.H w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT16Ux8, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLTI_U.W */
DIP("CLTI_U.W w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT32Ux4, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLTI_U.D */
DIP("CLTI_U.D w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_CmpGT64Ux2, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x04: { /* CLEI_S.df */
ULong tmp = i5;
switch (df) {
case 0x00: { /* CLEI_S.B */
DIP("CLEI_S.B w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
char stemp = ((int)tmp << 27) >> 27;
tmp = (UChar)stemp;
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128, binop(Iop_CmpGT8Sx16,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ8x16,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLEI_S.H */
DIP("CLEI_S.H w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
short stemp = ((int)tmp << 27) >> 27;
tmp = (UShort)stemp;
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128, binop(Iop_CmpGT16Sx8,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ16x8,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLEI_S.W */
DIP("CLEI_S.W w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
int stemp = ((int)tmp << 27) >> 27;
tmp = (UInt)stemp;
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT32Sx4,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ32x4,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLEI_S.D */
DIP("CLEI_S.D w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
Long stemp = ((Long)tmp << 59) >> 59;
tmp = stemp;
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT64Sx2,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ64x2,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* CLEI_U.df */
ULong tmp = i5;
switch (df) {
case 0x00: { /* CLEI_U.B */
DIP("CLEI_U.B w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT8Ux16,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ8x16,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLEI_U.H */
DIP("CLEI_U.H w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT16Ux8,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ16x8,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLEI_U.W */
DIP("CLEI_U.W w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
tmp |= (tmp << 32);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT32Ux4,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ32x4,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLEI_U.D */
DIP("CLEI_U.D w%d, w%d, %d", wd, ws, i5);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT64Ux2,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ64x2,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x06: { /* LDI.df */
ULong tmp;
UShort s10;
s10 = (cins & 0x001FF800) >> 11;
switch (df) {
case 0x00: /* LDI.B */
DIP("LDI.B w%d, %d", wd, s10);
tmp = s10 & 0xFFl;
tmp = tmp | (tmp << 8) | (tmp << 16) | (tmp << 24)
| (tmp << 32) | (tmp << 40) | (tmp << 48) |
(tmp << 56);
break;
case 0x01: /* LDI.H */
DIP("LDI.H w%d, %d", wd, s10);
tmp = extend_s_10to16(s10);
tmp = tmp | (tmp << 16) | (tmp << 32) | (tmp << 48);
break;
case 0x02: /* LDI.W */
DIP("LDI.W w%d, %d", wd, s10);
tmp = extend_s_10to32(s10);
tmp = tmp | (tmp << 32);
break;
case 0x03: /* LDI.D */
DIP("LDI.D w%d, %d", wd, s10);
tmp = extend_s_10to64(s10);
break;
default:
return -1;
}
putWReg(wd, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp)));
break;
}
default:
return -1;
}
return 0;
}
static Int msa_BIT_09(UInt cins, UChar wd, UChar ws) /* BIT (0x09) */
{
IRTemp t1, t2, t3;
UShort operation;
UChar df, m;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x007F0000) >> 16;
if ((df & 0x70) == 0x70) { // 111mmmm; b
m = df & 0x07;
df = 0;
} else if ((df & 0x60) == 0x60) { // 110mmmm; h
m = df & 0x0F;
df = 1;
} else if ((df & 0x40) == 0x40) { // 10mmmmm; w
m = df & 0x1F;
df = 2;
} else if ((df & 0x00) == 0x00) { // 0mmmmmm; d
m = df & 0x3F;
df = 3;
}
switch (operation) {
case 0x00: { /* SLLI.df */
switch (df) {
case 0x00: { /* SLLI.B */
DIP("SLLI.B w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShlN8x16, getWReg(ws), mkU8(m)));
break;
}
case 0x01: { /* SLLI.H */
DIP("SLLI.H w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShlN16x8, getWReg(ws), mkU8(m)));
break;
}
case 0x02: { /* SLLI.W */
DIP("SLLI.W w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShlN32x4, getWReg(ws), mkU8(m)));
break;
}
case 0x03: { /* SLLI.D */
DIP("SLLI.D w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShlN64x2, getWReg(ws), mkU8(m)));
break;
}
}
break;
}
case 0x01: { /* SRAI.df */
switch (df) {
case 0x00: { /* SRAI.B */
DIP("SRAI.B w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_SarN8x16, getWReg(ws), mkU8(m)));
break;
}
case 0x01: { /* SRAI.H */
DIP("SRAI.H w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_SarN16x8, getWReg(ws), mkU8(m)));
break;
}
case 0x02: { /* SRAI.W */
DIP("SRAI.W w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_SarN32x4, getWReg(ws), mkU8(m)));
break;
}
case 0x03: { /* SRAI.D */
DIP("SRAI.D w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_SarN64x2, getWReg(ws), mkU8(m)));
break;
}
}
break;
}
case 0x02: { /* SRLI.df */
switch (df) {
case 0x00: { /* SRLI.B */
DIP("SRLI.B w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShrN8x16, getWReg(ws), mkU8(m)));
break;
}
case 0x01: { /* SRLI.H */
DIP("SRLI.H w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShrN16x8, getWReg(ws), mkU8(m)));
break;
}
case 0x02: { /* SRLI.W */
DIP("SRLI.W w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShrN32x4, getWReg(ws), mkU8(m)));
break;
}
case 0x03: { /* SRLI.D */
DIP("SRLI.D w%d, w%d, %d", wd, ws, m);
putWReg(wd, binop(Iop_ShrN64x2, getWReg(ws), mkU8(m)));
break;
}
}
break;
}
case 0x03: { /* BCLRI.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 1;
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* BCLRI.B */
DIP("BCLRI.B w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t2, binop(Iop_ShlN8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x01: { /* BCLRI.H */
DIP("BCLRI.H w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t2, binop(Iop_ShlN16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x02: { /* BCLRI.W */
DIP("BCLRI.W w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 32);
assign(t2, binop(Iop_ShlN32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x03: { /* BCLRI.D */
DIP("BCLRI.D w%d, w%d, %d", wd, ws, m);
assign(t2, binop(Iop_ShlN64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
}
assign(t3, binop(Iop_AndV128,
mkexpr(t1), unop(Iop_NotV128, mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x04: { /* BSETI */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 1;
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* BSETI.B */
DIP("BSETI.B w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t2, binop(Iop_ShlN8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x01: { /* BSETI.H */
DIP("BSETI.H w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t2, binop(Iop_ShlN16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x02: { /* BSETI.W */
DIP("BSETI.W w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 32);
assign(t2, binop(Iop_ShlN32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x03: { /* BSETI.D */
DIP("BSETI.D w%d, w%d, %d", wd, ws, m);
assign(t2, binop(Iop_ShlN64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
}
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x05: { /* BNEGI.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 1;
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* BNEGI.B */
DIP("BNEGI.B w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t2, binop(Iop_ShlN8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x01: { /* BNEGI.H */
DIP("BNEGI.H w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t2, binop(Iop_ShlN16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x02: { /* BNEGI.W */
DIP("BNEGI.W w%d, w%d, %d", wd, ws, m);
tmp |= (tmp << 32);
assign(t2, binop(Iop_ShlN32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
case 0x03: { /* BNEGI.D */
DIP("BNEGI.D w%d, w%d, %d", wd, ws, m);
assign(t2, binop(Iop_ShlN64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
break;
}
}
assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x06: { /* BINSLI.df */
switch (df) {
case 0x00: { /* BINSLI.B */
DIP("BINSLI.B w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8080808080808080ULL;
assign(t1, binop(Iop_SarN8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x01: { /* BINSLI.H */
DIP("BINSLI.H w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8000800080008000ULL;
assign(t1,
binop(Iop_SarN16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x02: { /* BINSLI.W */
DIP("BINSLI.W w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8000000080000000ULL;
assign(t1,
binop(Iop_SarN32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x03: { /* BINSLI.D */
DIP("BINSLI.D w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8000000000000000ULL;
assign(t1,
binop(Iop_SarN64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)), getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
default:
return -1;
}
break;
}
case 0x07: {
switch (df) {
case 0x00: { /* BINSRI.B */
DIP("BINSRI.B w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0xFEFEFEFEFEFEFEFEULL;
assign(t1,
binop(Iop_ShlN8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)), mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)), getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x01: { /* BINSRI.H */
DIP("BINSRI.H w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0xFFFEFFFEFFFEFFFEULL;
assign(t1,
binop(Iop_ShlN16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x02: { /* BINSRI.W */
DIP("BINSRI.W w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0xFFFFFFFEFFFFFFFEULL;
assign(t1,
binop(Iop_ShlN32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x03: { /* BINSRI.D */
DIP("BINSRI.D w%d, w%d, w%d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = -2;
assign(t1,
binop(Iop_ShlN64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
mkU8(m)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_BIT_0A(UInt cins, UChar wd, UChar ws) /* BIT (0x0A) */
{
IRTemp t1, t2;
UShort operation;
UChar df, m;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x007F0000) >> 16;
if ((df & 0x70) == 0x70) { // 111mmmm; b
m = df & 0x07;
df = 0;
} else if ((df & 0x60) == 0x60) { // 110mmmm; h
m = df & 0x0F;
df = 1;
} else if ((df & 0x40) == 0x40) { // 10mmmmm; w
m = df & 0x1F;
df = 2;
} else if ((df & 0x00) == 0x00) { // 0mmmmmm; d
m = df & 0x3F;
df = 3;
}
switch (operation) {
case 0x00: { /* SAT_S.df */
switch (df) {
case 0x00: { /* SAT_S.B */
DIP("SAT_S.B w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN8x16, getWReg(ws), mkU8(7)));
if (m == 0) {
putWReg(wd, mkexpr(t1));
} else {
t2 = newTemp(Ity_V128);
assign(t2,
binop(Iop_SarN8x16, getWReg(ws), mkU8(m)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ8x16,
mkexpr(t1),
mkexpr(t2)),
getWReg(ws)),
binop(Iop_ShlN8x16,
binop(Iop_CmpGT8Sx16,
mkexpr(t1),
mkexpr(t2)),
mkU8(m))),
binop(Iop_ShrN8x16,
binop(Iop_CmpGT8Sx16,
mkexpr(t2),
mkexpr(t1)),
mkU8(8 - m))));
}
break;
}
case 0x01: { /* SAT_S.H */
DIP("SAT_S.H w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN16x8, getWReg(ws), mkU8(15)));
if (m == 0) {
putWReg(wd, mkexpr(t1));
} else {
t2 = newTemp(Ity_V128);
assign(t2,
binop(Iop_SarN16x8,
getWReg(ws),
mkU8(m)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ16x8,
mkexpr(t1),
mkexpr(t2)),
getWReg(ws)),
binop(Iop_ShlN16x8,
binop(Iop_CmpGT16Sx8,
mkexpr(t1),
mkexpr(t2)),
mkU8(m))),
binop(Iop_ShrN16x8,
binop(Iop_CmpGT16Sx8,
mkexpr(t2),
mkexpr(t1)),
mkU8(16 - m))));
}
break;
}
case 0x02: { /* SAT_S.W */
DIP("SAT_S.W w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN32x4, getWReg(ws), mkU8(31)));
if (m == 0) {
putWReg(wd, mkexpr(t1));
} else {
t2 = newTemp(Ity_V128);
assign(t2,
binop(Iop_SarN32x4,
getWReg(ws),
mkU8(m)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ32x4,
mkexpr(t1),
mkexpr(t2)),
getWReg(ws)),
binop(Iop_ShlN32x4,
binop(Iop_CmpGT32Sx4,
mkexpr(t1),
mkexpr(t2)),
mkU8(m))),
binop(Iop_ShrN32x4,
binop(Iop_CmpGT32Sx4,
mkexpr(t2),
mkexpr(t1)),
mkU8(32 - m))));
}
break;
}
case 0x03: { /* SAT_S.D */
DIP("SAT_S.D w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN64x2, getWReg(ws), mkU8(63)));
if (m == 0) {
putWReg(wd, mkexpr(t1));
} else {
t2 = newTemp(Ity_V128);
assign(t2,
binop(Iop_SarN64x2,
getWReg(ws),
mkU8(m)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ64x2,
mkexpr(t1),
mkexpr(t2)),
getWReg(ws)),
binop(Iop_ShlN64x2,
binop(Iop_CmpGT64Sx2,
mkexpr(t1),
mkexpr(t2)),
mkU8(m))),
binop(Iop_ShrN64x2,
binop(Iop_CmpGT64Sx2,
mkexpr(t2),
mkexpr(t1)),
mkU8(64 - m))));
}
break;
}
}
break;
}
case 0x01: { /* SAT_U.df */
switch (df) {
case 0x00: { /* SAT_U.B */
DIP("SAT_U.B w%d, w%d, %d", wd, ws, m);
if (m == 7) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
assign(t1,
binop(Iop_CmpEQ8x16,
binop(Iop_ShrN8x16,
getWReg(ws),
mkU8(m + 1)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
binop(Iop_ShrN8x16,
unop(Iop_NotV128,
mkexpr(t1)),
mkU8(7 - m))));
}
break;
}
case 0x01: { /* SAT_U.H */
DIP("SAT_U.H w%d, w%d, %d", wd, ws, m);
if (m == 15) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
assign(t1,
binop(Iop_CmpEQ16x8,
binop(Iop_ShrN16x8,
getWReg(ws),
mkU8(m + 1)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
binop(Iop_ShrN16x8,
unop(Iop_NotV128,
mkexpr(t1)),
mkU8(15 - m))));
}
break;
}
case 0x02: { /* SAT_U.W */
DIP("SAT_U.W w%d, w%d, %d", wd, ws, m);
if (m == 31) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
assign(t1,
binop(Iop_CmpEQ32x4,
binop(Iop_ShrN32x4,
getWReg(ws),
mkU8(m + 1)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1), \
getWReg(ws)),
binop(Iop_ShrN32x4,
unop(Iop_NotV128,
mkexpr(t1)),
mkU8(31 - m))));
}
break;
}
case 0x03: { /* SAT_U.D */
DIP("SAT_U.D w%d, w%d, %d", wd, ws, m);
if (m == 63) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
assign(t1,
binop(Iop_CmpEQ64x2,
binop(Iop_ShrN64x2,
getWReg(ws),
mkU8(m + 1)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
binop(Iop_ShrN64x2,
unop(Iop_NotV128,
mkexpr(t1)),
mkU8(63 - m))));
}
break;
}
}
break;
}
case 0x02: { /* SRARI.df */
switch (df) {
case 0x00: { /* SRARI.B */
DIP("SRARI.B w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_SarN8x16,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN8x16,
binop(Iop_ShlN8x16,
getWReg(ws),
mkU8(8 - m)),
mkU8(7)));
if (m) putWReg(wd, binop(Iop_Add8x16,
mkexpr(t1),
mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
case 0x01: { /* SRARI.H */
DIP("SRARI.H w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_SarN16x8,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN16x8,
binop(Iop_ShlN16x8,
getWReg(ws),
mkU8(16 - m)),
mkU8(15)));
if (m)
putWReg(wd,
binop(Iop_Add16x8,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
case 0x02: { /* SRARI.W */
DIP("SRARI.W w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_SarN32x4,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN32x4,
binop(Iop_ShlN32x4,
getWReg(ws),
mkU8(32 - m)),
mkU8(31)));
if (m)
putWReg(wd,
binop(Iop_Add32x4,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
case 0x03: { /* SRARI.D */
DIP("SRARI.D w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_SarN64x2,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
getWReg(ws),
mkU8(64 - m)),
mkU8(63)));
if (m)
putWReg(wd,
binop(Iop_Add64x2,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
}
break;
}
case 0x03: { /* SRLRI.df */
switch (df) {
case 0x00: { /* SRLRI.B */
DIP("SRLRI.B w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN8x16,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN8x16,
binop(Iop_ShlN8x16,
getWReg(ws),
mkU8(8 - m)),
mkU8(7)));
if (m)
putWReg(wd,
binop(Iop_Add8x16,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
case 0x01: { /* SRLRI.H */
DIP("SRLRI.H w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN16x8,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN16x8,
binop(Iop_ShlN16x8,
getWReg(ws),
mkU8(16 - m)),
mkU8(15)));
if (m)
putWReg(wd,
binop(Iop_Add16x8,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
case 0x02: { /* SRLRI.W */
DIP("SRLRI.W w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN32x4,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN32x4,
binop(Iop_ShlN32x4,
getWReg(ws),
mkU8(32 - m)),
mkU8(31)));
if (m)
putWReg(wd,
binop(Iop_Add32x4,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
case 0x03: { /* SRLRI.D */
DIP("SRLRI.D w%d, w%d, %d", wd, ws, m);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN64x2,
getWReg(ws),
mkU8(m)));
assign(t2,
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
getWReg(ws),
mkU8(64 - m)),
mkU8(63)));
if (m)
putWReg(wd,
binop(Iop_Add64x2,
mkexpr(t1), mkexpr(t2)));
else putWReg(wd, mkexpr(t1));
break;
}
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_0D(UInt cins, UChar wd, UChar ws) /* 3R (0x0D) */
{
IRTemp t1, t2, t3;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* SLL.df */
switch (df) {
case 0x00: { /* SLL.B */
DIP("SLL.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shl8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SLL.H */
DIP("SLL.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shl16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SLL.W */
DIP("SLL.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shl32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SLL.D */
DIP("SLL.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shl64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* SRA.df */
switch (df) {
case 0x00: { /* SRA.B */
DIP("SRA.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sar8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SRA.H */
DIP("SRA.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sar16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SRA.W */
DIP("SRA.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sar32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SRA.D */
DIP("SRA.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sar64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* SRL.df */
switch (df) {
case 0x00: { /* SRL.B */
DIP("SRL.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shr8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SRL.H */
DIP("SRL.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shr16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SRL.W */
DIP("SRL.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shr32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SRL.D */
DIP("SRL.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Shr64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* BCLR.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 1;
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* BCLR.B */
DIP("BCLR.B w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t2, binop(Iop_Shl8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x01: { /* BCLR.H */
DIP("BCLR.H w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t2,
binop(Iop_Shl16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x02: { /* BCLR.W */
DIP("BCLR.W w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 32);
assign(t2,
binop(Iop_Shl32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x03: { /* BCLR.D */
DIP("BCLR.D w%d, w%d, w%d", wd, ws, wt);
assign(t2,
binop(Iop_Shl64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
}
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), unop(Iop_NotV128, mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x04: { /* BSET.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 1;
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* BSET.B */
DIP("BSET.B w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t2,
binop(Iop_Shl8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x01: { /* BSET.H */
DIP("BSET.H w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t2,
binop(Iop_Shl16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x02: { /* BSET.W */
DIP("BSET.W w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 32);
assign(t2,
binop(Iop_Shl32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x03: { /* BSET.D */
DIP("BSET.D w%d, w%d, w%d", wd, ws, wt);
assign(t2,
binop(Iop_Shl64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
}
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x05: { /* BNEG.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 1;
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* BNEG.B */
DIP("BNEG.B w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 56) | (tmp << 48) | (tmp << 40) |
(tmp << 32) | (tmp << 24) | (tmp << 16) |
(tmp << 8);
assign(t2,
binop(Iop_Shl8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x01: { /* BNEG.H */
DIP("BNEG.H w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 48) | (tmp << 32) | (tmp << 16);
assign(t2,
binop(Iop_Shl16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x02: { /* BNEG.W */
DIP("BNEG.W w%d, w%d, w%d", wd, ws, wt);
tmp |= (tmp << 32);
assign(t2,
binop(Iop_Shl32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
case 0x03: { /* BNEG.D */
DIP("BNEG.D w%d, w%d, w%d", wd, ws, wt);
assign(t2,
binop(Iop_Shl64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
break;
}
}
assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x06: { /* BINSL.df */
switch (df) {
case 0x00: { /* BINSL.B */
DIP("BINSL.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8080808080808080ULL;
assign(t1,
binop(Iop_Sar8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x01: { /* BINSL.H */
DIP("BINSL.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8000800080008000ULL;
assign(t1,
binop(Iop_Sar16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x02: { /* BINSL.W */
DIP("BINSL.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8000000080000000ULL;
assign(t1,
binop(Iop_Sar32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x03: { /* BINSL.D */
DIP("BINSL.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0x8000000000000000ULL;
assign(t1,
binop(Iop_Sar64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(wd)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(ws)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* BINSR.df */
switch (df) {
case 0x00: { /* BINSR.B */
DIP("BINSR.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0xFEFEFEFEFEFEFEFEULL;
assign(t1,
binop(Iop_Shl8x16,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x01: { /* BINSR.H */
DIP("BINSR.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0xFFFEFFFEFFFEFFFEULL;
assign(t1,
binop(Iop_Shl16x8,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x02: { /* BINSR.W */
DIP("BINSR.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = 0xFFFFFFFEFFFFFFFEULL;
assign(t1,
binop(Iop_Shl32x4,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x03: { /* BINSR.D */
DIP("BINSR.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
ULong tmp = -2;
assign(t1,
binop(Iop_Shl64x2,
binop(Iop_64HLtoV128,
mkU64(tmp), mkU64(tmp)),
getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t1)),
getWReg(ws)));
assign(t3,
binop(Iop_AndV128,
mkexpr(t1), getWReg(wd)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_0E(UInt cins, UChar wd, UChar ws) /* 3R (0x0E) */
{
IRTemp t1, t2, t3, t4;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* ADDV.df */
switch (df) {
case 0x00: { /* ADDV.B */
DIP("ADDV.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ADDV.H */
DIP("ADDV.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ADDV.W */
DIP("ADDV.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ADDV.D */
DIP("ADDV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* SUBV.df */
switch (df) {
case 0x00: { /* SUBV.B */
DIP("SUBV.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sub8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SUBV.H */
DIP("SUBV.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sub16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SUBV.W */
DIP("SUBV.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sub32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SUBV.D */
DIP("SUBV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Sub64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* MAX_S.df */
switch (df) {
case 0x00: { /* MAX_S.B */
DIP("MAX_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MAX_S.H */
DIP("MAX_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MAX_S.W */
DIP("MAX_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MAX_S.D */
DIP("MAX_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max64Sx2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* MAX_U.df */
switch (df) {
case 0x00: { /* MAX_U.B */
DIP("MAX_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MAX_U.H */
DIP("MAX_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MAX_U.W */
DIP("MAX_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MAX_U.D */
DIP("MAX_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Max64Ux2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* MIN_S.df */
switch (df) {
case 0x00: { /* MIN_S.B */
DIP("MIN_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MIN_S.H */
DIP("MIN_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MIN_S.W */
DIP("MIN_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MIN_S.D */
DIP("MIN_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min64Sx2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* MIN_U.df */
switch (df) {
case 0x00: { /* MIN_U.B */
DIP("MIN_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MIN_U.H */
DIP("MIN_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MIN_U.W */
DIP("MIN_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MIN_U.D */
DIP("MIN_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Min64Ux2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x06: { /* MAX_A.df */
switch (df) {
case 0x00: { /* MAX_A.B */
DIP("MAX_A.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
assign(t4, binop(Iop_CmpGT8Ux16, mkexpr(t1), mkexpr(t2)));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(ws)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(wt))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MAX_A.H */
DIP("MAX_A.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
assign(t4, binop(Iop_CmpGT16Ux8, mkexpr(t1), mkexpr(t2)));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(ws)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(wt))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MAX_A.W */
DIP("MAX_A.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
assign(t4, binop(Iop_CmpGT32Ux4, mkexpr(t1), mkexpr(t2)));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(ws)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(wt))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MAX_A.D */
DIP("MAX_A.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
assign(t4, binop(Iop_CmpGT64Ux2, mkexpr(t1), mkexpr(t2)));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(ws)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(wt))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* MIN_A.df */
switch (df) {
case 0x00: { /* MIN_A.B */
DIP("MIN_A.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
assign(t4, binop(Iop_OrV128,
binop(Iop_CmpGT8Ux16,
mkexpr(t1), mkexpr(t2)),
binop(Iop_CmpEQ8x16,
mkexpr(t1), mkexpr(t2))));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(wt)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(ws))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MIN_A.H */
DIP("MIN_A.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
assign(t4, binop(Iop_OrV128,
binop(Iop_CmpGT16Ux8,
mkexpr(t1), mkexpr(t2)),
binop(Iop_CmpEQ16x8,
mkexpr(t1), mkexpr(t2))));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(wt)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(ws))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* MIN_A.W */
DIP("MIN_A.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
assign(t4, binop(Iop_OrV128,
binop(Iop_CmpGT32Ux4,
mkexpr(t1), mkexpr(t2)),
binop(Iop_CmpEQ32x4,
mkexpr(t1), mkexpr(t2))));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(wt)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(ws))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* MIN_A.D */
DIP("MIN_A.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
assign(t4, binop(Iop_OrV128,
binop(Iop_CmpGT64Ux2,
mkexpr(t1), mkexpr(t2)),
binop(Iop_CmpEQ64x2,
mkexpr(t1), mkexpr(t2))));
assign(t3, binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
getWReg(wt)),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
getWReg(ws))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_0F(UInt cins, UChar wd, UChar ws) /* 3R (0x0F) */
{
IRTemp t1, t2, t3;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* CEQ.df */
switch (df) {
case 0x00: { /* CEQ.B */
DIP("CEQ.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CEQ.H */
DIP("CEQ.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CEQ.W */
DIP("CEQ.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CEQ.D */
DIP("CEQ.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* CLT_S.df */
switch (df) {
case 0x00: { /* CLT_S.B */
DIP("CLT_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT8Sx16, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLT_S.H */
DIP("CLT_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT16Sx8, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLT_S.W */
DIP("CLT_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT32Sx4, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLT_S.D */
DIP("CLT_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT64Sx2, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* CLT_U.df */
switch (df) {
case 0x00: { /* CLT_U.B */
DIP("CLT_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT8Ux16, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLT_U.H */
DIP("CLT_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT16Ux8, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLT_U.W */
DIP("CLT_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT32Ux4, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLT_U.D */
DIP("CLT_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_CmpGT64Ux2, mkexpr(t2), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* CLE_S.df */
switch (df) {
case 0x00: { /* CLE_S.B */
DIP("CLE_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT8Sx16,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ8x16,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLE_S.H */
DIP("CLE_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT16Sx8,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ16x8,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLE_S.W */
DIP("CLE_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT32Sx4,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ32x4,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLE_S.D */
DIP("CLE_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT64Sx2,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ64x2,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* CLE_U.df */
switch (df) {
case 0x00: { /* CLE_U.B */
DIP("CLE_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT8Ux16,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ8x16,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* CLE_U.H */
DIP("CLE_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT16Ux8,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ16x8,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* CLE_U.W */
DIP("CLE_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT32Ux4,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ32x4,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* CLE_U.D */
DIP("CLE_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_OrV128,
binop(Iop_CmpGT64Ux2,
mkexpr(t2), mkexpr(t1)),
binop(Iop_CmpEQ64x2,
mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_10(UInt cins, UChar wd, UChar ws) /* 3R (0x10) */
{
IRTemp t1, t2, t3, t4;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* ADD_A.df */
switch (df) {
case 0x00: { /* ADD_A.B */
DIP("ADD_A.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
assign(t3, binop(Iop_Add8x16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ADD_A.H */
DIP("ADD_A.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
assign(t3, binop(Iop_Add16x8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ADD_A.W */
DIP("ADD_A.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
assign(t3, binop(Iop_Add32x4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ADD_A.D */
DIP("ADD_A.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
assign(t3, binop(Iop_Add64x2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* ADDS_A.df */
switch (df) {
case 0x00: { /* ADDS_A.B */
DIP("ADDS_A.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs8x16, getWReg(ws)));
assign(t2, unop(Iop_Abs8x16, getWReg(wt)));
assign(t3, binop(Iop_SarN8x16,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
mkU8(7)));
assign(t4, binop(Iop_SarN8x16,
binop(Iop_AndV128,
mkexpr(t2),
getWReg(wt)),
mkU8(7)));
putWReg(wd, binop(Iop_QAdd8Sx16,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t3)),
mkexpr(t1)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t4)),
mkexpr(t2)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t2)),
mkexpr(t4)))));
break;
}
case 0x01: { /* ADDS_A.H */
DIP("ADDS_A.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs16x8, getWReg(ws)));
assign(t2, unop(Iop_Abs16x8, getWReg(wt)));
assign(t3, binop(Iop_SarN16x8,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
mkU8(15)));
assign(t4, binop(Iop_SarN16x8,
binop(Iop_AndV128,
mkexpr(t2),
getWReg(wt)),
mkU8(15)));
putWReg(wd, binop(Iop_QAdd16Sx8,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t3)),
mkexpr(t1)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t4)),
mkexpr(t2)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t2)),
mkexpr(t4)))));
break;
}
case 0x02: { /* ADDS_A.W */
DIP("ADDS_A.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs32x4, getWReg(ws)));
assign(t2, unop(Iop_Abs32x4, getWReg(wt)));
assign(t3, binop(Iop_SarN32x4,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
mkU8(31)));
assign(t4, binop(Iop_SarN32x4,
binop(Iop_AndV128,
mkexpr(t2),
getWReg(wt)),
mkU8(31)));
putWReg(wd, binop(Iop_QAdd32Sx4,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t3)),
mkexpr(t1)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t4)),
mkexpr(t2)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t2)),
mkexpr(t4)))));
break;
}
case 0x03: { /* ADDS_A.D */
DIP("ADDS_A.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1, unop(Iop_Abs64x2, getWReg(ws)));
assign(t2, unop(Iop_Abs64x2, getWReg(wt)));
assign(t3, binop(Iop_SarN64x2,
binop(Iop_AndV128,
mkexpr(t1),
getWReg(ws)),
mkU8(63)));
assign(t4, binop(Iop_SarN64x2,
binop(Iop_AndV128,
mkexpr(t2),
getWReg(wt)),
mkU8(63)));
putWReg(wd,
binop(Iop_QAdd64Sx2,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t3)),
mkexpr(t1)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t4)),
mkexpr(t2)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t2)),
mkexpr(t4)))));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* ADDS_S.df */
switch (df) {
case 0x00: { /* ADDS_S.B */
DIP("ADDS_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ADDS_S.H */
DIP("ADDS_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ADDS_S.W */
DIP("ADDS_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ADDS_S.D */
DIP("ADDS_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd64Sx2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* ADDS_U.df */
switch (df) {
case 0x00: { /* ADDS_U.B */
DIP("ADDS_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ADDS_U.H */
DIP("ADDS_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ADDS_U.W */
DIP("ADDS_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ADDS_U.D */
DIP("ADDS_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QAdd64Ux2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* AVE_S.df */
switch (df) {
case 0x00: { /* AVE_S.B */
DIP("AVE_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add8x16,
binop(Iop_Add8x16,
binop(Iop_SarN8x16,
mkexpr(t1), mkU8(1)),
binop(Iop_SarN8x16,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN8x16,
binop(Iop_ShlN8x16,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(7)),
mkU8(7))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* AVE_S.H */
DIP("AVE_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add16x8,
binop(Iop_Add16x8,
binop(Iop_SarN16x8,
mkexpr(t1), mkU8(1)),
binop(Iop_SarN16x8,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN16x8,
binop(Iop_ShlN16x8,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(15)),
mkU8(15))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* AVE_S.W */
DIP("AVE_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add32x4,
binop(Iop_Add32x4,
binop(Iop_SarN32x4,
mkexpr(t1), mkU8(1)),
binop(Iop_SarN32x4,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN32x4,
binop(Iop_ShlN32x4,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(31)),
mkU8(31))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* AVE_S.D */
DIP("AVE_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add64x2,
binop(Iop_Add64x2,
binop(Iop_SarN64x2,
mkexpr(t1), mkU8(1)),
binop(Iop_SarN64x2,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(63)),
mkU8(63))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* AVE_U.df */
switch (df) {
case 0x00: { /* AVE_U.B */
DIP("AVE_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add16x8,
binop(Iop_Add8x16,
binop(Iop_ShrN8x16,
mkexpr(t1), mkU8(1)),
binop(Iop_ShrN8x16,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN8x16,
binop(Iop_ShlN8x16,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(7)),
mkU8(7))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* AVE_U.H */
DIP("AVE_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add16x8,
binop(Iop_Add16x8,
binop(Iop_ShrN16x8,
mkexpr(t1), mkU8(1)),
binop(Iop_ShrN16x8,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN16x8,
binop(Iop_ShlN16x8,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(15)),
mkU8(15))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* AVE_U.W */
DIP("AVE_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add32x4,
binop(Iop_Add32x4,
binop(Iop_ShrN32x4,
mkexpr(t1), mkU8(1)),
binop(Iop_ShrN32x4,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN32x4,
binop(Iop_ShlN32x4,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(31)),
mkU8(31))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* AVE_U.D */
DIP("AVE_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add64x2,
binop(Iop_Add64x2,
binop(Iop_ShrN64x2,
mkexpr(t1), mkU8(1)),
binop(Iop_ShrN64x2,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
binop(Iop_AndV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(63)),
mkU8(63))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x06: { /* AVER_S.df */
switch (df) {
case 0x00: { /* AVER_S.B */
DIP("AVER_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Avg8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* AVER_S.H */
DIP("AVER_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Avg16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* AVER_S.W */
DIP("AVER_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Avg32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* AVER_S.D */
DIP("AVER_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add64x2,
binop(Iop_Add64x2,
binop(Iop_SarN64x2,
mkexpr(t1), mkU8(1)),
binop(Iop_SarN64x2,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
binop(Iop_OrV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(63)),
mkU8(63))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* AVER_U.df */
switch (df) {
case 0x00: { /* AVER_U.B */
DIP("AVER_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Avg8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* AVER_U.H */
DIP("AVER_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Avg16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* AVER_U.W */
DIP("AVER_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Avg32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* AVER_U.D */
DIP("AVER_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_Add64x2,
binop(Iop_Add64x2,
binop(Iop_ShrN64x2,
mkexpr(t1), mkU8(1)),
binop(Iop_ShrN64x2,
mkexpr(t2), mkU8(1))),
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
binop(Iop_OrV128,
mkexpr(t1),
mkexpr(t2)),
mkU8(63)),
mkU8(63))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_11(UInt cins, UChar wd, UChar ws) /* 3R (0x11) */
{
IRTemp t1, t2, t3;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* SUBS_S.df */
switch (df) {
case 0x00: { /* SUBS_S.B */
DIP("SUBS_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub8Sx16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SUBS_S.H */
DIP("SUBS_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub16Sx8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SUBS_S.W */
DIP("SUBS_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub32Sx4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SUBS_S.D */
DIP("SUBS_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub64Sx2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* SUBS_U.df */
switch (df) {
case 0x00: { /* SUBS_U.B */
DIP("SUBS_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub8Ux16, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* SUBS_U.H */
DIP("SUBS_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub16Ux8, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* SUBS_U.W */
DIP("SUBS_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub32Ux4, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* SUBS_U.D */
DIP("SUBS_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QSub64Ux2, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* SUBSUS_U.df */
switch (df) {
case 0x00: { /* SUBSUS_U.B */
DIP("SUBSUS_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub8x16, getWReg(ws), getWReg(wt)));
assign(t2, binop(Iop_SarN8x16, getWReg(wt), mkU8(7)));
assign(t3, binop(Iop_OrV128,
binop(Iop_CmpGT8Ux16,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpEQ8x16,
getWReg(ws),
getWReg(wt))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_XorV128,
mkexpr(t3),
mkexpr(t2)))));
break;
}
case 0x01: { /* SUBSUS_U.H */
DIP("SUBSUS_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub16x8, getWReg(ws), getWReg(wt)));
assign(t2, binop(Iop_SarN16x8, getWReg(wt), mkU8(15)));
assign(t3,
binop(Iop_OrV128,
binop(Iop_CmpGT16Ux8,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpEQ16x8,
getWReg(ws),
getWReg(wt))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_XorV128,
mkexpr(t3),
mkexpr(t2)))));
break;
}
case 0x02: { /* SUBSUS_U.W */
DIP("SUBSUS_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub32x4, getWReg(ws), getWReg(wt)));
assign(t2, binop(Iop_SarN32x4, getWReg(wt), mkU8(31)));
assign(t3,
binop(Iop_OrV128,
binop(Iop_CmpGT32Ux4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpEQ32x4,
getWReg(ws),
getWReg(wt))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_XorV128,
mkexpr(t3),
mkexpr(t2)))));
break;
}
case 0x03: { /* SUBSUS_U.D */
DIP("SUBSUS_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub64x2, getWReg(ws), getWReg(wt)));
assign(t2, binop(Iop_SarN64x2, getWReg(wt), mkU8(63)));
assign(t3,
binop(Iop_OrV128,
binop(Iop_CmpGT64Ux2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpEQ64x2,
getWReg(ws),
getWReg(wt))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_XorV128,
mkexpr(t3),
mkexpr(t2)))));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* SUBSUU_S.df */
switch (df) {
case 0x00: { /* SUBSUU_S.B */
DIP("SUBSUU_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub8x16, getWReg(ws), getWReg(wt)));
assign(t2,
binop(Iop_SarN8x16,
binop (Iop_AndV128,
binop(Iop_XorV128,
getWReg(ws),
getWReg(wt)),
binop(Iop_XorV128,
mkexpr(t1),
getWReg(wt))),
mkU8(7)));
assign(t3,
binop(Iop_AndV128,
binop(Iop_SarN8x16,
getWReg(ws), mkU8(7)),
mkexpr(t2)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_XorV128,
binop(Iop_ShlN8x16,
mkexpr(t2), mkU8(7)),
mkexpr(t3))));
break;
}
case 0x01: { /* SUBSUU_S.H */
DIP("SUBSUU_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub16x8, getWReg(ws), getWReg(wt)));
assign(t2,
binop(Iop_SarN16x8,
binop (Iop_AndV128,
binop(Iop_XorV128,
getWReg(ws),
getWReg(wt)),
binop(Iop_XorV128,
mkexpr(t1),
getWReg(wt))),
mkU8(15)));
assign(t3,
binop(Iop_AndV128,
binop(Iop_SarN16x8,
getWReg(ws),
mkU8(15)),
mkexpr(t2)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_XorV128,
binop(Iop_ShlN16x8,
mkexpr(t2), mkU8(15)),
mkexpr(t3))));
break;
}
case 0x02: { /* SUBSUU_S.W */
DIP("SUBSUU_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub32x4, getWReg(ws), getWReg(wt)));
assign(t2,
binop(Iop_SarN32x4,
binop (Iop_AndV128,
binop(Iop_XorV128,
getWReg(ws),
getWReg(wt)),
binop(Iop_XorV128,
mkexpr(t1),
getWReg(wt))),
mkU8(31)));
assign(t3,
binop(Iop_AndV128,
binop(Iop_SarN32x4,
getWReg(ws),
mkU8(31)),
mkexpr(t2)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_XorV128,
binop(Iop_ShlN32x4,
mkexpr(t2),
mkU8(31)),
mkexpr(t3))));
break;
}
case 0x03: { /* SUBSUU_S.D */
DIP("SUBSUU_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_Sub64x2, getWReg(ws), getWReg(wt)));
assign(t2,
binop(Iop_SarN64x2,
binop (Iop_AndV128,
binop(Iop_XorV128,
getWReg(ws),
getWReg(wt)),
binop(Iop_XorV128,
mkexpr(t1),
getWReg(wt))),
mkU8(63)));
assign(t3,
binop(Iop_AndV128,
binop(Iop_SarN64x2,
getWReg(ws),
mkU8(63)),
mkexpr(t2)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_XorV128,
binop(Iop_ShlN64x2,
mkexpr(t2), mkU8(63)),
mkexpr(t3))));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* ASUB_S.df */
switch (df) {
case 0x00: { /* ASUB_S.B */
DIP("ASUB_S.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN8x16, getWReg(ws), mkU8(7)));
assign(t2, binop(Iop_SarN8x16, getWReg(wt), mkU8(7)));
assign(t3, binop(Iop_Sub8x16, getWReg(ws), getWReg(wt)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t2)),
mkexpr(t3)),
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_XorV128,
mkexpr(t1),
mkexpr(t2))),
unop(Iop_Abs8x16,
mkexpr(t3)))),
binop(Iop_AndV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_Sub8x16,
getWReg(wt),
getWReg(ws)))));
break;
}
case 0x01: { /* ASUB_S.H */
DIP("ASUB_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN16x8, getWReg(ws), mkU8(15)));
assign(t2, binop(Iop_SarN16x8, getWReg(wt), mkU8(15)));
assign(t3, binop(Iop_Sub16x8, getWReg(ws), getWReg(wt)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t2)),
mkexpr(t3)),
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_XorV128,
mkexpr(t1),
mkexpr(t2))),
unop(Iop_Abs16x8,
mkexpr(t3)))),
binop(Iop_AndV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_Sub16x8,
getWReg(wt),
getWReg(ws)))));
break;
}
case 0x02: { /* ASUB_S.W */
DIP("ASUB_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN32x4, getWReg(ws), mkU8(31)));
assign(t2, binop(Iop_SarN32x4, getWReg(wt), mkU8(31)));
assign(t3, binop(Iop_Sub32x4, getWReg(ws), getWReg(wt)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t2)),
mkexpr(t3)),
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_XorV128,
mkexpr(t1),
mkexpr(t2))),
unop(Iop_Abs32x4,
mkexpr(t3)))),
binop(Iop_AndV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_Sub32x4,
getWReg(wt),
getWReg(ws)))));
break;
}
case 0x03: { /* ASUB_S.D */
DIP("ASUB_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, binop(Iop_SarN64x2, getWReg(ws), mkU8(63)));
assign(t2, binop(Iop_SarN64x2, getWReg(wt), mkU8(63)));
assign(t3, binop(Iop_Sub64x2, getWReg(ws), getWReg(wt)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
mkexpr(t2)),
mkexpr(t3)),
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_XorV128,
mkexpr(t1),
mkexpr(t2))),
unop(Iop_Abs64x2,
mkexpr(t3)))),
binop(Iop_AndV128,
binop(Iop_AndV128,
mkexpr(t1),
unop(Iop_NotV128,
mkexpr(t2))),
binop(Iop_Sub64x2,
getWReg(wt),
getWReg(ws)))));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* ASUB_U.df */
switch (df) {
case 0x00: { /* ASUB_U.B */
DIP("ASUB_U.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_SarN8x16,
binop(Iop_XorV128,
mkexpr(t1), mkexpr(t2)),
mkU8(7)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t3)),
unop(Iop_Abs8x16,
binop(Iop_Sub8x16,
mkexpr(t1),
mkexpr(t2)))),
binop(Iop_AndV128, mkexpr(t3),
binop(Iop_Sub8x16,
binop(Iop_Max8Ux16,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_Min8Ux16,
mkexpr(t1),
mkexpr(t2))))));
break;
}
case 0x01: { /* ASUB_U.H */
DIP("ASUB_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_SarN16x8,
binop(Iop_XorV128,
mkexpr(t1), mkexpr(t2)),
mkU8(15)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t3)),
unop(Iop_Abs16x8,
binop(Iop_Sub16x8,
mkexpr(t1),
mkexpr(t2)))),
binop(Iop_AndV128,
mkexpr(t3),
binop(Iop_Sub16x8,
binop(Iop_Max16Ux8,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_Min16Ux8,
mkexpr(t1),
mkexpr(t2))))));
break;
}
case 0x02: { /* ASUB_U.W */
DIP("ASUB_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_SarN32x4,
binop(Iop_XorV128,
mkexpr(t1), mkexpr(t2)),
mkU8(31)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t3)),
unop(Iop_Abs32x4,
binop(Iop_Sub32x4,
mkexpr(t1),
mkexpr(t2)))),
binop(Iop_AndV128,
mkexpr(t3),
binop(Iop_Sub32x4,
binop(Iop_Max32Ux4,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_Min32Ux4,
mkexpr(t1),
mkexpr(t2))))));
break;
}
case 0x03: { /* ASUB_U.D */
DIP("ASUB_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_SarN64x2,
binop(Iop_XorV128,
mkexpr(t1), mkexpr(t2)),
mkU8(63)));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t3)),
unop(Iop_Abs64x2,
binop(Iop_Sub64x2,
mkexpr(t1),
mkexpr(t2)))),
binop(Iop_AndV128,
mkexpr(t3),
binop(Iop_Sub64x2,
binop(Iop_Max64Ux2,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_Min64Ux2,
mkexpr(t1),
mkexpr(t2))))));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_12(UInt cins, UChar wd, UChar ws) /* 3R (0x12) */
{
IRTemp t1, t2, t3, t4, t5, t6;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* MULV.df */
switch (df) {
case 0x00: { /* MULV.B */
DIP("MULV.B w%d, w%d, w%d", wd, ws, wt);
putWReg(wd, binop(Iop_Mul8x16, getWReg(ws), getWReg(wt)));
break;
}
case 0x01: { /* MULV.H */
DIP("MULV.H w%d, w%d, w%d", wd, ws, wt);
putWReg(wd, binop(Iop_Mul16x8, getWReg(ws), getWReg(wt)));
break;
}
case 0x02: { /* MULV.W */
DIP("MULV.W w%d, w%d, w%d", wd, ws, wt);
putWReg(wd, binop(Iop_Mul32x4, getWReg(ws), getWReg(wt)));
break;
}
case 0x03: { /* MULV.D */
DIP("MULV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t2))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t2)))));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* MADDV.df */
switch (df) {
case 0x00: { /* MADDV.B */
DIP("MADDV.B w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_Add8x16,
getWReg(wd),
binop(Iop_Mul8x16,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* MADDV.H */
DIP("MADDV.H w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_Add16x8,
getWReg(wd),
binop(Iop_Mul16x8,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x02: { /* MADDV.W */
DIP("MADDV.W w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_Add32x4,
getWReg(wd),
binop(Iop_Mul32x4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x03: { /* MADDV.D */
DIP("MADDV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
putWReg(wd,
binop(Iop_Add64x2,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t2))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t2))))));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* MSUBV.df */
switch (df) {
case 0x00: { /* MSUBV.B */
DIP("MSUBV.B w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_Sub8x16,
getWReg(wd),
binop(Iop_Mul8x16,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* MSUBV.H */
DIP("MSUBV.H w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_Sub16x8,
getWReg(wd),
binop(Iop_Mul16x8,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x02: { /* MSUBV.W */
DIP("MSUBV.W w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_Sub32x4,
getWReg(wd),
binop(Iop_Mul32x4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x03: { /* MSUBV.D */
DIP("MSUBV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
putWReg(wd,
binop(Iop_Sub64x2,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t2))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t2))))));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* DIV_S.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x00: { /* DIV_S.B */
DIP("DIV_S.B w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[16];
Int i;
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFF),
binop(Iop_DivS32,
unop(Iop_8Sto32,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i))),
unop(Iop_8Sto32,
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(i))))),
mkU8((i & 3) << 3)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[15]),
binop(Iop_Or32,
mkexpr(tmp[14]),
binop(Iop_Or32,
mkexpr(tmp[13]),
mkexpr(tmp[12])))),
binop(Iop_Or32,
mkexpr(tmp[11]),
binop(Iop_Or32,
mkexpr(tmp[10]),
binop(Iop_Or32,
mkexpr(tmp[9]),
mkexpr(tmp[8]))))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
binop(Iop_Or32,
mkexpr(tmp[6]),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4])))),
binop(Iop_Or32,
mkexpr(tmp[3]),
binop(Iop_Or32,
mkexpr(tmp[2]),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))))
);
break;
}
case 0x01: { /* DIV_S.H */
DIP("DIV_S.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFFFF),
binop(Iop_DivS32,
unop(Iop_16Sto32,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i))),
unop(Iop_16Sto32,
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(i))))),
mkU8((i & 1) << 4)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* DIV_S.W */
DIP("DIV_S.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_DivS32,
binop(Iop_GetElem32x4,
mkexpr(t1), mkU8(i)),
binop(Iop_GetElem32x4,
mkexpr(t2), mkU8(i))));
}
putWReg(wd,
binop(Iop_64HLtoV128, \
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* DIV_S.D */
DIP("DIV_S.D w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_DivS64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t2))),
binop(Iop_DivS64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t2)))));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* DIV_U.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x00: { /* DIV_U.B */
DIP("DIV_U.B w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[16];
Int i;
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFF),
binop(Iop_DivU32,
unop(Iop_8Uto32,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i))),
unop(Iop_8Uto32,
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(i))))),
mkU8((i & 3) << 3)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[15]),
binop(Iop_Or32,
mkexpr(tmp[14]),
binop(Iop_Or32,
mkexpr(tmp[13]),
mkexpr(tmp[12])))),
binop(Iop_Or32,
mkexpr(tmp[11]),
binop(Iop_Or32,
mkexpr(tmp[10]),
binop(Iop_Or32,
mkexpr(tmp[9]),
mkexpr(tmp[8]))))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
binop(Iop_Or32,
mkexpr(tmp[6]),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4])))),
binop(Iop_Or32,
mkexpr(tmp[3]),
binop(Iop_Or32,
mkexpr(tmp[2]),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))))
);
break;
}
case 0x01: { /* DIV_U.H */
DIP("DIV_U.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFFFF),
binop(Iop_DivU32,
unop(Iop_16Uto32,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i))),
unop(Iop_16Uto32,
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(i))))),
mkU8((i & 1) << 4)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* DIV_U.W */
DIP("DIV_U.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_DivU32,
binop(Iop_GetElem32x4,
mkexpr(t1), mkU8(i)),
binop(Iop_GetElem32x4,
mkexpr(t2), mkU8(i))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* DIV_U.D */
DIP("DIV_U.D w%d, w%d, w%d", wd, ws, wt);
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_DivU64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t2))),
binop(Iop_DivU64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t2)))));
break;
}
default:
return -1;
}
break;
}
case 0x06: { /* MOD_S.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x00: { /* MOD_S.B */
DIP("MOD_S.B w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[16];
Int i;
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFF),
unop(Iop_64HIto32,
binop(Iop_DivModS32to32,
unop(Iop_8Sto32,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i))),
unop(Iop_8Sto32,
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(i)))))),
mkU8((i & 3) << 3)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[15]),
binop(Iop_Or32,
mkexpr(tmp[14]),
binop(Iop_Or32,
mkexpr(tmp[13]),
mkexpr(tmp[12])))),
binop(Iop_Or32,
mkexpr(tmp[11]),
binop(Iop_Or32,
mkexpr(tmp[10]),
binop(Iop_Or32,
mkexpr(tmp[9]),
mkexpr(tmp[8]))))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
binop(Iop_Or32,
mkexpr(tmp[6]),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4])))),
binop(Iop_Or32,
mkexpr(tmp[3]),
binop(Iop_Or32,
mkexpr(tmp[2]),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))))));
break;
}
case 0x01: { /* MOD_S.H */
DIP("MOD_S.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFFFF),
unop(Iop_64HIto32,
binop(Iop_DivModS32to32,
unop(Iop_16Sto32,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i))),
unop(Iop_16Sto32,
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(i)))))),
mkU8((i & 1) << 4)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* MOD_S.W */
DIP("MOD_S.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
unop(Iop_64HIto32,
binop(Iop_DivModS32to32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(i)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* MOD_S.D */
DIP("MOD_S.D w%d, w%d, w%d", wd, ws, wt);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
t6 = newTemp(Ity_I64);
assign(t3, unop(Iop_V128HIto64, mkexpr(t1)));
assign(t4, unop(Iop_V128HIto64, mkexpr(t2)));
assign(t5, unop(Iop_V128to64, mkexpr(t1)));
assign(t6, unop(Iop_V128to64, mkexpr(t2)));
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_Sub64,
mkexpr(t3),
binop(Iop_Mul64,
mkexpr(t4),
binop(Iop_DivS64,
mkexpr(t3),
mkexpr(t4)))),
binop(Iop_Sub64,
mkexpr(t5),
binop(Iop_Mul64,
mkexpr(t6),
binop(Iop_DivS64,
mkexpr(t5),
mkexpr(t6))))));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* MOD_U.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x00: { /* MOD_U.B */
DIP("MOD_U.B w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[16];
Int i;
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFF),
unop(Iop_64HIto32,
binop(Iop_DivModU32to32,
unop(Iop_8Uto32,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i))),
unop(Iop_8Uto32,
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(i)))))),
mkU8((i & 3) << 3)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[15]),
binop(Iop_Or32,
mkexpr(tmp[14]),
binop(Iop_Or32,
mkexpr(tmp[13]),
mkexpr(tmp[12])))),
binop(Iop_Or32,
mkexpr(tmp[11]),
binop(Iop_Or32,
mkexpr(tmp[10]),
binop(Iop_Or32,
mkexpr(tmp[9]),
mkexpr(tmp[8]))))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
binop(Iop_Or32,
mkexpr(tmp[6]),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4])))),
binop(Iop_Or32,
mkexpr(tmp[3]),
binop(Iop_Or32,
mkexpr(tmp[2]),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))))));
break;
}
case 0x01: { /* MOD_U.H */
DIP("MOD_U.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Shl32,
binop(Iop_And32,
mkU32(0xFFFF),
unop(Iop_64HIto32,
binop(Iop_DivModU32to32,
unop(Iop_16Uto32,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i))),
unop(Iop_16Uto32,
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(i)))))),
mkU8((i & 1) << 4)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_Or32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_Or32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* MOD_U.W */
DIP("MOD_U.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
unop(Iop_64HIto32,
binop(Iop_DivModU32to32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(i)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* MOD_U.D */
DIP("MOD_U.D w%d, w%d, w%d", wd, ws, wt);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
t6 = newTemp(Ity_I64);
assign(t3, unop(Iop_V128HIto64, mkexpr(t1)));
assign(t4, unop(Iop_V128HIto64, mkexpr(t2)));
assign(t5, unop(Iop_V128to64, mkexpr(t1)));
assign(t6, unop(Iop_V128to64, mkexpr(t2)));
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_Sub64,
mkexpr(t3),
binop(Iop_Mul64,
mkexpr(t4),
binop(Iop_DivU64,
mkexpr(t3),
mkexpr(t4)))),
binop(Iop_Sub64,
mkexpr(t5),
binop(Iop_Mul64,
mkexpr(t6),
binop(Iop_DivU64,
mkexpr(t5),
mkexpr(t6))))));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_13(UInt cins, UChar wd, UChar ws) /* 3R (0x13) */
{
IRTemp t1, t2;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* DOTP_S.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x01: { /* DOTP_S.H */
DIP("DOTP_S.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_Add16,
binop(Iop_MullS8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* DOTP_S.W */
DIP("DOTP_S.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Add32,
binop(Iop_MullS16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* DOTP_S.D */
DIP("DOTP_S.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_Add64,
binop(Iop_MullS32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(tmp[1]), mkexpr(tmp[0])));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* DOTP_U.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x01: { /* DOTP_U.H */
DIP("DOTP_U.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_Add16,
binop(Iop_MullU8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* DOTP_U.W */
DIP("DOTP_U.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Add32,
binop(Iop_MullU16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* DOTP_U.D */
DIP("DOTP_U.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_Add64,
binop(Iop_MullU32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(tmp[1]), mkexpr(tmp[0])));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* DPADD_S.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x01: { /* DPADD_S.H */
DIP("DPADD_S.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_Add16,
binop(Iop_MullS8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Add16x8,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x02: { /* DPADD_S.W */
DIP("DPADD_S.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Add32,
binop(Iop_MullS16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Add32x4,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x03: { /* DPADD_S.D */
DIP("DPADD_S.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_Add64,
binop(Iop_MullS32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Add64x2,
getWReg(wd),
binop(Iop_64HLtoV128,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* DPADD_U.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x01: { /* DPADD_U.H */
DIP("DPADD_U.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_Add16,
binop(Iop_MullU8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Add16x8,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x02: { /* DPADD_U.W */
DIP("DPADD_U.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Add32,
binop(Iop_MullU16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Add32x4,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x03: { /* DPADD_U.D */
DIP("DPADD_U.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_Add64,
binop(Iop_MullU32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Add64x2,
getWReg(wd),
binop(Iop_64HLtoV128,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* DPSUB_S.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x01: { /* DPSUB_S.H */
DIP("DPSUB_S.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_Add16,
binop(Iop_MullS8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Sub16x8,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x02: { /* DPSUB_S.W */
DIP("DPSUB_S.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Add32,
binop(Iop_MullS16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Sub32x4,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x03: { /* DPSUB_S.D */
DIP("DPSUB_S.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_Add64,
binop(Iop_MullS32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullS32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Sub64x2,
getWReg(wd),
binop(Iop_64HLtoV128,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* DPSUB_U.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
switch (df) {
case 0x01: { /* DPSUB_U.H */
DIP("DPSUB_U.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_Add16,
binop(Iop_MullU8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem8x16,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Sub16x8,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x02: { /* DPSUB_U.W */
DIP("DPSUB_U.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_Add32,
binop(Iop_MullU16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem16x8,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Sub32x4,
getWReg(wd),
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x03: { /* DPSUB_U.D */
DIP("DPSUB_U.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_Add64,
binop(Iop_MullU32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i))),
binop(Iop_MullU32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2 * i + 1)),
binop(Iop_GetElem32x4,
mkexpr(t2),
mkU8(2 * i + 1)))));
}
putWReg(wd,
binop(Iop_Sub64x2,
getWReg(wd),
binop(Iop_64HLtoV128,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_14(UInt cins, UChar wd, UChar ws) /* 3R (0x14) */
{
IRTemp t1, t2, t3, t4;
IRType ty;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
ty = mode64 ? Ity_I64 : Ity_I32;
switch (operation) {
case 0x00: { /* SLD.df */
switch (df) {
case 0x00: {
DIP("SLD.B w%d, w%d[%d]", wd, ws, wt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shl32,
binop(Iop_And32,
mkNarrowTo32(ty,
getIReg(wt)),
mkU32(15)),
mkU8(3)));
assign(t2,
binop(Iop_ShrV128,
getWReg(ws),
unop(Iop_32to8, mkexpr(t1))));
assign(t3,
binop(Iop_ShlV128,
getWReg(wd),
unop(Iop_32to8,
binop(Iop_Sub32,
mkU32(128),
mkexpr(t1)))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t2), mkexpr(t3)));
break;
}
case 0x01: {/* SLD.H */
DIP("SLD.H w%d, w%d[%d]", wd, ws, wt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shl32,
binop(Iop_And32,
mkNarrowTo32(ty,
getIReg(wt)),
mkU32(7)),
mkU8(3)));
assign(t2,
binop(Iop_32HLto64, mkU32(0), mkexpr(t1)));
assign(t3,
binop(Iop_Shr64x2,
getWReg(ws),
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t2))));
assign(t4,
binop(Iop_Shl64x2,
getWReg(wd),
binop(Iop_Sub64x2,
binop(Iop_64HLtoV128,
mkU64(0x40ul),
mkU64(0x40ul)),
binop(Iop_64HLtoV128,
mkexpr(t2),
mkexpr(t2)))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3),
IRExpr_ITE(
binop(Iop_CmpNE32,
mkexpr(t1), mkU32(0)),
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
break;
}
case 0x02: {/* SLD.W */
DIP("SLD.W w%d, w%d[%d]", wd, ws, wt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shl32,
binop(Iop_And32,
mkNarrowTo32(ty,
getIReg(wt)),
mkU32(3)),
mkU8(3)));
assign(t2,
binop(Iop_32HLto64,
mkexpr(t1), mkexpr(t1)));
assign(t3,
binop(Iop_Shr32x4,
getWReg(ws),
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t2))));
assign(t4,
binop(Iop_Shl32x4,
getWReg(wd),
binop(Iop_Sub32x4,
binop(Iop_64HLtoV128,
mkU64(0x2000000020ul),
mkU64(0x2000000020ul)),
binop(Iop_64HLtoV128,
mkexpr(t2),
mkexpr(t2)))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3),
IRExpr_ITE(
binop(Iop_CmpNE32,
mkexpr(t1), mkU32(0)),
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
break;
}
case 0x03: { /* SLD.D */
DIP("SLD.D w%d, w%d[%d]", wd, ws, wt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shl32,
binop(Iop_And32,
mkNarrowTo32(ty,
getIReg(wt)),
mkU32(1)),
mkU8(3)));
assign(t2,
binop(Iop_32HLto64,
binop(Iop_Or32,
mkexpr(t1),
binop(Iop_Shl32,
mkexpr(t1), mkU8(16))),
binop(Iop_Or32,
mkexpr(t1),
binop(Iop_Shl32,
mkexpr(t1), mkU8(16)))));
assign(t3,
binop(Iop_Shr16x8,
getWReg(ws),
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t2))));
assign(t4,
binop(Iop_Shl16x8,
getWReg(wd),
binop(Iop_Sub16x8,
binop(Iop_64HLtoV128,
mkU64(0x10001000100010ul),
mkU64(0x10001000100010ul)),
binop(Iop_64HLtoV128,
mkexpr(t2),
mkexpr(t2)))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3),
IRExpr_ITE(
binop(Iop_CmpNE32,
mkexpr(t1), mkU32(0)),
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
break;
}
}
break;
}
case 0x01: { /* SPLAT.df */
switch (df) {
Int i;
case 0x00: { /* SPLAT.B */
DIP("SPLAT.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I32);
assign(t1, getWReg(ws));
assign(t2,
mkNarrowTo32(ty, getIReg(wt)));
IRTemp tmp[16];
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I8);
assign(tmp[i],
binop(Iop_GetElem8x16,
mkexpr(t1),
unop(Iop_32to8, mkexpr(t2))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[15]),
mkexpr(tmp[14])),
binop(Iop_8HLto16,
mkexpr(tmp[13]),
mkexpr(tmp[12]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[11]),
mkexpr(tmp[10])),
binop(Iop_8HLto16,
mkexpr(tmp[9]),
mkexpr(tmp[8])))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_8HLto16,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_8HLto16,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x01: { /* SPLAT.H */
DIP("SPLAT.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I32);
assign(t1, getWReg(ws));
assign(t2,
mkNarrowTo32(ty, getIReg(wt)));
IRTemp tmp[8];
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
binop(Iop_GetElem16x8,
mkexpr(t1),
unop(Iop_32to8, mkexpr(t2))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* SPLAT.W */
DIP("SPLAT.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I32);
assign(t1, getWReg(ws));
assign(t2,
mkNarrowTo32(ty, getIReg(wt)));
IRTemp tmp[4];
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
binop(Iop_GetElem32x4,
mkexpr(t1),
unop(Iop_32to8, mkexpr(t2))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* SPLAT.D */
DIP("SPLAT.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I32);
assign(t1, getWReg(ws));
assign(t2,
mkNarrowTo32(ty, getIReg(wt)));
IRTemp tmp[2];
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
binop(Iop_GetElem64x2,
mkexpr(t1),
unop(Iop_32to8, mkexpr(t2))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(tmp[1]), mkexpr(tmp[0])));
break;
}
}
break;
}
case 0x02: { /* PCKEV.df */
switch (df) {
case 0x00: { /* PCKEV.B */
DIP("PCKEV.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_PackEvenLanes8x16,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* PCKEV.H */
DIP("PCKEV.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_PackEvenLanes16x8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* PCKEV.W */
DIP("PCKEV.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_PackEvenLanes32x4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* PCKEV.D */
DIP("PCKEV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveLO64x2,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* PCKOD.df */
switch (df) {
case 0x00: { /* PCKOD.B */
DIP("PCKOD.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_PackOddLanes8x16,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* PCKOD.H */
DIP("PCKOD.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_PackOddLanes16x8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* PCKOD.W */
DIP("PCKOD.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_PackOddLanes32x4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* PCKOD.D */
DIP("PCKOD.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveHI64x2,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* ILVL.df */
switch (df) {
case 0x00: { /* ILVL.B */
DIP("ILVL.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveHI8x16,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ILVL.H */
DIP("ILVL.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveHI16x8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ILVL.W */
DIP("ILVL.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveHI32x4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ILVL.D */
DIP("ILVL.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveHI64x2,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* ILVR.df */
switch (df) {
case 0x00: { /* ILVL.B */
DIP("ILVL.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveLO8x16,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ILVL.H */
DIP("ILVL.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveLO16x8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ILVL.W */
DIP("ILVL.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveLO32x4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ILVL.D */
DIP("ILVL.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveLO64x2,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
}
break;
}
case 0x06: { /* ILVEV.df */
switch (df) {
case 0x00: { /* ILVEV.B */
DIP("ILVEV.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveEvenLanes8x16,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ILVEV.H */
DIP("ILVEV.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveEvenLanes16x8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ILVEV.W */
DIP("ILVEV.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveEvenLanes32x4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ILVEV.D */
DIP("ILVEV.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveLO64x2,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* ILVOD.df */
switch (df) {
case 0x00: { /* ILVOD.B */
DIP("ILVOD.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveOddLanes8x16,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* ILVOD.H */
DIP("ILVOD.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveOddLanes16x8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* ILVOD.W */
DIP("ILVOD.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveOddLanes32x4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* ILVOD.D */
DIP("ILVOD.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_InterleaveHI64x2,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_15(UInt cins, UChar wd, UChar ws) /* 3R (0x15) */
{
IRTemp t1, t2, t3, t4;
UShort operation;
UChar df, wt;
operation = (cins & 0x03800000) >> 23;
df = (cins & 0x00600000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* VSHF.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
assign(t3, getWReg(wt));
switch (df) {
case 0x00: { /* VSHF.B */
DIP("VSHF.B w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[16];
Int i;
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I8);
assign(tmp[i],
IRExpr_ITE(
binop(Iop_CmpEQ8,
binop(Iop_And8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i)),
mkU8(0xC0)),
mkU8(0x0)),
IRExpr_ITE(
binop(Iop_CmpEQ8,
binop(Iop_And8,
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i)),
mkU8(0x10)),
mkU8(0x0)),
binop(Iop_GetElem8x16,
mkexpr(t3),
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i))),
binop(Iop_GetElem8x16,
mkexpr(t2),
binop(Iop_GetElem8x16,
mkexpr(t1),
mkU8(i)))),
mkU8(0x0)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[15]),
mkexpr(tmp[14])),
binop(Iop_8HLto16,
mkexpr(tmp[13]),
mkexpr(tmp[12]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[11]),
mkexpr(tmp[10])),
binop(Iop_8HLto16,
mkexpr(tmp[9]),
mkexpr(tmp[8])))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_8HLto16,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_8HLto16,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x01: { /* VSHF.H */
DIP("VSHF.H w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[8];
Int i;
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
assign(tmp[i],
IRExpr_ITE(
binop(Iop_CmpEQ16,
binop(Iop_And16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i)),
mkU16(0xC0)),
mkU16(0x0)),
IRExpr_ITE(
binop(Iop_CmpEQ16,
binop(Iop_And16,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i)),
mkU16(0x08)),
mkU16(0x0)),
binop(Iop_GetElem16x8,
mkexpr(t3),
unop(Iop_16to8,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i)))),
binop(Iop_GetElem16x8,
mkexpr(t2),
unop(Iop_16to8,
binop(Iop_GetElem16x8,
mkexpr(t1),
mkU8(i))))),
mkU16(0x0)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x02: { /* VSHF.W */
DIP("VSHF.W w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
IRExpr_ITE(
binop(Iop_CmpEQ32,
binop(Iop_And32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(i)),
mkU32(0xC0)),
mkU32(0x0)),
IRExpr_ITE(
binop(Iop_CmpEQ32,
binop(Iop_And32,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(i)),
mkU32(0x04)),
mkU32(0x0)),
binop(Iop_GetElem32x4,
mkexpr(t3),
unop(Iop_32to8,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(i)))),
binop(Iop_GetElem32x4,
mkexpr(t2),
unop(Iop_32to8,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(i))))),
mkU32(0x0)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x03: { /* VSHF.D */
DIP("VSHF.D w%d, w%d, w%d", wd, ws, wt);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
IRExpr_ITE(
binop(Iop_CmpEQ64,
binop(Iop_And64,
binop(Iop_GetElem64x2,
mkexpr(t1),
mkU8(i)),
mkU64(0xC0)),
mkU64(0x0)),
IRExpr_ITE(
binop(Iop_CmpEQ64,
binop(Iop_And64,
binop(Iop_GetElem64x2,
mkexpr(t1),
mkU8(i)),
mkU64(0x02)),
mkU64(0x0)),
binop(Iop_GetElem64x2,
mkexpr(t3),
unop(Iop_64to8,
binop(Iop_GetElem64x2,
mkexpr(t1),
mkU8(i)))),
binop(Iop_GetElem64x2,
mkexpr(t2),
unop(Iop_64to8,
binop(Iop_GetElem64x2,
mkexpr(t1),
mkU8(i))))),
mkU64(0x0)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(tmp[1]), mkexpr(tmp[0])));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* SRAR.df */
switch (df) {
case 0x00: { /* SRAR.B */
DIP("SRAR.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Sar8x16,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub8x16,
binop(Iop_64HLtoV128,
mkU64(0x808080808080808ull),
mkU64(0x808080808080808ull)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ8x16,
binop(Iop_ShlN8x16,
getWReg(wt),
mkU8(5)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN8x16,
binop(Iop_AndV128,
binop(Iop_Shl8x16,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(7)));
putWReg(wd,
binop(Iop_Add8x16,
mkexpr(t1), mkexpr(t3)));
break;
}
case 0x01: { /* SRAR.H */
DIP("SRAR.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Sar16x8,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub16x8,
binop(Iop_64HLtoV128,
mkU64(0x10001000100010ul),
mkU64(0x10001000100010ul)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ16x8,
binop(Iop_ShlN16x8,
getWReg(wt),
mkU8(12)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN16x8,
binop(Iop_AndV128,
binop(Iop_Shl16x8,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(15)));
putWReg(wd,
binop(Iop_Add16x8,
mkexpr(t1), mkexpr(t3)));
break;
}
case 0x02: { /* SRAR.W */
DIP("SRAR.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128); // shifted
t2 = newTemp(Ity_V128); // 32 - wt
t3 = newTemp(Ity_V128); // rv
t4 = newTemp(Ity_V128); // wt % 32 == 0
assign(t1,
binop(Iop_Sar32x4,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub32x4,
binop(Iop_64HLtoV128,
mkU64(0x2000000020ul),
mkU64(0x2000000020ul)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ32x4,
binop(Iop_ShlN32x4,
getWReg(wt),
mkU8(27)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN32x4,
binop(Iop_AndV128,
binop(Iop_Shl32x4,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(31)));
putWReg(wd,
binop(Iop_Add32x4,
mkexpr(t1), mkexpr(t3)));
break;
}
case 0x03: { /* SRAR.D */
DIP("SRAR.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Sar64x2,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub64x2,
binop(Iop_64HLtoV128,
mkU64(64ul), mkU64(64ul)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ64x2,
binop(Iop_ShlN64x2,
getWReg(wt),
mkU8(58)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN64x2,
binop(Iop_AndV128,
binop(Iop_Shl64x2,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(63)));
putWReg(wd,
binop(Iop_Add64x2,
mkexpr(t1), mkexpr(t3)));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* SRLR.df */
switch (df) {
case 0x00: { /* SRLR.B */
DIP("SRLR.B w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shr8x16,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub8x16,
binop(Iop_64HLtoV128,
mkU64(0x808080808080808ull),
mkU64(0x808080808080808ull)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ8x16,
binop(Iop_ShlN8x16,
getWReg(wt),
mkU8(5)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN8x16,
binop(Iop_AndV128,
binop(Iop_Shl8x16,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(7)));
putWReg(wd,
binop(Iop_Add8x16,
mkexpr(t1), mkexpr(t3)));
break;
}
case 0x01: { /* SRLR.H */
DIP("SRLR.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shr16x8,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub16x8,
binop(Iop_64HLtoV128,
mkU64(0x10001000100010ul),
mkU64(0x10001000100010ul)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ16x8,
binop(Iop_ShlN16x8,
getWReg(wt),
mkU8(12)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN16x8,
binop(Iop_AndV128,
binop(Iop_Shl16x8,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(15)));
putWReg(wd,
binop(Iop_Add16x8,
mkexpr(t1), mkexpr(t3)));
break;
}
case 0x02: { /* SRLR.W */
DIP("SRLR.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shr32x4,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub32x4,
binop(Iop_64HLtoV128,
mkU64(0x2000000020ul),
mkU64(0x2000000020ul)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ32x4,
binop(Iop_ShlN32x4,
getWReg(wt),
mkU8(27)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN32x4,
binop(Iop_AndV128,
binop(Iop_Shl32x4,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(31)));
putWReg(wd,
binop(Iop_Add32x4,
mkexpr(t1), mkexpr(t3)));
break;
}
case 0x03: { /* SRLR.D */
DIP("SRLR.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_Shr64x2,
getWReg(ws),
getWReg(wt)));
assign(t2,
binop(Iop_Sub64x2,
binop(Iop_64HLtoV128,
mkU64(64ul), mkU64(64ul)),
getWReg(wt)));
assign(t4,
unop(Iop_NotV128,
binop(Iop_CmpEQ64x2,
binop(Iop_ShlN64x2,
getWReg(wt),
mkU8(58)),
binop(Iop_64HLtoV128,
mkU64(0), mkU64(0)))));
assign(t3,
binop(Iop_ShrN64x2,
binop(Iop_AndV128,
binop(Iop_Shl64x2,
getWReg(ws),
mkexpr(t2)),
mkexpr(t4)),
mkU8(63)));
putWReg(wd,
binop(Iop_Add64x2,
mkexpr(t1), mkexpr(t3)));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* HADD_S.df */
switch (df) {
case 0x01: { /* HADD_S.H */
DIP("HADD_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add16x8,
binop(Iop_SarN16x8,
mkexpr(t1), mkU8(8)),
binop(Iop_SarN16x8,
binop(Iop_ShlN16x8,
mkexpr(t2), mkU8(8)),
mkU8(8))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* HADD_S.W */
DIP("HADD_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add32x4,
binop(Iop_SarN32x4,
mkexpr(t1), mkU8(16)),
binop(Iop_SarN32x4,
binop(Iop_ShlN32x4,
mkexpr(t2), mkU8(16)),
mkU8(16))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* HADD_S.D */
DIP("HADD_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add64x2,
binop(Iop_SarN64x2,
mkexpr(t1), mkU8(32)),
binop(Iop_SarN64x2,
binop(Iop_ShlN64x2,
mkexpr(t2), mkU8(32)),
mkU8(32))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* HADD_U.df */
switch (df) {
case 0x01: { /* HADD_U.H */
DIP("HADD_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add16x8,
binop(Iop_ShrN16x8,
mkexpr(t1), mkU8(8)),
binop(Iop_ShrN16x8,
binop(Iop_ShlN16x8,
mkexpr(t2), mkU8(8)),
mkU8(8))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* HADD_U.W */
DIP("HADD_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add32x4,
binop(Iop_ShrN32x4,
mkexpr(t1), mkU8(16)),
binop(Iop_ShrN32x4,
binop(Iop_ShlN32x4,
mkexpr(t2), mkU8(16)),
mkU8(16))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* HADD_U.D */
DIP("HADD_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Add64x2,
binop(Iop_ShrN64x2,
mkexpr(t1), mkU8(32)),
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
mkexpr(t2), mkU8(32)),
mkU8(32))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x06: { /* HSUB_S.df */
switch (df) {
case 0x01: { /* HSUB_S.H */
DIP("HSUB_S.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Sub16x8,
binop(Iop_SarN16x8,
mkexpr(t1), mkU8(8)),
binop(Iop_SarN16x8,
binop(Iop_ShlN16x8,
mkexpr(t2), mkU8(8)),
mkU8(8))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* HSUB_S.W */
DIP("HSUB_S.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Sub32x4,
binop(Iop_SarN32x4,
mkexpr(t1), mkU8(16)),
binop(Iop_SarN32x4,
binop(Iop_ShlN32x4,
mkexpr(t2), mkU8(16)),
mkU8(16))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* HSUB_S.D */
DIP("HSUB_S.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Sub64x2,
binop(Iop_SarN64x2,
mkexpr(t1), mkU8(32)),
binop(Iop_SarN64x2,
binop(Iop_ShlN64x2,
mkexpr(t2), mkU8(32)),
mkU8(32))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* HSUB_U.df */
switch (df) {
case 0x01: { /* HSUB_U.H */
DIP("HSUB_U.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Sub16x8,
binop(Iop_ShrN16x8,
mkexpr(t1), mkU8(8)),
binop(Iop_ShrN16x8,
binop(Iop_ShlN16x8,
mkexpr(t2), mkU8(8)),
mkU8(8))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* HSUB_U.W */
DIP("HSUB_U.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Sub32x4,
binop(Iop_ShrN32x4,
mkexpr(t1), mkU8(16)),
binop(Iop_ShrN32x4,
binop(Iop_ShlN32x4,
mkexpr(t2), mkU8(16)),
mkU8(16))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* HSUB_U.D */
DIP("HSUB_U.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_Sub64x2,
binop(Iop_ShrN64x2,
mkexpr(t1), mkU8(32)),
binop(Iop_ShrN64x2,
binop(Iop_ShlN64x2,
mkexpr(t2), mkU8(32)),
mkU8(32))));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_1A(UInt cins, UChar wd, UChar ws) /* 3R (0x1A) */
{
UShort operation;
UChar df, wt;
operation = (cins & 0x03C00000) >> 22;
df = (cins & 0x00200000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* FCAF.df */
switch (df) {
case 0x00: { /* FCAF.W */
DIP("FCAF.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCAFW, 2);
putWReg(wd, binop(Iop_64HLtoV128, mkU64(0ul), mkU64(0ul)));
break;
}
case 0x01: { /* FCAF.D */
DIP("FCAF.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCAFD, 2);
putWReg(wd, binop(Iop_64HLtoV128, mkU64(0ul), mkU64(0ul)));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* FCUN.df */
switch (df) {
case 0x00: { /* FCUN.W */
DIP("FCUN.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCUNW, 2);
putWReg(wd, binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FCUN.D */
DIP("FCUN.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCUND, 2);
putWReg(wd, binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* FCEQ.df */
switch (df) {
case 0x00: { /* FCEQ.W */
DIP("FCEQ.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCEQW, 2);
putWReg(wd, binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FCEQ.D */
DIP("FCEQ.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCEQD, 2);
putWReg(wd, binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* FCUEQ.df */
switch (df) {
case 0x00: { /* FCUEQ.W */
DIP("FCUEQ.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCUEQW, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FCUEQ.D */
DIP("FCUEQ.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCUEQD, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* FCLT.df */
switch (df) {
case 0x00: { /* FCLT.W */
DIP("FCLT.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCLTW, 2);
putWReg(wd,
binop(Iop_CmpLT32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FCLT.D */
DIP("FCLT.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCLTD, 2);
putWReg(wd,
binop(Iop_CmpLT64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* FCULT.df */
switch (df) {
case 0x00: { /* FCULT.W */
DIP("FCULT.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCULTW, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLT32Fx4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FCULT.D */
DIP("FCULT.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCULTD, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLT64Fx2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x06: { /* FCLE.df */
switch (df) {
case 0x00: { /* FCLE.W */
DIP("FCLE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCLEW, 2);
putWReg(wd,
binop(Iop_CmpLE32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FCLE.D */
DIP("FCLE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCLED, 2);
putWReg(wd,
binop(Iop_CmpLE64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* FCULE.df */
switch (df) {
case 0x00: { /* FCULE.W */
DIP("FCULE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCULEW, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLE32Fx4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FCULE.D */
DIP("FCULE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCULED, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLE64Fx2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x08: { /* FSAF.df */
switch (df) {
case 0x00: { /* FSAF.W */
DIP("FSAF.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSAFW, 2);
putWReg(wd,
binop(Iop_64HLtoV128,
mkU64(0ul), mkU64(0ul)));
break;
}
case 0x01: { /* FSAF.D */
DIP("FSAF.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSAFD, 2);
putWReg(wd,
binop(Iop_64HLtoV128,
mkU64(0ul), mkU64(0ul)));
break;
}
default:
return -1;
}
break;
}
case 0x09: { /* FSUN.df */
switch (df) {
case 0x00: { /* FSUN.W */
DIP("FSUN.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUNW, 2);
putWReg(wd,
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FSUN.D */
DIP("FSUN.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUND, 2);
putWReg(wd,
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0A: { /* FSEQ.df */
switch (df) {
case 0x00: { /* FSEQ.W */
DIP("FSEQ.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSEQW, 2);
putWReg(wd,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FSEQ.D */
DIP("FSEQ.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSEQD, 2);
putWReg(wd,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0B: { /* FSUEQ.df */
switch (df) {
case 0x00: { /* FSUEQ.W */
DIP("FSUEQ.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUEQW, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FSUEQ.D */
DIP("FSUEQ.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUEQD, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x0C: { /* FSLT.df */
switch (df) {
case 0x00: { /* FSLT.W */
DIP("FSLT.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSLTW, 2);
putWReg(wd,
binop(Iop_CmpLT32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FSLT.D */
DIP("FSLT.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSLTD, 2);
putWReg(wd,
binop(Iop_CmpLT64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0D: { /* FSULT.df */
switch (df) {
case 0x00: { /* FSULT.W */
DIP("FSULT.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSULTW, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLT32Fx4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FSULT.D */
DIP("FSULT.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSULTD, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLT64Fx2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x0E: { /* FSLE.df */
switch (df) {
case 0x00: { /* FSLE.W */
DIP("FSLE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSLEW, 2);
putWReg(wd,
binop(Iop_CmpLE32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FSLE.D */
DIP("FSLE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSLED, 2);
putWReg(wd,
binop(Iop_CmpLE64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0F: { /* FSULE.df */
switch (df) {
case 0x00: { /* FSULE.W */
DIP("FSULE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSULEW, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLE32Fx4,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FSULE.D */
DIP("FSULE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSULED, 2);
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_CmpLE64Fx2,
getWReg(ws),
getWReg(wt)),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_1B(UInt cins, UChar wd, UChar ws) /* 3R (0x1B) */
{
IRTemp t1, t2, t3, t4;
UShort operation;
UChar df, wt;
operation = (cins & 0x03C00000) >> 22;
df = (cins & 0x00200000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* FADD.df */
switch (df) {
case 0x00: { /* FADD.W */
DIP("FADD.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FADDW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Add32Fx4, rm,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FADD.D */
DIP("FADD.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FADDD, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Add64Fx2, rm,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x01: { /* FSUB.df */
switch (df) {
case 0x00: { /* FSUB.W */
DIP("FSUB.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUBW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Sub32Fx4, rm,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FSUB.D */
DIP("FSUB.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUBD, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Sub64Fx2, rm,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* FMUL.df */
switch (df) {
case 0x00: { /* FMUL.W */
DIP("FMUL.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMULW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Mul32Fx4, rm,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FMUL.D */
DIP("FMUL.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMULW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Mul64Fx2, rm,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* FDIV.df */
switch (df) {
case 0x00: { /* FDIV.W */
DIP("FDIV.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FDIVW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Div32Fx4, rm,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FDIV.D */
DIP("FDIV.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FDIVD, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Div64Fx2, rm,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* FMADD.df */
switch (df) {
case 0x00: { /* FMADD.W */
DIP("FMADD.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMADDW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_F32);
assign(tmp[i],
qop(Iop_MAddF32, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(ws),
mkU8(i))),
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(wt),
mkU8(i))),
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(wd),
mkU8(i)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[3])),
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[2]))),
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[1])),
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[0])))));
break;
}
case 0x01: { /* FMADD.D */
DIP("FMADD.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMADDW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_F64);
assign(tmp[i],
qop(Iop_MAddF64, rm,
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
getWReg(ws),
mkU8(i))),
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
getWReg(wt),
mkU8(i))),
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
getWReg(wd),
mkU8(i)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
unop(Iop_ReinterpF64asI64,
mkexpr(tmp[1])),
unop(Iop_ReinterpF64asI64,
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* FMSUB.df */
switch (df) {
case 0x00: { /* FMSUB.W */
DIP("FMSUB.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMADDW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_F32);
assign(tmp[i],
qop(Iop_MSubF32, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(ws),
mkU8(i))),
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(wt),
mkU8(i))),
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(wd),
mkU8(i)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[3])),
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[2]))),
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[1])),
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[0])))));
break;
}
case 0x01: { /* FMSUB.D */
DIP("FMSUB.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMADDD, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_F64);
assign(tmp[i],
qop(Iop_MSubF64, rm,
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
getWReg(ws),
mkU8(i))),
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
getWReg(wt),
mkU8(i))),
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
getWReg(wd),
mkU8(i)))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
unop(Iop_ReinterpF64asI64,
mkexpr(tmp[1])),
unop(Iop_ReinterpF64asI64,
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
case 0x07: { /* FEXP2.df */
switch (df) {
case 0x00: { /* FEXP2.W */
DIP("FEXP2.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FEXP2W, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Scale2_32Fx4, rm,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FEXP2.D */
DIP("FEXP2.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FEXP2D, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_Scale2_64Fx2, rm,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x08: { /* FEXDO.df */
switch (df) {
case 0x00: { /* FEXDO.H */
DIP("FEXDO.H w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FEXDOH, 2);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
assign(t1,
unop(Iop_F32toF16x4_DEP,
getWReg(ws)));
assign(t2,
unop(Iop_F32toF16x4_DEP,
getWReg(wt)));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t1), mkexpr(t2)));
break;
}
case 0x01: { /* FEXDO.W */
DIP("FEXDO.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FEXDOW, 2);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
unop(Iop_ReinterpF32asI32,
binop(Iop_F64toF32, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128to64,
getWReg(ws))))));
assign(t2,
unop(Iop_ReinterpF32asI32,
binop(Iop_F64toF32, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128HIto64,
getWReg(ws))))));
assign(t3,
unop(Iop_ReinterpF32asI32,
binop(Iop_F64toF32, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128to64,
getWReg(wt))))));
assign(t4,
unop(Iop_ReinterpF32asI32,
binop(Iop_F64toF32, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128HIto64,
getWReg(wt))))));
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(t2), mkexpr(t1)),
binop(Iop_32HLto64,
mkexpr(t4), mkexpr(t3))));
break;
}
default:
return -1;
}
break;
}
case 0x0A: { /* FTQ.df */
switch (df) {
case 0x00: { /* FTQ.H */
DIP("FTQ.H w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FTQH, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_F32x4_2toQ16x8, rm,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FTQ.W */
DIP("FTQ.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FTQW, 2);
IRExpr *rm = get_IR_roundingmode_MSA();
putWReg(wd,
triop(Iop_F64x2_2toQ32x4, rm,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0C: { /* FMIN.df */
switch (df) {
case 0x00: { /* FMIN.W */
DIP("FMIN.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMINW, 2);
putWReg(wd,
binop(Iop_Min32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FMIN.D */
DIP("FMIN.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMINW, 2);
putWReg(wd,
binop(Iop_Min64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0D: { /* FMIN_A.df */
switch (df) {
case 0x00: { /* FMIN_A.W */
DIP("FMIN_A.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMINAW, 2);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFF7FFFFFFF),
mkU64(0x7FFFFFFF7FFFFFFF))));
assign(t2,
binop(Iop_AndV128,
getWReg(wt),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFF7FFFFFFF),
mkU64(0x7FFFFFFF7FFFFFFF))));
assign(t3,
binop(Iop_Min32Fx4,
mkexpr(t2), mkexpr(t1)));
assign(t4,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN32Fx4,
mkexpr(t3),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ32Fx4,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_OrV128,
getWReg(ws),
getWReg(wt))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN32Fx4,
mkexpr(t1),
mkexpr(t1)),
binop(Iop_CmpLT32Fx4,
mkexpr(t3),
mkexpr(t1))),
getWReg(wt)),
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN32Fx4,
mkexpr(t2),
mkexpr(t2)),
binop(Iop_CmpLT32Fx4,
mkexpr(t3),
mkexpr(t2))),
getWReg(ws))))),
binop(Iop_64HLtoV128,
mkU64(0x8000000080000000),
mkU64(0x8000000080000000))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3), mkexpr(t4)));
break;
}
case 0x01: { /* FMIN_A.D */
DIP("FMIN_A.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMINAD, 2);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFFFFFFFFFF),
mkU64(0x7FFFFFFFFFFFFFFF))));
assign(t2,
binop(Iop_AndV128,
getWReg(wt),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFFFFFFFFFF),
mkU64(0x7FFFFFFFFFFFFFFF))));
assign(t3,
binop(Iop_Min64Fx2,
mkexpr(t2), mkexpr(t1)));
assign(t4,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN64Fx2,
mkexpr(t3),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ64Fx2,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_OrV128,
getWReg(ws),
getWReg(wt))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN64Fx2,
mkexpr(t1),
mkexpr(t1)),
binop(Iop_CmpLT64Fx2,
mkexpr(t3),
mkexpr(t1))),
getWReg(wt)),
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN64Fx2,
mkexpr(t2),
mkexpr(t2)),
binop(Iop_CmpLT64Fx2,
mkexpr(t3),
mkexpr(t2))),
getWReg(ws))))),
binop(Iop_64HLtoV128,
mkU64(0x8000000000000000),
mkU64(0x8000000000000000))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3), mkexpr(t4)));
break;
}
default:
return -1;
}
break;
}
case 0x0E: { /* FMAX.df */
switch (df) {
case 0x00: { /* FMAX.W */
DIP("FMAX.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMAXW, 2);
putWReg(wd,
binop(Iop_Max32Fx4,
getWReg(ws),
getWReg(wt)));
break;
}
case 0x01: { /* FMAX.D */
DIP("FMAX.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMAXW, 2);
putWReg(wd,
binop(Iop_Max64Fx2,
getWReg(ws),
getWReg(wt)));
break;
}
default:
return -1;
}
break;
}
case 0x0F: { /* FMAX_A.df */
switch (df) {
case 0x00: { /* FMAX_A.W */
DIP("FMAX_A.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMAXAW, 2);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFF7FFFFFFF),
mkU64(0x7FFFFFFF7FFFFFFF))));
assign(t2,
binop(Iop_AndV128,
getWReg(wt),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFF7FFFFFFF),
mkU64(0x7FFFFFFF7FFFFFFF))));
assign(t3,
binop(Iop_Max32Fx4,
mkexpr(t2), mkexpr(t1)));
assign(t4,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN32Fx4,
mkexpr(t3),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ32Fx4,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_AndV128,
getWReg(ws),
getWReg(wt))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN32Fx4,
mkexpr(t1),
mkexpr(t1)),
binop(Iop_CmpLT32Fx4,
mkexpr(t1),
mkexpr(t3))),
getWReg(wt)),
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN32Fx4,
mkexpr(t2),
mkexpr(t2)),
binop(Iop_CmpLT32Fx4,
mkexpr(t2),
mkexpr(t3))),
getWReg(ws))))),
binop(Iop_64HLtoV128,
mkU64(0x8000000080000000),
mkU64(0x8000000080000000))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3), mkexpr(t4)));
break;
}
case 0x01: { /* FMAX_A.D */
DIP("FMAX_A.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FMAXAD, 2);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFFFFFFFFFF),
mkU64(0x7FFFFFFFFFFFFFFF))));
assign(t2,
binop(Iop_AndV128,
getWReg(wt),
binop(Iop_64HLtoV128,
mkU64(0x7FFFFFFFFFFFFFFF),
mkU64(0x7FFFFFFFFFFFFFFF))));
assign(t3,
binop(Iop_Max64Fx2,
mkexpr(t2), mkexpr(t1)));
assign(t4,
binop(Iop_AndV128,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN64Fx2,
mkexpr(t3),
mkexpr(t3))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_CmpEQ64Fx2,
mkexpr(t1),
mkexpr(t2)),
binop(Iop_AndV128,
getWReg(ws),
getWReg(wt))),
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN64Fx2,
mkexpr(t1),
mkexpr(t1)),
binop(Iop_CmpLT64Fx2,
mkexpr(t1),
mkexpr(t3))),
getWReg(wt)),
binop(Iop_AndV128,
binop(Iop_OrV128,
binop(Iop_CmpUN64Fx2,
mkexpr(t2),
mkexpr(t2)),
binop(Iop_CmpLT64Fx2,
mkexpr(t2),
mkexpr(t3))),
getWReg(ws))))),
binop(Iop_64HLtoV128,
mkU64(0x8000000000000000),
mkU64(0x8000000000000000))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t3), mkexpr(t4)));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_3R_1C(UInt cins, UChar wd, UChar ws) /* 3R (0x1C) */
{
IRTemp t1, t2, t3, t4, t5, t6;
UShort operation;
UChar df, wt;
operation = (cins & 0x03C00000) >> 22;
df = (cins & 0x00200000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x01: { /* FCOR.df */
switch (df) {
case 0x00: { /* FCOR.W */
DIP("FCOR.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCORW, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FCOR.D */
DIP("FCOR.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCORD, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x02: { /* FCUNE.df */
switch (df) {
case 0x00: { /* FCUNE.W */
DIP("FCUNE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCUNEW, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FCUNE.D */
DIP("FCUNE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCUNED, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x03: { /* FCNE.df */
switch (df) {
case 0x00: { /* FCNE.W */
DIP("FCNE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCNEW, 2);
putWReg(wd,
binop(Iop_XorV128,
unop(Iop_NotV128,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt))),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FCNE.D */
DIP("FCNE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FCNED, 2);
putWReg(wd,
binop(Iop_XorV128,
unop(Iop_NotV128,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt))),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x04: { /* MUL_Q.df */
switch (df) {
case 0x00: { /* MUL_Q.H */
DIP("MUL_Q.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_QDMulHi16Sx8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MUL_Q.W */
DIP("MUL_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
binop(Iop_QDMulHi32Sx4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x05: { /* MADD_Q.df */
switch (df) {
case 0x00: { /* MADD_Q.W */
DIP("MADD_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(ws),
getWReg(ws)),
mkU8(16)));
assign(t2, // odd
binop(Iop_SarN32x4,
getWReg(ws), mkU8(16)));
assign(t3, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wt),
getWReg(wt)),
mkU8(16)));
assign(t4, // odd
binop(Iop_SarN32x4,
getWReg(wt), mkU8(16)));
assign(t5,
binop(Iop_Add32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wd),
getWReg(wd)),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t1), mkexpr(t3))));
assign(t6,
binop(Iop_Add32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
getWReg(wd),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t2), mkexpr(t4))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes16x8,
binop(Iop_QandQSarNnarrow32Sto16Sx4,
mkexpr(t6), mkU8(15)),
binop(Iop_QandQSarNnarrow32Sto16Sx4,
mkexpr(t5), mkU8(15))));
break;
}
case 0x01: { /* MADD_Q.W */
DIP("MADD_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(ws),
getWReg(ws)),
mkU8(32)));
assign(t2, // odd
binop(Iop_SarN64x2,
getWReg(ws), mkU8(32)));
assign(t3, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wt),
getWReg(wt)),
mkU8(32)));
assign(t4, // odd
binop(Iop_SarN64x2,
getWReg(wt), mkU8(32)));
assign(t5,
binop(Iop_Add64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wd),
getWReg(wd)),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t3))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t3))))));
assign(t6,
binop(Iop_Add64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
getWReg(wd),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t2)),
unop(Iop_V128HIto64,
mkexpr(t4))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t2)),
unop(Iop_V128to64,
mkexpr(t4))))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes32x4,
binop(Iop_QandQSarNnarrow64Sto32Sx2,
mkexpr(t6), mkU8(31)),
binop(Iop_QandQSarNnarrow64Sto32Sx2,
mkexpr(t5), mkU8(31))));
break;
}
default:
return -1;
}
break;
}
case 0x06: { /* MSUB_Q.df */
switch (df) {
case 0x00: { /* MSUB_Q.H */
DIP("MSUB_Q.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(ws),
getWReg(ws)),
mkU8(16)));
assign(t2, // odd
binop(Iop_SarN32x4,
getWReg(ws), mkU8(16)));
assign(t3, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wt),
getWReg(wt)),
mkU8(16)));
assign(t4, // odd
binop(Iop_SarN32x4,
getWReg(wt), mkU8(16)));
assign(t5,
binop(Iop_Sub32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wd),
getWReg(wd)),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t1), mkexpr(t3))));
assign(t6,
binop(Iop_Sub32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
getWReg(wd),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t2), mkexpr(t4))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes16x8,
binop(Iop_QandQSarNnarrow32Sto16Sx4,
mkexpr(t6), mkU8(15)),
binop(Iop_QandQSarNnarrow32Sto16Sx4,
mkexpr(t5), mkU8(15))));
break;
}
case 0x01: { /* MSUB_Q.W */
DIP("MSUB_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(ws),
getWReg(ws)),
mkU8(32)));
assign(t2, // odd
binop(Iop_SarN64x2,
getWReg(ws), mkU8(32)));
assign(t3, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wt),
getWReg(wt)),
mkU8(32)));
assign(t4, // odd
binop(Iop_SarN64x2,
getWReg(wt), mkU8(32)));
assign(t5,
binop(Iop_Sub64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wd),
getWReg(wd)),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t3))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t3))))));
assign(t6,
binop(Iop_Sub64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
getWReg(wd),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t2)),
unop(Iop_V128HIto64,
mkexpr(t4))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t2)),
unop(Iop_V128to64,
mkexpr(t4))))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes32x4,
binop(Iop_QandQSarNnarrow64Sto32Sx2,
mkexpr(t6), mkU8(31)),
binop(Iop_QandQSarNnarrow64Sto32Sx2,
mkexpr(t5), mkU8(31))));
break;
}
default:
return -1;
}
break;
}
case 0x09: { /* FSOR.df */
switch (df) {
case 0x00: { /* FSOR.W */
DIP("FSOR.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSORW, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FSOR.D */
DIP("FSOR.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSORD, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x0A: { /* FSUNE.df */
switch (df) {
case 0x00: { /* FSUNE.W */
DIP("FSUNE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUNEW, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FSUNE.D */
DIP("FSUNE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSUNED, 2);
putWReg(wd,
unop(Iop_NotV128,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x0B: { /* FSNE.df */
switch (df) {
case 0x00: { /* FSNE.W */
DIP("FSNE.W w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSNEW, 2);
putWReg(wd,
binop(Iop_XorV128,
unop(Iop_NotV128,
binop(Iop_CmpEQ32Fx4,
getWReg(ws),
getWReg(wt))),
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(wt))));
break;
}
case 0x01: { /* FSNE.D */
DIP("FSNE.D w%d, w%d, w%d", wd, ws, wt);
calculateMSACSR(ws, wt, FSNED, 2);
putWReg(wd,
binop(Iop_XorV128,
unop(Iop_NotV128,
binop(Iop_CmpEQ64Fx2,
getWReg(ws),
getWReg(wt))),
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(wt))));
break;
}
default:
return -1;
}
break;
}
case 0x0C: { /* MULR_Q.df */
switch (df) {
case 0x00: { /* MULR_Q.H */
DIP("MULR_Q.H w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QRDMulHi16Sx8,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* MULR_Q.W */
DIP("MULR_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_QRDMulHi32Sx4,
mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
break;
}
case 0x0D: { /* MADDR_Q.df */
switch (df) {
case 0x00: { /* MADDR_Q.W */
DIP("MADDR_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(ws),
getWReg(ws)),
mkU8(16)));
assign(t2, // odd
binop(Iop_SarN32x4,
getWReg(ws), mkU8(16)));
assign(t3, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wt),
getWReg(wt)),
mkU8(16)));
assign(t4, // odd
binop(Iop_SarN32x4,
getWReg(wt), mkU8(16)));
assign(t5,
binop(Iop_Add32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wd),
getWReg(wd)),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t1), mkexpr(t3))));
assign(t6,
binop(Iop_Add32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
getWReg(wd),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t2), mkexpr(t4))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes16x8,
binop(Iop_QandQRSarNnarrow32Sto16Sx4,
mkexpr(t6), mkU8(15)),
binop(Iop_QandQRSarNnarrow32Sto16Sx4,
mkexpr(t5), mkU8(15))));
break;
}
case 0x01: { /* MADDR_Q.D */
DIP("MADDR_Q.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(ws),
getWReg(ws)),
mkU8(32)));
assign(t2, // odd
binop(Iop_SarN64x2,
getWReg(ws), mkU8(32)));
assign(t3, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wt),
getWReg(wt)),
mkU8(32)));
assign(t4, // odd
binop(Iop_SarN64x2,
getWReg(wt), mkU8(32)));
assign(t5,
binop(Iop_Add64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wd),
getWReg(wd)),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t3))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t3))))));
assign(t6,
binop(Iop_Add64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
getWReg(wd),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t2)),
unop(Iop_V128HIto64,
mkexpr(t4))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t2)),
unop(Iop_V128to64,
mkexpr(t4))))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes32x4,
binop(Iop_QandQRSarNnarrow64Sto32Sx2,
mkexpr(t6), mkU8(31)),
binop(Iop_QandQRSarNnarrow64Sto32Sx2,
mkexpr(t5), mkU8(31))));
break;
}
default:
return -1;
}
break;
}
case 0x0E: { /* MSUBR_Q.df */
switch (df) {
case 0x00: { /* MSUBR_Q.W */
DIP("MSUBR_Q.W w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(ws),
getWReg(ws)),
mkU8(16)));
assign(t2, // odd
binop(Iop_SarN32x4,
getWReg(ws), mkU8(16)));
assign(t3, // even
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wt),
getWReg(wt)),
mkU8(16)));
assign(t4, // odd
binop(Iop_SarN32x4,
getWReg(wt), mkU8(16)));
assign(t5,
binop(Iop_Sub32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(wd),
getWReg(wd)),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t1), mkexpr(t3))));
assign(t6,
binop(Iop_Sub32x4,
binop(Iop_ShlN32x4,
binop(Iop_SarN32x4,
getWReg(wd),
mkU8(16)),
mkU8(15)),
binop(Iop_Mul32x4,
mkexpr(t2), mkexpr(t4))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes16x8,
binop(Iop_QandQRSarNnarrow32Sto16Sx4,
mkexpr(t6), mkU8(15)),
binop(Iop_QandQRSarNnarrow32Sto16Sx4,
mkexpr(t5), mkU8(15))));
break;
}
case 0x01: { /* MSUBR_Q.D */
DIP("MSUBR_Q.D w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
t6 = newTemp(Ity_V128);
assign(t1, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(ws),
getWReg(ws)),
mkU8(32)));
assign(t2, // odd
binop(Iop_SarN64x2,
getWReg(ws), mkU8(32)));
assign(t3, // even
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wt),
getWReg(wt)),
mkU8(32)));
assign(t4, // odd
binop(Iop_SarN64x2,
getWReg(wt), mkU8(32)));
assign(t5,
binop(Iop_Sub64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
binop(Iop_InterleaveEvenLanes32x4,
getWReg(wd),
getWReg(wd)),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t1)),
unop(Iop_V128HIto64,
mkexpr(t3))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t1)),
unop(Iop_V128to64,
mkexpr(t3))))));
assign(t6,
binop(Iop_Sub64x2,
binop(Iop_ShlN64x2,
binop(Iop_SarN64x2,
getWReg(wd),
mkU8(32)),
mkU8(31)),
binop(Iop_64HLtoV128,
binop(Iop_Mul64,
unop(Iop_V128HIto64,
mkexpr(t2)),
unop(Iop_V128HIto64,
mkexpr(t4))),
binop(Iop_Mul64,
unop(Iop_V128to64,
mkexpr(t2)),
unop(Iop_V128to64,
mkexpr(t4))))));
putWReg(wd,
binop(Iop_InterleaveEvenLanes32x4,
binop(Iop_QandQRSarNnarrow64Sto32Sx2,
mkexpr(t6), mkU8(31)),
binop(Iop_QandQRSarNnarrow64Sto32Sx2,
mkexpr(t5), mkU8(31))));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_ELM(UInt cins, UChar wd, UChar ws) /* ELM (0x19) */
{
IRTemp t1, t2, t3, t4, t5;
IRType ty;
UShort operation;
UChar df, n;
operation = (cins & 0x03C00000) >> 22;
ty = mode64 ? Ity_I64 : Ity_I32;
switch ((cins & 0x03FF0000) >> 16) {
case 0x07E: /* CFCMSA */
DIP("CFCMSA r%d, c%d", wd, ws);
switch (ws) {
case 0: { /* MSAIR */
IRDirty *d;
t1 = newTemp(Ity_I32);
/* IRExpr_BBPTR() =>
Need to pass pointer to
guest state to helper. */
d = unsafeIRDirty_1_N(t1, 0,
"mips_dirtyhelper_get_MSAIR",
&mips_dirtyhelper_get_MSAIR,
mkIRExprVec_0());
/* d->nFxState = 0; */
stmt(IRStmt_Dirty(d));
putIReg(wd,
mkWidenFrom32(ty, mkexpr(t1), True));
break;
}
case 1: /* MSACSR */
putIReg(wd,
mkWidenFrom32(ty, getMSACSR(), True));
break;
default:
putIReg(wd,
mkWidenFrom32(ty, mkU32(0), False));
break;
}
break;
case 0x03E: /* CTCMSA */
DIP("CTCMSA r%d, c%d", ws, wd);
if (wd == 1) { /* MSACSR */
putMSACSR(
binop(Iop_And32, mkNarrowTo32(ty, getIReg(ws)),
mkU32(0x1FFFFFF)));
}
break;
case 0x0BE: /* MOVE.V */
DIP("MOVE.V w%d, w%d", ws, wd);
putWReg(wd, getWReg(ws));
break;
default:
df = (cins & 0x003F0000) >> 16;
if ((df & 0x38) == 0x38) { // 11100n; dw
n = df & 0x01;
df = 0x38;
} else if ((df & 0x30) == 0x30) { // 1100nn; w
n = df & 0x03;
df = 0x30;
} else if ((df & 0x20) == 0x20) { // 100nnn; hw
n = df & 0x07;
df = 0x20;
} else if ((df & 0x00) == 0x00) { // 00nnnn; b
n = df & 0x0F;
df = 0x00;
}
switch (operation) {
case 0x00: /* SLDI.df */
switch (df) {
case 0x00: /* SLDI.B */
DIP("SLDI.B w%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrV128,
getWReg(ws),
mkU8(n << 3)));
assign(t2,
binop(Iop_ShlV128,
getWReg(wd),
mkU8(n ?
(16 - n) << 3 : 0)));
putWReg(wd,
binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
break;
case 0x20: /* SLDI.H */
DIP("SLDI.H w%d, w%d[%d]", wd, ws, n);
if (n == 0) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN64x2,
getWReg(ws),
mkU8(n << 3)));
assign(t2,
binop(Iop_ShlN64x2,
getWReg(wd),
mkU8((8 - n) << 3)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t1),
mkexpr(t2)));
}
break;
case 0x30: /* SLDI.W */
DIP("SLDI.W w%d, w%d[%d]", wd, ws, n);
if (n == 0) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN32x4,
getWReg(ws),
mkU8(n << 3)));
assign(t2,
binop(Iop_ShlN32x4,
getWReg(wd),
mkU8((4 - n) << 3)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t1),
mkexpr(t2)));
}
break;
case 0x38: /* SLDI.D */
DIP("SLDI.D w%d, w%d[%d]", wd, ws, n);
if (n == 0) {
putWReg(wd, getWReg(ws));
} else {
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1,
binop(Iop_ShrN16x8,
getWReg(ws),
mkU8(n << 3)));
assign(t2,
binop(Iop_ShlN16x8,
getWReg(wd),
mkU8((2 - n) << 3)));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t1),
mkexpr(t2)));
}
break;
default:
return -1;
}
break;
case 0x01: /* SPLATI.df */
switch (df) {
case 0x00: { /* SPLATI.B */
DIP("SPLATI.B w%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
if (n & 1)
assign(t1,
binop(Iop_InterleaveOddLanes8x16,
getWReg(ws),
getWReg(ws)));
else
assign(t1,
binop(Iop_InterleaveEvenLanes8x16,
getWReg(ws),
getWReg(ws)));
n /= 2;
if (n & 1)
assign(t2,
binop(Iop_InterleaveOddLanes16x8,
mkexpr(t1), mkexpr(t1)));
else
assign(t2,
binop(Iop_InterleaveEvenLanes16x8,
mkexpr(t1), mkexpr(t1)));
n /= 2;
if (n & 1)
assign(t3,
binop(Iop_InterleaveOddLanes32x4,
mkexpr(t2), mkexpr(t2)));
else
assign(t3,
binop(Iop_InterleaveEvenLanes32x4,
mkexpr(t2), mkexpr(t2)));
n /= 2;
if (n & 1)
assign(t4,
binop(Iop_InterleaveHI64x2,
mkexpr(t3), mkexpr(t3)));
else
assign(t4,
binop(Iop_InterleaveLO64x2,
mkexpr(t3), mkexpr(t3)));
putWReg(wd, mkexpr(t4));
break;
}
case 0x20: { /* SPLATI.H */
DIP("SPLATI.H w%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
if (n & 1)
assign(t1,
binop(Iop_InterleaveOddLanes16x8,
getWReg(ws),
getWReg(ws)));
else
assign(t1,
binop(Iop_InterleaveEvenLanes16x8,
getWReg(ws),
getWReg(ws)));
n /= 2;
if (n & 1)
assign(t2,
binop(Iop_InterleaveOddLanes32x4,
mkexpr(t1), mkexpr(t1)));
else
assign(t2,
binop(Iop_InterleaveEvenLanes32x4,
mkexpr(t1), mkexpr(t1)));
n /= 2;
if (n & 1)
assign(t3,
binop(Iop_InterleaveHI64x2,
mkexpr(t2), mkexpr(t2)));
else
assign(t3,
binop(Iop_InterleaveLO64x2,
mkexpr(t2), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x30: { /* SPLATI.W */
DIP("SPLATI.W w%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
if (n & 1)
assign(t2,
binop(Iop_InterleaveOddLanes32x4,
mkexpr(t1), mkexpr(t1)));
else
assign(t2,
binop(Iop_InterleaveEvenLanes32x4,
mkexpr(t1), mkexpr(t1)));
n /= 2;
if (n & 1)
assign(t3,
binop(Iop_InterleaveHI64x2,
mkexpr(t2), mkexpr(t2)));
else
assign(t3,
binop(Iop_InterleaveLO64x2,
mkexpr(t2), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x38: /* SPLATI.D */
DIP("SPLATI.D w%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
if (n)
assign(t3,
binop(Iop_InterleaveHI64x2,
mkexpr(t1), mkexpr(t1)));
else
assign(t3,
binop(Iop_InterleaveLO64x2,
mkexpr(t1), mkexpr(t1)));
putWReg(wd, mkexpr(t3));
break;
default:
return -1;
}
break;
case 0x02: /* COPY_S.df */
switch (df) {
case 0x00: /* COPY_S.B */
DIP("COPY_S.B r%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_I8);
switch (n) {
case 0:
assign(t1,
unop(Iop_32to8,
unop(Iop_V128to32,
getWReg(ws))));
break;
case 1:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_V128to32,
getWReg(ws)))));
break;
case 2:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 3:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 4:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 5:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 6:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 7:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 8:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 9:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 10:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 11:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 12:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 13:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 14:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 15:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
}
putIReg(wd,
unop(mode64 ? Iop_8Sto64 : Iop_8Sto32,
mkexpr(t1)));
break;
case 0x20: /* COPY_S.H */
DIP("COPY_S.H r%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_I16);
switch (n) {
case 0:
assign(t1,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 1:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 2:
assign(t1,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 3:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 4:
assign(t1,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
case 5:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
case 6:
assign(t1,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
case 7:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
}
putIReg(wd,
unop(mode64 ? Iop_16Sto64 : Iop_16Sto32,
mkexpr(t1)));
break;
case 0x30: /* COPY_S.W */
DIP("COPY_S.W r%d, w%d[%d]", wd, ws, n);
switch (n) {
case 0:
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_V128to32,
getWReg(ws)),
True));
break;
case 1:
t2 = newTemp(Ity_I64);
assign(t2,
unop(Iop_V128to64, getWReg(ws)));
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_64HIto32,
mkexpr(t2)),
True));
break;
case 2:
t2 = newTemp(Ity_I64);
assign(t2,
unop(Iop_V128HIto64,
getWReg(ws)));
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_64to32,
mkexpr(t2)),
True));
break;
case 3:
t2 = newTemp(Ity_I64);
assign(t2,
unop(Iop_V128HIto64,
getWReg(ws)));
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_64HIto32,
mkexpr(t2)),
True));
break;
default:
break;
}
break;
case 0x38: /* COPY_S.D */
if (mode64) {
DIP("COPY_S.D r%d, w%d[%d]", wd, ws, n);
switch (n) {
case 0:
putIReg(wd,
unop(Iop_V128to64,
getWReg(ws)));
break;
case 1:
putIReg(wd,
unop(Iop_V128HIto64,
getWReg(ws)));
break;
}
} else {
return -2;
}
break;
default:
return -1;
}
break;
case 0x03: { /* COPY_U.df */
switch (df) {
case 0x00: /* COPY_U.B */
DIP("COPY_U.B r%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_I8);
switch (n) {
case 0:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 1:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 2:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 3:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 4:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 5:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 6:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 7:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws))))));
break;
case 8:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 9:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 10:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 11:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 12:
assign(t1,
unop(Iop_16to8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 13:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 14:
assign(t1,
unop(Iop_16to8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
case 15:
assign(t1,
unop(Iop_16HIto8,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws))))));
break;
}
putIReg(wd,
unop(mode64 ? Iop_8Uto64 : Iop_8Uto32,
mkexpr(t1)));
break;
case 0x20: /* COPY_U.H */
DIP("COPY_U.H r%d, w%d[%d]", wd, ws, n);
t1 = newTemp(Ity_I16);
switch (n) {
case 0:
assign(t1,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 1:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 2:
assign(t1,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 3:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws)))));
break;
case 4:
assign(t1,
unop(Iop_32to16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
case 5:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
case 6:
assign(t1,
unop(Iop_32to16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
case 7:
assign(t1,
unop(Iop_32HIto16,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws)))));
break;
}
putIReg(wd,
unop(mode64 ? Iop_16Uto64 : Iop_16Uto32,
mkexpr(t1)));
break;
case 0x30: /* COPY_U.W */
DIP("COPY_U.W r%d, w%d[%d]", wd, ws, n);
switch (n) {
case 0:
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_V128to32,
getWReg(ws)),
False));
break;
case 1:
t2 = newTemp(Ity_I64);
assign(t2,
unop(Iop_V128to64,
getWReg(ws)));
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_64HIto32,
mkexpr(t2)),
False));
break;
case 2:
t2 = newTemp(Ity_I64);
assign(t2,
unop(Iop_V128HIto64,
getWReg(ws)));
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_64to32,
mkexpr(t2)),
False));
break;
case 3:
t2 = newTemp(Ity_I64);
assign(t2,
unop(Iop_V128HIto64,
getWReg(ws)));
putIReg(wd,
mkWidenFrom32(ty,
unop(Iop_64HIto32,
mkexpr(t2)),
False));
break;
default:
break;
}
break;
default:
return -1;
}
break;
}
case 0x04: { /* INSERT.df */
t5 = newTemp(Ity_I64);
UInt hi = 1;
ULong mask;
IRTemp *src, *dst;
assign(t5, mode64 ? getIReg(ws) :
unop(Iop_32Uto64, getIReg(ws)));
if (df == 0x38) { /* INSERT.D */
if (mode64) {
DIP("INSERT.D w%d[%d], r%d", wd, n, ws);
if (n == 0) {
putWReg(wd,
binop(Iop_64HLtoV128,
unop(Iop_V128HIto64,
getWReg(wd)),
mkexpr(t5)));
} else {
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t5),
unop(Iop_V128to64,
getWReg(wd))));
}
break;
} else {
return -2;
}
} else {
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
assign(t1, unop(Iop_V128to64, getWReg(wd)));
assign(t2, unop(Iop_V128HIto64, getWReg(wd)));
}
switch (df) {
case 0x00: /* INSERT.B */
DIP("INSERT.B w%d[%d], r%d", wd, n, ws);
if (n >= 8) {
n -= 8;
} else {
hi = 0;
}
n <<= 3;
mask = 0xFFull;
break;
case 0x20: /* INSERT.H */
DIP("INSERT.H w%d[%d], r%d", wd, n, ws);
if (n >= 4) {
n -= 4;
} else {
hi = 0;
}
n <<= 4;
mask = 0xFFFFull;
break;
case 0x30: /* INSERT.W */
DIP("INSERT.W w%d[%d], r%d", wd, n, ws);
if (n >= 2) {
n -= 2;
} else {
hi = 0;
}
n <<= 5;
mask = 0xFFFFFFFFull;
break;
default:
return -1;
}
if (hi) {
t4 = newTemp(Ity_I64);
src = &t2;
dst = &t4;
t3 = t1;
} else {
t3 = newTemp(Ity_I64);
src = &t1;
dst = &t3;
t4 = t2;
}
mask <<= n;
assign(*dst,
binop(Iop_Or64,
binop(Iop_And64, mkexpr(*src), mkU64(~mask)),
binop(Iop_And64,
binop(Iop_Shl64, mkexpr(t5), mkU8(n)),
mkU64(mask))));
putWReg(wd,
binop(Iop_64HLtoV128, mkexpr(t4), mkexpr(t3)));
break;
}
case 0x05: { /* INSVE.df */
switch (df) {
case 0x00: { /* INSVE.B */
DIP("INSVE.B w%d[%d], w%d[0]", wd, n, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[16];
for (i = 0; i < 16; i++) {
tmp[i] = newTemp(Ity_I8);
if (n == i)
assign(tmp[i],
binop(Iop_GetElem8x16,
mkexpr(t2), mkU8(0x0)));
else
assign(tmp[i],
binop(Iop_GetElem8x16,
mkexpr(t1), mkU8(i)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[15]),
mkexpr(tmp[14])),
binop(Iop_8HLto16,
mkexpr(tmp[13]),
mkexpr(tmp[12]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[11]),
mkexpr(tmp[10])),
binop(Iop_8HLto16,
mkexpr(tmp[9]),
mkexpr(tmp[8])))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_8HLto16,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_16HLto32,
binop(Iop_8HLto16,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_8HLto16,
mkexpr(tmp[1]),
mkexpr(tmp[0]))))));
break;
}
case 0x20: { /* INSVE.H */
DIP("INSVE.H w%d[%d], r%d[0]", wd, n, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[8];
for (i = 0; i < 8; i++) {
tmp[i] = newTemp(Ity_I16);
if (n == i)
assign(tmp[i],
binop(Iop_GetElem16x8,
mkexpr(t2), mkU8(0x0)));
else
assign(tmp[i],
binop(Iop_GetElem16x8,
mkexpr(t1), mkU8(i)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[7]),
mkexpr(tmp[6])),
binop(Iop_16HLto32,
mkexpr(tmp[5]),
mkexpr(tmp[4]))),
binop(Iop_32HLto64,
binop(Iop_16HLto32,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_16HLto32,
mkexpr(tmp[1]),
mkexpr(tmp[0])))));
break;
}
case 0x30: { /* INSVE.W */
DIP("INSVE.W w%d[%d], r%d[0]", wd, n, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[4];
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
if (n == i)
assign(tmp[i],
binop(Iop_GetElem32x4,
mkexpr(t2), mkU8(0x0)));
else
assign(tmp[i],
binop(Iop_GetElem32x4,
mkexpr(t1), mkU8(i)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))));
break;
}
case 0x38: { /* INSVE.D */
DIP("INSVE.D w%d[%d], r%d[0]", wd, n, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, getWReg(wd));
assign(t2, getWReg(ws));
Int i;
IRTemp tmp[2];
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
if (n == i)
assign(tmp[i],
binop(Iop_GetElem64x2,
mkexpr(t2), mkU8(0x0)));
else
assign(tmp[i],
binop(Iop_GetElem64x2,
mkexpr(t1), mkU8(i)));
}
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(tmp[1]), mkexpr(tmp[0])));
break;
}
}
break;
}
default:
return -1;
}
}
return 0;
}
static Int msa_VEC(UInt cins, UChar wd, UChar ws) /* VEC */
{
IRTemp t1, t2, t3;
UShort operation;
UChar wt;
vassert((cins & 0x03000000) == 0);
operation = (cins & 0x03E00000) >> 21;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x00: { /* AND.V */
DIP("AND.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_AndV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x01: { /* OR.V */
DIP("OR.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x02: { /* NOR.V */
DIP("NOR.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3,
unop(Iop_NotV128,
binop(Iop_OrV128, mkexpr(t1), mkexpr(t2))));
putWReg(wd, mkexpr(t3));
break;
}
case 0x03: { /* XOR.V */
DIP("XOR.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
assign(t2, getWReg(wt));
assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x04: { /* BMNZ (ws AND wt) OR (wd AND NOT wt) */
DIP("BMNZ.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(ws), getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
getWReg(wd),
unop(Iop_NotV128, getWReg(wt))));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x05: { /* BMZ.V (ws AND NOT wt) OR (wd AND wt) */
DIP("BMZ.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(wd), getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
getWReg(ws),
unop(Iop_NotV128, getWReg(wt))));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
case 0x06: { /* BSEL (ws AND NOT wd) OR (wt AND wd) */
DIP("BSEL.V w%d, w%d, w%d", wd, ws, wt);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1,
binop(Iop_AndV128,
getWReg(wd), getWReg(wt)));
assign(t2,
binop(Iop_AndV128,
getWReg(ws),
unop(Iop_NotV128, getWReg(wd))));
assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2)));
putWReg(wd, mkexpr(t3));
break;
}
default:
return -1;
}
return 0;
}
static Int msa_2R(UInt cins, UChar wd, UChar ws) /* 2R */
{
IRTemp t1, t2, t3, t4;
IRType ty;
UShort operation;
UChar df;
vassert((cins & 0x00200000) == 0);
operation = (cins & 0x03FC0000) >> 18;
df = (cins & 0x00030000) >> 16;
ty = mode64 ? Ity_I64 : Ity_I32;
switch (operation) {
case 0xC0: { /* FILL.df */
t1 = newTemp(Ity_I64);
switch (df) {
case 0x00: /* FILL.B */
DIP("FILL.B w%d, r%d", wd, ws);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I16);
t4 = newTemp(Ity_I8);
assign(t4, mkNarrowTo8(ty, getIReg(ws)));
assign(t3,
binop(Iop_8HLto16, mkexpr(t4), mkexpr(t4)));
assign(t2,
binop(Iop_16HLto32, mkexpr(t3), mkexpr(t3)));
assign(t1,
binop(Iop_32HLto64, mkexpr(t2), mkexpr(t2)));
break;
case 0x01: /* FILL.H */
DIP("FILL.H w%d, r%d", wd, ws);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I16);
assign(t3, mkNarrowTo16(ty, getIReg(ws)));
assign(t2,
binop(Iop_16HLto32, mkexpr(t3), mkexpr(t3)));
assign(t1,
binop(Iop_32HLto64, mkexpr(t2), mkexpr(t2)));
break;
case 0x02: /* FILL.W */
DIP("FILL.W w%d, r%d", wd, ws);
t2 = newTemp(Ity_I32);
assign(t2, mkNarrowTo32(ty, getIReg(ws)));
assign(t1,
binop(Iop_32HLto64, mkexpr(t2), mkexpr(t2)));
break;
case 0x03: /* FILL.D */
if (mode64) {
DIP("FILL.W w%d, r%d", wd, ws);
t2 = newTemp(Ity_I32);
assign(t1, getIReg(ws));
} else {
return -2;
}
break;
default:
return -1;
}
putWReg(wd,
binop(Iop_64HLtoV128, mkexpr(t1), mkexpr(t1)));
break;
}
case 0xC1: { /* PCNT.df */
switch (df) {
case 0x00: /* PCNT.B */
DIP("PCNT.B w%d, r%d", wd, ws);
putWReg(wd,
unop(Iop_Cnt8x16, getWReg(ws)));
break;
case 0x01: /* PCNT.H */
DIP("PCNT.H w%d, r%d", wd, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
assign(t1, unop(Iop_Cnt8x16, getWReg(ws)));
assign(t2,
binop(Iop_Add16x8,
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0x00FF00FF00FF00FFULL),
mkU64(0x00FF00FF00FF00FFULL))),
binop(Iop_AndV128,
binop(Iop_ShrN16x8,
mkexpr(t1), mkU8(8)),
binop(Iop_64HLtoV128,
mkU64(0x00FF00FF00FF00FFULL),
mkU64(0x00FF00FF00FF00FFULL)))));
putWReg(wd, mkexpr(t2));
break;
case 0x02: /* PCNT.W */
DIP("PCNT.W w%d, r%d", wd, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, unop(Iop_Cnt8x16, getWReg(ws)));
assign(t2,
binop(Iop_Add32x4,
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0x00FF00FF00FF00FFULL),
mkU64(0x00FF00FF00FF00FFULL))),
binop(Iop_AndV128,
binop(Iop_ShrN32x4,
mkexpr(t1), mkU8(8)),
binop(Iop_64HLtoV128,
mkU64(0x00FF00FF00FF00FFULL),
mkU64(0x00FF00FF00FF00FFULL)))));
assign(t3,
binop(Iop_Add32x4,
binop(Iop_AndV128,
mkexpr(t2),
binop(Iop_64HLtoV128,
mkU64(0x0000FFFF0000FFFFULL),
mkU64(0x0000FFFF0000FFFFULL))),
binop(Iop_AndV128,
binop(Iop_ShrN32x4,
mkexpr(t2), mkU8(16)),
binop(Iop_64HLtoV128,
mkU64(0x0000FFFF0000FFFFULL),
mkU64(0x0000FFFF0000FFFFULL)))));
putWReg(wd, mkexpr(t3));
break;
case 0x03: /* PCNT.D */
DIP("PCNT.D w%d, r%d", wd, ws);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);;
assign(t1, unop(Iop_Cnt8x16, getWReg(ws)));
assign(t2,
binop(Iop_Add64x2,
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0x00FF00FF00FF00FFULL),
mkU64(0x00FF00FF00FF00FFULL))),
binop(Iop_AndV128,
binop(Iop_ShrN64x2,
mkexpr(t1), mkU8(8)),
binop(Iop_64HLtoV128,
mkU64(0x00FF00FF00FF00FFULL),
mkU64(0x00FF00FF00FF00FFULL)))));
assign(t3,
binop(Iop_Add64x2,
binop(Iop_AndV128,
mkexpr(t2),
binop(Iop_64HLtoV128,
mkU64(0x0000FFFF0000FFFFULL),
mkU64(0x0000FFFF0000FFFFULL))),
binop(Iop_AndV128,
binop(Iop_ShrN64x2,
mkexpr(t2), mkU8(16)),
binop(Iop_64HLtoV128,
mkU64(0x0000FFFF0000FFFFULL),
mkU64(0x0000FFFF0000FFFFULL)))));
assign(t4,
binop(Iop_Add64x2,
binop(Iop_AndV128,
mkexpr(t3),
binop(Iop_64HLtoV128,
mkU64(0x00000000FFFFFFFFULL),
mkU64(0x00000000FFFFFFFFULL))),
binop(Iop_AndV128,
binop(Iop_ShrN64x2,
mkexpr(t3), mkU8(32)),
binop(Iop_64HLtoV128,
mkU64(0x00000000FFFFFFFFULL),
mkU64(0x00000000FFFFFFFFULL)))));
putWReg(wd, mkexpr(t4));
break;
default:
return -1;
}
break;
}
case 0xC2: { /* NLOC.df */
switch (df) {
case 0x00: /* NLOC.B */
DIP("NLOC.B w%d, w%d", wd, ws);
putWReg(wd,
unop(Iop_Cls8x16, getWReg(ws)));
break;
case 0x01: /* NLOC.H */
DIP("NLOC.H w%d, w%d", wd, ws);
putWReg(wd,
unop(Iop_Cls16x8, getWReg(ws)));
break;
case 0x02: /* NLOC.W */
DIP("NLOC.W w%d, w%d", wd, ws);
putWReg(wd,
unop(Iop_Cls32x4, getWReg(ws)));
break;
case 0x03: /* NLOC.D */
DIP("NLOC.D w%d, w%d", wd, ws);
t1 = newTemp(Ity_V128);
assign(t1, unop(Iop_NotV128, getWReg(ws)));
putWReg(wd, unop(Iop_Clz64x2, mkexpr(t1)));
break;
default:
return -1;
}
break;
}
case 0xC3: { /* NLZC.df */
switch (df) {
case 0x00: /* NLZC.B */
DIP("NLZC.W w%d, w%d", wd, ws);
putWReg(wd,
unop(Iop_Clz8x16, getWReg(ws)));
break;
case 0x01: /* NLZC.H */
DIP("NLZC.H w%d, w%d", wd, ws);
putWReg(wd,
unop(Iop_Clz16x8, getWReg(ws)));
break;
case 0x02: /* NLZC.W */
DIP("NLZC.W w%d, w%d", wd, ws);
putWReg(wd,
unop(Iop_Clz32x4, getWReg(ws)));
break;
case 0x03: {/* NLZC.D */
putWReg(wd,
unop(Iop_Clz64x2, getWReg(ws)));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_2RF(UInt cins, UChar wd, UChar ws) /* 2RF */
{
IRTemp t1, t2, t3, t4, t5;
UShort operation;
UChar df, wt;
operation = (cins & 0x03FE0000) >> 17;
df = (cins & 0x00010000) >> 16;
wt = (cins & 0x001F0000) >> 16;
switch (operation) {
case 0x190: { /* FCLASS.df */
IRTemp t0 = newTemp(Ity_V128);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
t5 = newTemp(Ity_V128);
switch (df) {
case 0x00: { /* FCLASS.W */
DIP("FCLASS.W w%d, w%d", wd, ws);
assign(t0,
binop(Iop_CmpEQ32x4,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7F8000007F800000ull),
mkU64(0x7F8000007F800000ull))),
binop(Iop_64HLtoV128,
mkU64(0ull), mkU64(0ull))));
assign(t1,
binop(Iop_CmpEQ32x4,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7F8000007F800000ull),
mkU64(0x7F8000007F800000ull))),
binop(Iop_64HLtoV128,
mkU64(0x7F8000007F800000ull),
mkU64(0x7F8000007F800000ull))));
assign(t2,
binop(Iop_SarN32x4,
getWReg(ws), mkU8(31)));
assign(t3,
binop(Iop_CmpEQ32x4,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x0040000000400000ull),
mkU64(0x0040000000400000ull))),
binop(Iop_64HLtoV128,
mkU64(0x0040000000400000ull),
mkU64(0x0040000000400000ull))));
assign(t4,
binop(Iop_CmpEQ32x4,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x007FFFFF007FFFFFULL),
mkU64(0x007FFFFF007FFFFFULL))),
binop(Iop_64HLtoV128,
mkU64(0ull), mkU64(0ull))));
assign(t5,
binop(Iop_Shl32x4,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_AndV128,
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(0x100000001ull),
mkU64(0x100000001ull)))),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t0),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(0x800000008ull),
mkU64(0x800000008ull))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t4)),
binop(Iop_64HLtoV128,
mkU64(0x400000004ull),
mkU64(0x400000004ull))))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t0)),
binop(Iop_64HLtoV128,
mkU64(0x200000002ull),
mkU64(0x200000002ull)))))),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t2),
binop(Iop_64HLtoV128,
mkU64(0x200000002ull),
mkU64(0x200000002ull))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t2)),
binop(Iop_64HLtoV128,
mkU64(0x600000006ull),
mkU64(0x600000006ull))))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t5),
binop(Iop_AndV128,
binop(Iop_CmpEQ32x4,
mkexpr(t5),
binop(Iop_64HLtoV128,
mkU64(0ull),
mkU64(0ull))),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t3),
binop(Iop_64HLtoV128,
mkU64(0x100000001ull),
mkU64(0x100000001ull))),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t3)),
binop(Iop_64HLtoV128,
mkU64(0x200000002ull),
mkU64(0x200000002ull)))))));
break;
}
case 0x01: { /* FCLASS.D */
DIP("FCLASS.D w%d, w%d", wd, ws);
assign(t0,
binop(Iop_CmpEQ64x2,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7FF0000000000000ull),
mkU64(0x7FF0000000000000ull))),
binop(Iop_64HLtoV128,
mkU64(0ull), mkU64(0ull))));
assign(t1,
binop(Iop_CmpEQ64x2,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x7FF0000000000000ull),
mkU64(0x7FF0000000000000ull))),
binop(Iop_64HLtoV128,
mkU64(0x7FF0000000000000ull),
mkU64(0x7FF0000000000000ull))));
assign(t2,
binop(Iop_SarN64x2,
getWReg(ws), mkU8(63)));
assign(t3,
binop(Iop_CmpEQ64x2,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x0008000000000000ull),
mkU64(0x0008000000000000ull))),
binop(Iop_64HLtoV128,
mkU64(0x0008000000000000ull),
mkU64(0x0008000000000000ull))));
assign(t4,
binop(Iop_CmpEQ64x2,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x000FFFFFFFFFFFFFULL),
mkU64(0x000FFFFFFFFFFFFFULL))),
binop(Iop_64HLtoV128,
mkU64(0ull), mkU64(0ull))));
assign(t5,
binop(Iop_Shl64x2,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_AndV128,
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(1ull),
mkU64(1ull)))),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t0),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
binop(Iop_64HLtoV128,
mkU64(8ull),
mkU64(8ull))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t4)),
binop(Iop_64HLtoV128,
mkU64(4ull),
mkU64(4ull))))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t1)),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t0)),
binop(Iop_64HLtoV128,
mkU64(2ull),
mkU64(2ull)))))),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t2),
binop(Iop_64HLtoV128,
mkU64(2ull),
mkU64(2ull))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t2)),
binop(Iop_64HLtoV128,
mkU64(6ull),
mkU64(6ull))))));
putWReg(wd,
binop(Iop_OrV128,
mkexpr(t5),
binop(Iop_AndV128,
binop(Iop_CmpEQ64x2,
mkexpr(t5),
binop(Iop_64HLtoV128,
mkU64(0ull),
mkU64(0ull))),
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t3),
binop(Iop_64HLtoV128,
mkU64(1ull),
mkU64(1ull))),
binop(Iop_AndV128,
unop(Iop_NotV128,
mkexpr(t3)),
binop(Iop_64HLtoV128,
mkU64(2ull),
mkU64(2ull)))))));
break;
}
default:
return -1;
}
break;
}
case 0x191: { /* FTRUNC_S.df */
switch (df) {
case 0x00: { /* FTRUNC_S.W */
DIP("FTRUNC_S.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTRUNCSW, 1);
putWReg(wd, unop(Iop_F32toI32Sx4_RZ, getWReg(ws)));
break;
}
case 0x01: { /* FTRUNC_S.D */
DIP("FTRUNC_S.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTRUNCSD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
assign(t3,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(ws))),
binop(Iop_Max64Fx2,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0xC3E0000000000000),
mkU64(0xC3E0000000000000)))));
assign(t1,
binop(Iop_F64toI64S, mkU32(0x3),
unop(Iop_ReinterpI64asF64,
unop(Iop_V128to64, mkexpr(t3)))));
assign(t2,
binop(Iop_F64toI64S, mkU32(0x3),
unop(Iop_ReinterpI64asF64,
unop(Iop_V128HIto64, mkexpr(t3)))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
case 0x192: { /* FTRUNC_U.df */
switch (df) {
case 0x00: { /* FTRUNC_U.W */
DIP("FTRUNC_U.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTRUNCUW, 1);
putWReg(wd, unop(Iop_F32toI32Ux4_RZ, getWReg(ws)));
break;
}
case 0x01: { /* FTRUNC_U.D */
DIP("FTRUNC_U.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTRUNCUD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
assign(t1,
binop(Iop_F64toI64U,
mkU32(0x3),
unop(Iop_ReinterpI64asF64,
unop(Iop_V128to64,
getWReg(ws)))));
assign(t2,
binop(Iop_F64toI64U,
mkU32(0x3),
unop(Iop_ReinterpI64asF64,
unop(Iop_V128HIto64,
getWReg(ws)))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
case 0x193: { /* FSQRT.df */
switch (df) {
case 0x00: { /* FSQRT.W */
DIP("FSQRT.W w%d, w%d", wd, ws);
IRExpr *rm = get_IR_roundingmode_MSA();
calculateMSACSR(ws, wd, FSQRTW, 1);
putWReg(wd, binop(Iop_Sqrt32Fx4, rm, getWReg(ws)));
break;
}
case 0x01: { /* FSQRT.D */
DIP("FSQRT.D w%d, w%d", wd, ws);
IRExpr *rm = get_IR_roundingmode_MSA();
calculateMSACSR(ws, wd, FSQRTD, 1);
putWReg(wd, binop(Iop_Sqrt64Fx2, rm, getWReg(ws)));
break;
}
default:
return -1;
}
break;
}
case 0x194: { /* FRSQRT.df */
switch (df) {
case 0x00: { /* FRSQRT.W */
DIP("FRSQRT.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FRSQRTW, 1);
putWReg(wd, unop(Iop_RSqrtEst32Fx4, getWReg(ws)));
break;
}
case 0x01: { /* FRSQRT.D */
DIP("FRSQRT.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FRSQRTD, 1);
putWReg(wd, unop(Iop_RSqrtEst64Fx2, getWReg(ws)));
break;
}
default:
return -1;
}
break;
}
case 0x195: { /* FRCP.df */
switch (df) { /* FRCP.W */
case 0x00: {
DIP("FRCP.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FRCPW, 1);
putWReg(wd, unop(Iop_RecipEst32Fx4, getWReg(ws)));
break;
}
case 0x01: { /* FRCP.D */
DIP("FRCP.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FRCPD, 1);
putWReg(wd, unop(Iop_RecipEst64Fx2, getWReg(ws)));
break;
}
default:
return -1;
}
break;
}
case 0x196: { /* FRINT.df */
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1, getWReg(ws));
switch (df) {
case 0x00: { /* FRINT.W */
DIP("FRINT.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FRINTW, 1);
assign(t2,
binop(Iop_OrV128,
binop(Iop_CmpLT32Fx4,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0xCF000000CF000000ull),
mkU64(0xCF000000CF000000ull))),
binop(Iop_CmpLT32Fx4,
binop(Iop_64HLtoV128,
mkU64(0x4F0000004F000000ull),
mkU64(0x4F0000004F000000ull)),
mkexpr(t1))));
assign(t3,
binop(Iop_CmpEQ32x4,
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0x0040000000400000ull),
mkU64(0x0040000000400000ull))),
binop(Iop_64HLtoV128,
mkU64(0x0040000000400000ull),
mkU64(0x0040000000400000ull))));
assign(t4,
binop(Iop_CmpUN32Fx4,
mkexpr(t1), mkexpr(t1)));
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_I32);
assign(tmp[i],
unop(Iop_ReinterpF32asI32,
binop(Iop_RoundF32toInt, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
mkexpr(t1), mkU8(i))))));
}
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_OrV128,
mkexpr(t2),
binop(Iop_AndV128,
mkexpr(t4),
unop(Iop_NotV128,
mkexpr(t3)))),
mkexpr(t1)),
binop(Iop_AndV128,
binop(Iop_AndV128,
mkexpr(t4),
mkexpr(t3)),
binop(Iop_64HLtoV128,
mkU64(0x7FBFFFFF7FBFFFFF),
mkU64(0x7FBFFFFF7FBFFFFF)))),
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_OrV128,
mkexpr(t2),
mkexpr(t4))),
binop(Iop_OrV128,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
mkexpr(tmp[3]),
mkexpr(tmp[2])),
binop(Iop_32HLto64,
mkexpr(tmp[1]),
mkexpr(tmp[0]))),
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0x8000000080000000ull),
mkU64(0x8000000080000000ull)))
))));
break;
}
case 0x01: { /* FRINT.D */
DIP("FRINT.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FRINTD, 1);
assign(t2,
binop(Iop_OrV128,
binop(Iop_CmpLT64Fx2,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0xC3E0000000000000ull),
mkU64(0xC3E0000000000000ull))),
binop(Iop_CmpLT64Fx2,
binop(Iop_64HLtoV128,
mkU64(0x43E0000000000000ull),
mkU64(0x43E0000000000000ull)),
mkexpr(t1))));
assign(t3,
binop(Iop_CmpEQ64x2,
binop(Iop_AndV128,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x0008000000000000ull),
mkU64(0x0008000000000000ull))),
binop(Iop_64HLtoV128,
mkU64(0x0008000000000000ull),
mkU64(0x0008000000000000ull))));
assign(t4,
binop(Iop_CmpUN64Fx2,
mkexpr(t1), mkexpr(t1)));
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_I64);
assign(tmp[i],
unop(Iop_ReinterpF64asI64,
binop(Iop_RoundF64toInt, rm,
unop(Iop_ReinterpI64asF64,
binop(Iop_GetElem64x2,
mkexpr(t1), mkU8(i))))));
}
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_OrV128,
binop(Iop_AndV128,
binop(Iop_OrV128,
mkexpr(t2),
binop(Iop_AndV128,
mkexpr(t4),
unop(Iop_NotV128,
mkexpr(t3)))),
mkexpr(t1)),
binop(Iop_AndV128,
binop(Iop_AndV128,
mkexpr(t4),
mkexpr(t3)),
binop(Iop_64HLtoV128,
mkU64(0x7FF7FFFFFFFFFFFF),
mkU64(0x7FF7FFFFFFFFFFFF)))),
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_OrV128,
mkexpr(t2),
mkexpr(t4))),
binop(Iop_OrV128,
binop(Iop_64HLtoV128,
mkexpr(tmp[1]),
mkexpr(tmp[0])),
binop(Iop_AndV128,
mkexpr(t1),
binop(Iop_64HLtoV128,
mkU64(0x8000000000000000ull),
mkU64(0x8000000000000000ull))
)))));
break;
}
default:
return -1;
}
break;
}
case 0x197: { /* FLOG2.df */
switch (df) {
case 0x00: { /* FLOG2.W */
DIP("FLOG2.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FLOG2W, 1);
putWReg(wd, unop(Iop_Log2_32Fx4, getWReg(ws)));
break;
}
case 0x01: { /* FLOG2.D */
DIP("FLOG2.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FLOG2D, 1);
putWReg(wd, unop(Iop_Log2_64Fx2, getWReg(ws)));
break;
}
default:
return -1;
}
break;
}
case 0x198: { /* FEXUPL.df */
switch (df) {
case 0x00: { /* FEXUPL.W */
DIP("FEXUPL.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FEXUPLW, 1);
putWReg(wd,
unop(Iop_F16toF32x4,
unop(Iop_V128HIto64,
getWReg(ws))));
break;
}
case 0x01: { /* FEXUPL.D */
DIP("FEXUPL.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FEXUPLD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
assign(t1,
unop(Iop_ReinterpF64asI64,
unop(Iop_F32toF64,
unop(Iop_ReinterpI32asF32,
unop(Iop_64to32,
unop(Iop_V128HIto64,
getWReg(ws)))))));
assign(t2,
unop(Iop_ReinterpF64asI64,
unop(Iop_F32toF64,
unop(Iop_ReinterpI32asF32,
unop(Iop_64HIto32,
unop(Iop_V128HIto64,
getWReg(ws)))))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
case 0x199: { /* FEXUPR.df */
switch (df) {
case 0x00: { /* FEXUPR.W */
DIP("FEXUPR.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FEXUPRW, 1);
putWReg(wd,
unop(Iop_F16toF32x4,
unop(Iop_V128to64,
getWReg(ws))));
break;
}
case 0x01: { /* FEXUPR.D */
DIP("FEXUPR.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FEXUPRD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
assign(t1,
unop(Iop_ReinterpF64asI64,
unop(Iop_F32toF64,
unop(Iop_ReinterpI32asF32,
unop(Iop_64to32,
unop(Iop_V128to64,
getWReg(ws)))))));
assign(t2,
unop(Iop_ReinterpF64asI64,
unop(Iop_F32toF64,
unop(Iop_ReinterpI32asF32,
unop(Iop_64HIto32,
unop(Iop_V128to64,
getWReg(ws)))))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
case 0x19A: { /* FFQL.df */
switch (df) {
case 0x00: { /* FFQL.W */
DIP("FFQL.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFQLW, 1);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_SarN32x4,
binop(Iop_InterleaveHI16x8,
getWReg(ws),
getWReg(ws)),
mkU8(16)));
assign(t2,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(1)))),
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(0))))));
assign(t3,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(3)))),
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2))))));
putWReg(wd,
triop(Iop_Div32Fx4, rm,
binop(Iop_64HLtoV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_64HLtoV128,
mkU64(0x4700000047000000),
mkU64(0x4700000047000000))));
break;
}
case 0x01: { /* FFQL.D */
DIP("FFQL.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFQLD, 1);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_SarN64x2,
binop(Iop_InterleaveHI32x4,
getWReg(ws),
getWReg(ws)),
mkU8(32)));
assign(t2,
unop(Iop_ReinterpF64asI64,
binop(Iop_I64StoF64, rm,
unop(Iop_V128to64,
mkexpr(t1)))));
assign(t3,
unop(Iop_ReinterpF64asI64,
binop(Iop_I64StoF64, rm,
unop(Iop_V128HIto64,
mkexpr(t1)))));
putWReg(wd,
triop(Iop_Div64Fx2, rm,
binop(Iop_64HLtoV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_64HLtoV128,
mkU64(0x41E0000000000000),
mkU64(0x41E0000000000000))));
break;
}
default:
return -1;
}
break;
}
case 0x19B: { /* FFQR.df */
switch (df) {
case 0x00: { /* FFQR.W */
DIP("FFQR.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFQRW, 1);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_SarN32x4,
binop(Iop_InterleaveLO16x8,
getWReg(ws),
getWReg(ws)),
mkU8(16)));
assign(t2,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(1)))),
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(0))))));
assign(t3,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(3)))),
unop(Iop_ReinterpF32asI32,
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1),
mkU8(2))))));
putWReg(wd,
triop(Iop_Div32Fx4, rm,
binop(Iop_64HLtoV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_64HLtoV128,
mkU64(0x4700000047000000),
mkU64(0x4700000047000000))));
break;
}
case 0x01: { /* FFQR.D */
DIP("FFQR.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFQRD, 1);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_SarN64x2,
binop(Iop_InterleaveLO32x4,
getWReg(ws),
getWReg(ws)),
mkU8(32)));
assign(t2,
unop(Iop_ReinterpF64asI64,
binop(Iop_I64StoF64, rm,
unop(Iop_V128to64,
mkexpr(t1)))));
assign(t3,
unop(Iop_ReinterpF64asI64,
binop(Iop_I64StoF64, rm,
unop(Iop_V128HIto64,
mkexpr(t1)))));
putWReg(wd,
triop(Iop_Div64Fx2, rm,
binop(Iop_64HLtoV128,
mkexpr(t3), mkexpr(t2)),
binop(Iop_64HLtoV128,
mkU64(0x41E0000000000000),
mkU64(0x41E0000000000000))));
break;
}
default:
return -1;
}
break;
}
case 0x19C: { /* FTINT_S.df */
switch (df) { /* FTINT_S.W */
case 0x00: {
DIP("FTINT_S.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTINT_SW, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_I32);
assign(t3,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN32Fx4,
getWReg(ws),
getWReg(ws))),
binop(Iop_Max32Fx4,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0xCF000000CF000000),
mkU64(0xCF000000CF000000)))));
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_32HLto64,
binop(Iop_F32toI32S, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
mkexpr(t3), mkU8(1)))),
binop(Iop_F32toI32S, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
mkexpr(t3), mkU8(0))))));
assign(t2,
binop(Iop_32HLto64,
binop(Iop_F32toI32S, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
mkexpr(t3), mkU8(3)))),
binop(Iop_F32toI32S, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
mkexpr(t3), mkU8(2))))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
case 0x01: { /* FTINT_S.D */
DIP("FTINT_S.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTINT_SD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
assign(t3,
binop(Iop_AndV128,
unop(Iop_NotV128,
binop(Iop_CmpUN64Fx2,
getWReg(ws),
getWReg(ws))),
binop(Iop_Max64Fx2,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0xC3E0000000000000),
mkU64(0xC3E0000000000000)))));
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_F64toI64S, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128to64, mkexpr(t3)))));
assign(t2,
binop(Iop_F64toI64S, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128HIto64, mkexpr(t3)))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
case 0x19D: {/* FTINT_U.df */
switch (df) { /* FTINT_U.W */
case 0x00: {
DIP("FTINT_U.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTINT_UW, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_V128);
t4 = newTemp(Ity_V128);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_32HLto64,
binop(Iop_F32toI32U, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(ws), mkU8(1)))),
binop(Iop_F32toI32U, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(ws), mkU8(0))))));
assign(t2,
binop(Iop_32HLto64,
binop(Iop_F32toI32U, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(ws), mkU8(3)))),
binop(Iop_F32toI32U, rm,
unop(Iop_ReinterpI32asF32,
binop(Iop_GetElem32x4,
getWReg(ws), mkU8(2))))));
assign(t3,
unop(Iop_NotV128,
binop(Iop_SarN32x4,
getWReg(ws),
mkU8(31))));
assign(t4,
binop(Iop_CmpLT32Fx4,
getWReg(ws),
binop(Iop_64HLtoV128,
mkU64(0x4EFFFFFF4EFFFFFF),
mkU64(0x4EFFFFFF4EFFFFFF))));
putWReg(wd,
binop(Iop_OrV128,
binop(Iop_AndV128,
mkexpr(t4),
binop(Iop_AndV128,
binop(Iop_64HLtoV128,
mkexpr(t2),
mkexpr(t1)),
mkexpr(t3))),
binop(Iop_AndV128,
unop(Iop_NotV128, mkexpr(t4)),
unop(Iop_F32toI32Ux4_RZ,
getWReg(ws)))));
break;
}
case 0x01: { /* FTINT_U.D */
DIP("FTINT_U.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wd, FTINT_UD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
IRExpr *rm = get_IR_roundingmode_MSA();
assign(t1,
binop(Iop_F64toI64U, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128to64,
getWReg(ws)))));
assign(t2,
binop(Iop_F64toI64U, rm,
unop(Iop_ReinterpI64asF64,
unop(Iop_V128HIto64,
getWReg(ws)))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
case 0x19E: { /* FFINT_S.df */
t1 = newTemp(Ity_V128);
assign(t1, getWReg(ws));
IRExpr *rm = get_IR_roundingmode_MSA();
switch (df) {
case 0x00: { /* FFINT_S.W */
DIP("FFINT_S.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFINTSW, 1);
IRTemp tmp[4];
Int i;
for (i = 0; i < 4; i++) {
tmp[i] = newTemp(Ity_F32);
assign(tmp[i],
binop(Iop_I32StoF32, rm,
binop(Iop_GetElem32x4,
mkexpr(t1), mkU8(i))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[3])),
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[2]))),
binop(Iop_32HLto64,
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[1])),
unop(Iop_ReinterpF32asI32,
mkexpr(tmp[0])))));
break;
}
case 0x01: { /* FFINT_S.D */
DIP("FFINT_S.D w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFINTSD, 1);
IRTemp tmp[2];
Int i;
for (i = 0; i < 2; i++) {
tmp[i] = newTemp(Ity_F64);
assign(tmp[i],
binop(Iop_I64StoF64, rm,
binop(Iop_GetElem64x2,
mkexpr(t1), mkU8(i))));
}
putWReg(wd,
binop(Iop_64HLtoV128,
unop(Iop_ReinterpF64asI64,
mkexpr(tmp[1])),
unop(Iop_ReinterpF64asI64,
mkexpr(tmp[0]))));
break;
}
default:
return -1;
}
break;
}
case 0x19F: { /* FFINT_U.df */
IRExpr *rm = get_IR_roundingmode_MSA();
switch (df) {
case 0x00: { /* FFINT_U.W */
DIP("FFINT_U.W w%d, w%d", wd, ws);
calculateMSACSR(ws, wt, FFINT_UW, 1);
putWReg(wd, unop(Iop_I32UtoF32x4_DEP, getWReg(ws)));
break;
}
case 0x01: { /* FFINT_U.D */
DIP("FFINT_U.D w%d, w%d",
wd, ws);
calculateMSACSR(ws, wt,
FFINT_UD, 1);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
assign(t1,
unop(Iop_ReinterpF64asI64,
binop(Iop_I64UtoF64, rm,
unop(Iop_V128to64,
getWReg(ws)))));
assign(t2,
unop(Iop_ReinterpF64asI64,
binop(Iop_I64UtoF64, rm,
unop(Iop_V128HIto64,
getWReg(ws)))));
putWReg(wd,
binop(Iop_64HLtoV128,
mkexpr(t2), mkexpr(t1)));
break;
}
default:
return -1;
}
break;
}
default:
return -1;
}
return 0;
}
static Int msa_MI10_load(UInt cins, UChar wd, UChar ws) /* MI10 (0x20) */
{
IRTemp t1;
UShort i10;
UChar df;
i10 = (cins & 0x03FF0000) >> 16;
df = cins & 0x00000003;
switch (df) {
case 0x00: { /* LD.B */
DIP("LD.B w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10);
putWReg(wd, load(Ity_V128, mkexpr(t1)));
break;
}
case 0x01: { /* LD.H */
DIP("LD.H w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10 << 1);
#if defined (_MIPSEL)
putWReg(wd, load(Ity_V128, mkexpr(t1)));
#elif defined (_MIPSEB)
putWReg(wd,
unop(Iop_Reverse8sIn16_x8,
load(Ity_V128, mkexpr(t1))));
#endif
break;
}
case 0x02: { /* LD.W */
DIP("LD.W w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10 << 2);
#if defined (_MIPSEL)
putWReg(wd, load(Ity_V128, mkexpr(t1)));
#elif defined (_MIPSEB)
putWReg(wd,
unop(Iop_Reverse8sIn32_x4,
load(Ity_V128, mkexpr(t1))));
#endif
break;
}
case 0x03: { /* LD.D */
DIP("LD.D w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10 << 3);
#if defined (_MIPSEL)
putWReg(wd, load(Ity_V128, mkexpr(t1)));
#elif defined (_MIPSEB)
putWReg(wd,
unop(Iop_Reverse8sIn64_x2,
load(Ity_V128, mkexpr(t1))));
#endif
break;
}
default:
return -1;
}
return 0;
}
static Int msa_MI10_store(UInt cins, UChar wd, UChar ws) /* MI10 (0x24) */
{
IRTemp t1;
UShort i10;
UChar df;
df = cins & 0x00000003;
i10 = (cins & 0x03FF0000) >> 16;
switch (df) {
case 0x00: { /* ST.B */
DIP("ST.B w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10);
store(mkexpr(t1), getWReg(wd));
break;
}
case 0x01: { /* ST.H */
DIP("ST.H w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10 << 1);
#if defined (_MIPSEL)
store(mkexpr(t1), getWReg(wd));
#elif defined (_MIPSEB)
store(mkexpr(t1),
unop(Iop_Reverse8sIn16_x8, getWReg(wd)));
#endif
break;
}
case 0x02: { /* ST.W */
DIP("ST.W w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10 << 2);
#if defined (_MIPSEL)
store(mkexpr(t1), getWReg(wd));
#elif defined (_MIPSEB)
store(mkexpr(t1),
unop(Iop_Reverse8sIn32_x4, getWReg(wd)));
#endif
break;
}
case 0x03: { /* ST.D */
DIP("ST.D w%d, %d(r%d)", wd, ws, i10);
LOAD_STORE_PATTERN_MSA(i10 << 3);
#if defined (_MIPSEL)
store(mkexpr(t1), getWReg(wd));
#elif defined (_MIPSEB)
store(mkexpr(t1),
unop(Iop_Reverse8sIn64_x2, getWReg(wd)));
#endif
break;
}
default:
return -1;
}
return 0;
}
/*------------------------------------------------------------*/
/*--- Disassemble a single MIPS MSA (SIMD) instruction ---*/
/*--- Return values: ---*/
/*--- 0: Success ---*/
/*--- -1: Decode failure (unknown instruction) ---*/
/*--- -2: Illegal instruction ---*/
/*------------------------------------------------------------*/
static Int disMSAInstr_MIPS_WRK ( UInt cins )
{
UChar minor_opcode, wd, ws;
vassert(has_msa);
vassert((cins & 0xFC000000) == 0x78000000);
minor_opcode = (cins & 0x20) > 0 ? (cins & 0x3C) : (cins & 0x3F);
wd = (cins & 0x000007C0) >> 6;
ws = (cins & 0x0000F800) >> 11;
switch (minor_opcode) {
case 0x0:
return msa_I8_logical(cins, wd, ws);
case 0x01:
return msa_I8_branch(cins, wd, ws);
case 0x02:
return msa_I8_shift(cins, wd, ws);
case 0x06:
return msa_I5_06(cins, wd, ws);
case 0x07:
return msa_I5_07(cins, wd, ws);
case 0x09:
return msa_BIT_09(cins, wd, ws);
case 0x0A:
return msa_BIT_0A(cins, wd, ws);
case 0x0D:
return msa_3R_0D(cins, wd, ws);
case 0x0E:
return msa_3R_0E(cins, wd, ws);
case 0x0F:
return msa_3R_0F(cins, wd, ws);
case 0x10:
return msa_3R_10(cins, wd, ws);
case 0x11:
return msa_3R_11(cins, wd, ws);
case 0x12:
return msa_3R_12(cins, wd, ws);
case 0x13:
return msa_3R_13(cins, wd, ws);
case 0x14:
return msa_3R_14(cins, wd, ws);
case 0x15:
return msa_3R_15(cins, wd, ws);
case 0x19:
return msa_ELM(cins, wd, ws);
case 0x1A:
return msa_3R_1A(cins, wd, ws);
case 0x1B:
return msa_3R_1B(cins, wd, ws);
case 0x1C:
return msa_3R_1C(cins, wd, ws);
case 0x1E:
if ((cins & 0x03000000) == 0)
return msa_VEC(cins, wd, ws);
else if ((cins & 0x00200000) == 0)
return msa_2R(cins, wd, ws);
else
return msa_2RF(cins, wd, ws);
case 0x20:
return msa_MI10_load(cins, wd, ws);
case 0x24:
return msa_MI10_store(cins, wd, ws);
}
return -1;
}
/*------------------------------------------------------------*/
/*--- DSP to IR function ---*/
/*------------------------------------------------------------*/
extern UInt disDSPInstr_MIPS_WRK ( UInt );
/*------------------------------------------------------------*/
/*--- Disassemble a single instruction ---*/
/*------------------------------------------------------------*/
/* Disassemble a single instruction into IR. The instruction is
located in host memory at guest_instr, and has guest IP of
guest_PC_curr_instr, which will have been set before the call
here. */
static UInt disInstr_MIPS_WRK_Special(UInt cins, const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo, DisResult* dres,
IRStmt** bstmt, IRExpr** lastn)
{
IRTemp t0, t1 = 0, t2, t3, t4, t5;
UInt rs, rt, rd, sa, tf, function, trap_code, imm, instr_index, rot, sel;
/* Additional variables for instruction fields in DSP ASE insructions */
UInt ac;
imm = get_imm(cins);
rs = get_rs(cins);
rt = get_rt(cins);
rd = get_rd(cins);
sa = get_sa(cins);
tf = get_tf(cins);
sel = get_sel(cins);
instr_index = get_instr_index(cins);
trap_code = get_code(cins);
function = get_function(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
ac = get_acNo(cins);
switch (function) {
case 0x00: { /* SLL */
DIP("sll r%u, r%u, %u", rd, rt, sa);
IRTemp tmpRt32 = newTemp(Ity_I32);
IRTemp tmpSh32 = newTemp(Ity_I32);
IRTemp tmpRd = newTemp(Ity_I64);
if (mode64) {
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
assign(tmpSh32, binop(Iop_Shl32, mkexpr(tmpRt32), mkU8(sa)));
assign(tmpRd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
putIReg(rd, mkexpr(tmpRd));
} else
SXX_PATTERN(Iop_Shl32);
break;
}
case 0x01: { /* MOVCI */
UInt mov_cc = get_mov_cc(cins);
if (tf == 0) { /* MOVF */
DIP("movf r%u, r%u, %u", rd, rs, mov_cc);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + mov_cc)),
mkU32(0x1))
));
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
putIReg(rd, IRExpr_ITE(mkexpr(t3), getIReg(rs), getIReg(rd)));
} else if (tf == 1) { /* MOVT */
DIP("movt r%u, r%u, %u", rd, rs, mov_cc);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + mov_cc)),
mkU32(0x1))
));
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
putIReg(rd, IRExpr_ITE(mkexpr(t3), getIReg(rs), getIReg(rd)));
}
break;
}
case 0x02: { /* SRL */
rot = get_rot(cins);
if (rot) {
DIP("rotr r%u, r%u, %u", rd, rt, sa);
putIReg(rd, mkWidenFrom32(ty, genROR32(mkNarrowTo32(ty,
getIReg(rt)), sa), True));
} else {
DIP("srl r%u, r%u, %u", rd, rt, sa);
if (mode64) {
IRTemp tmpSh32 = newTemp(Ity_I32);
IRTemp tmpRt32 = newTemp(Ity_I32);
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
assign(tmpSh32, binop(Iop_Shr32, mkexpr(tmpRt32), mkU8(sa)));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
} else {
SXX_PATTERN(Iop_Shr32);
}
}
break;
}
case 0x03: /* SRA */
DIP("sra r%u, r%u, %u", rd, rt, sa);
if (mode64) {
IRTemp tmpRt32 = newTemp(Ity_I32);
IRTemp tmpSh32 = newTemp(Ity_I32);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
assign(t1, binop(Iop_And64, getIReg(rt), /* hi */
mkU64(0xFFFFFFFF00000000ULL)));
assign(t2, binop(Iop_Sar64, mkexpr(t1), mkU8(sa)));
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkU8(sa)));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
} else {
SXX_PATTERN(Iop_Sar32);
}
break;
case 0x04: { /* SLLV */
DIP("sllv r%u, r%u, r%u", rd, rt, rs);
if (mode64) {
IRTemp tmpRs8 = newTemp(Ity_I8);
IRTemp tmpRt32 = newTemp(Ity_I32);
IRTemp tmpSh32 = newTemp(Ity_I32);
IRTemp tmp = newTemp(ty);
assign(tmp, binop(mkSzOp(ty, Iop_And8), getIReg(rs),
mkSzImm(ty, 31)));
assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp)));
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
assign(tmpSh32, binop(Iop_Shl32, mkexpr(tmpRt32), mkexpr(tmpRs8)));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
} else {
SXXV_PATTERN(Iop_Shl32);
}
break;
}
case 0x05: { /* LSA */
UInt imm2 = (imm & 0xC0) >> 6;
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) || has_msa) {
DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2);
if (mode64) {
DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2);
putIReg(rd, unop(Iop_32Sto64,
binop(Iop_Add32,
binop(Iop_Shl32,
unop(Iop_64to32, getIReg(rs)),
mkU8(imm2 + 1)),
unop(Iop_64to32, getIReg(rt)))));
break;
} else {
DIP("lsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2);
putIReg(rd, binop(Iop_Add32,
binop(Iop_Shl32,
getIReg(rs), mkU8(imm2 + 1)), getIReg(rt)));
break;
}
} else {
ILLEGAL_INSTRUCTON;
break;
}
}
case 0x06: { /* SRLV */
rot = get_rotv(cins);
if (rot) {
DIP("rotrv r%u, r%u, r%u", rd, rt, rs);
putIReg(rd, mkWidenFrom32(ty, genRORV32(mkNarrowTo32(ty,
getIReg(rt)), mkNarrowTo32(ty, getIReg(rs))), True));
break;
} else { /* SRLV */
DIP("srlv r%u, r%u, r%u", rd, rt, rs);
if (mode64) {
SXXV_PATTERN64(Iop_Shr32);
} else {
SXXV_PATTERN(Iop_Shr32);
}
break;
}
}
case 0x07: /* SRAV */
DIP("srav r%u, r%u, r%u", rd, rt, rs);
if (mode64) {
IRTemp tmpRt32 = newTemp(Ity_I32);
IRTemp tmpSh32 = newTemp(Ity_I32);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I8);
assign(t4, unop(Iop_32to8, binop(Iop_And32,
mkNarrowTo32(ty, getIReg(rs)), mkU32(0x0000001F))));
assign(t1, binop(Iop_And64, getIReg(rt), /* hi */
mkU64(0xFFFFFFFF00000000ULL)));
assign(t2, binop(Iop_Sar64, mkexpr(t1), mkexpr(t4)));
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkexpr(t4)));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True));
} else {
SXXV_PATTERN(Iop_Sar32);
}
break;
case 0x08: /* JR */
DIP("jr r%u", rs);
t0 = newTemp(ty);
assign(t0, getIReg(rs));
*lastn = mkexpr(t0);
break;
case 0x09: /* JALR */
DIP("jalr r%u r%u", rd, rs);
if (mode64) {
putIReg(rd, mkU64(guest_PC_curr_instr + 8));
t0 = newTemp(Ity_I64);
assign(t0, getIReg(rs));
*lastn = mkexpr(t0);
} else {
putIReg(rd, mkU32(guest_PC_curr_instr + 8));
t0 = newTemp(Ity_I32);
assign(t0, getIReg(rs));
*lastn = mkexpr(t0);
}
break;
case 0x0A: { /* MOVZ */
DIP("movz r%u, r%u, r%u", rd, rs, rt);
t1 = newTemp(ty);
t2 = newTemp(ty);
if (mode64) {
assign(t1, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpEQ64,
getIReg(rt), mkU64(0x0)))));
assign(t2, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpNE64,
getIReg(rt), mkU64(0x0)))));
putIReg(rd, binop(Iop_Add64, binop(Iop_And64, getIReg(rs),
mkexpr(t1)), binop(Iop_And64, getIReg(rd), mkexpr(t2))));
} else {
assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rt),
mkU32(0x0))));
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpNE32, getIReg(rt),
mkU32(0x0))));
putIReg(rd, binop(Iop_Add32, binop(Iop_And32, getIReg(rs),
mkexpr(t1)), binop(Iop_And32, getIReg(rd),
mkexpr(t2))));
}
break;
}
case 0x0B: { /* MOVN */
DIP("movn r%u, r%u, r%u", rd, rs, rt);
t1 = newTemp(ty);
t2 = newTemp(ty);
if (mode64) {
assign(t1, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpEQ64,
getIReg(rt), mkU64(0x0)))));
assign(t2, unop(Iop_32Sto64, unop(Iop_1Sto32, binop(Iop_CmpNE64,
getIReg(rt), mkU64(0x0)))));
putIReg(rd, binop(Iop_Add64, binop(Iop_And64, getIReg(rs),
mkexpr(t2)), binop(Iop_And64, getIReg(rd),
mkexpr(t1))));
} else {
assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rt),
mkU32(0x0))));
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpNE32, getIReg(rt),
mkU32(0x0))));
putIReg(rd, binop(Iop_Add32, binop(Iop_And32, getIReg(rs),
mkexpr(t2)), binop(Iop_And32, getIReg(rd),
mkexpr(t1))));
}
break;
}
case 0x0C: /* SYSCALL */
DIP("syscall");
if (mode64)
putPC(mkU64(guest_PC_curr_instr + 4));
else
putPC(mkU32(guest_PC_curr_instr + 4));
dres->jk_StopHere = Ijk_Sys_syscall;
dres->whatNext = Dis_StopHere;
break;
case 0x0D: /* BREAK */
DIP("break 0x%x", trap_code);
if (mode64)
jmp_lit64(dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4));
else
jmp_lit32(dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4));
vassert(dres->whatNext == Dis_StopHere);
break;
case 0x0F: /* SYNC */
DIP("sync 0x%x", sel);
/* Just ignore it. */
break;
case 0x10: { /* MFHI, CLZ R6 */
if (((instr_index >> 6) & 0x1f) == 1) { /* CLZ */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("clz r%u, r%u", rd, rs);
if (mode64) {
IRTemp tmpClz32 = newTemp(Ity_I32);
IRTemp tmpRs32 = newTemp(Ity_I32);
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
assign(tmpClz32, unop(Iop_Clz32, mkexpr(tmpRs32)));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClz32), True));
} else {
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0)));
putIReg(rd, IRExpr_ITE(mkexpr(t1),
mkU32(0x00000020),
unop(Iop_Clz32, getIReg(rs))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MFHI */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -1;
}
break;
} else {
DIP("mfhi r%u", rd);
putIReg(rd, getHI());
break;
}
}
case 0x11: { /* MTHI, CLO R6 */
if (((instr_index >> 6) & 0x1f) == 1) { /* CLO */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("clo r%u, r%u", rd, rs);
if (mode64) {
IRTemp tmpClo32 = newTemp(Ity_I32);
IRTemp tmpRs32 = newTemp(Ity_I32);
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ32, mkexpr(tmpRs32), mkU32(0xffffffff)));
assign(tmpClo32, IRExpr_ITE(mkexpr(t1),
mkU32(0x00000020),
unop(Iop_Clz32, unop(Iop_Not32, mkexpr(tmpRs32)))));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClo32), True));
break;
} else {
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0xffffffff)));
putIReg(rd, IRExpr_ITE(mkexpr(t1),
mkU32(0x00000020),
unop(Iop_Clz32,
unop(Iop_Not32, getIReg(rs)))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MTHI */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -1;
}
break;
} else {
DIP("mthi r%u", rs);
putHI(getIReg(rs));
break;
}
}
case 0x12: { /* MFLO */
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MFLO */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -1;
}
break;
} else {
switch (sa) {
case 0:
DIP("mflo r%u", rd);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
putIReg(rd, getLO());
break;
case 1:
DIP("dclz r%u, r%u", rd, rs);
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0)));
putIReg(rd, IRExpr_ITE(mkexpr(t1),
mkU64(0x00000040),
unop(Iop_Clz64, getIReg(rs))));
break;
}
break;
}
}
case 0x13: { /* MTLO */
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MTLO */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -1;
}
break;
} else {
switch (sa) {
case 0:
DIP("mtlo r%u", rs);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
putLO(getIReg(rs));
break;
case 1:
DIP("dclo r%u, r%u", rd, rs);
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ64, getIReg(rs),
mkU64(0xffffffffffffffffULL)));
putIReg(rd, IRExpr_ITE(mkexpr(t1),
mkU64(0x40),
unop(Iop_Clz64, unop(Iop_Not64,
getIReg(rs)))));
break;
}
break;
}
}
case 0x15: { /* DLSA */
UInt imm2 = (imm & 0xC0) >> 6;
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) || has_msa) {
DIP("dlsa r%u, r%u, r%u, imm: 0x%x", rd, rs, rt, imm2);
putIReg(rd, binop(Iop_Add64,
binop(Iop_Shl64, getIReg(rs), mkU8(imm2 + 1)),
getIReg(rt)));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
case 0x18: { /* MULT */
switch (sa & 0x3) {
case 0: {
if ((1 <= ac) && ( 3 >= ac)) {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MULT */
UInt retVal = disDSPInstr_MIPS_WRK(cins);
if (0 != retVal) {
return -2;
}
break;
} else {
return -2;
}
} else {
DIP("mult r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
break;
}
}
case 2: { /* MUL R6 */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("mul r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Sto64,
unop(Iop_64to32,
binop(Iop_MullS32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt))))));
} else {
putIReg(rd, unop(Iop_64to32,
binop(Iop_MullS32,
getIReg(rs), getIReg(rt))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
}
case 3: { /* MUH R6 */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("muh r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Sto64,
unop(Iop_64HIto32,
binop(Iop_MullS32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt))))));
} else {
putIReg(rd, unop(Iop_64HIto32,
binop(Iop_MullS32,
getIReg(rs), getIReg(rt))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
}
}
break;
}
case 0x19: { /* MULTU */
switch (sa & 0x3) {
case 0: {
if ((1 <= ac) && ( 3 >= ac)) {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MULTU */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal) {
return -2;
}
break;
} else {
return -2;
}
} else {
DIP("multu r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
break;
}
}
case 2: { /* MULU R6 */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("mulu r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Uto64,
unop(Iop_64to32,
binop(Iop_MullU32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt))))));
} else {
putIReg(rd, unop(Iop_64to32,
binop(Iop_MullU32,
getIReg(rs), getIReg(rt))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
}
case 3: { /* MUHU R6 */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("muhu r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Uto64,
unop(Iop_64HIto32,
binop(Iop_MullU32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt))))));
} else {
putIReg(rd, unop(Iop_64HIto32,
binop(Iop_MullU32,
getIReg(rs), getIReg(rt))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
}
}
break;
}
case 0x1A: /* DIV */
switch (sa & 0x3) {
case 0:
DIP("div r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
if (mode64) {
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_DivModS32to32,
mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
} else {
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt)));
putHI(unop(Iop_64HIto32, mkexpr(t1)));
putLO(unop(Iop_64to32, mkexpr(t1)));
}
break;
case 2:
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("div r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Sto64,
binop(Iop_DivS32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt)))));
} else {
putIReg(rd, binop(Iop_DivS32, getIReg(rs), getIReg(rt)));
}
} else {
ILLEGAL_INSTRUCTON
}
break;
case 3:
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("mod r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Sto64,
unop(Iop_64HIto32,
binop(Iop_DivModS32to32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt))))));
} else {
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt)));
putIReg(rd, unop(Iop_64HIto32, mkexpr(t1)));
}
} else {
ILLEGAL_INSTRUCTON
}
break;
}
break;
case 0x1B: /* DIVU */
switch (sa & 0x3) {
case 0:
DIP("divu r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
if (mode64) {
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_DivModU32to32,
mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t1)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t1)), True));
} else {
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt)));
putHI(unop(Iop_64HIto32, mkexpr(t1)));
putLO(unop(Iop_64to32, mkexpr(t1)));
}
break;
case 2:
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("divu r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Sto64,
binop(Iop_DivU32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt)))));
} else {
putIReg(rd, binop(Iop_DivU32, getIReg(rs), getIReg(rt)));
}
break;
} else {
ILLEGAL_INSTRUCTON
}
break;
case 3:
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("modu r%u, r%u, r%u", rs, rt, rd);
if (mode64) {
putIReg(rd, unop(Iop_32Uto64,
unop(Iop_64HIto32,
binop(Iop_DivModU32to32,
unop(Iop_64to32, getIReg(rs)),
unop(Iop_64to32, getIReg(rt))))));
} else {
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt)));
putIReg(rd, unop(Iop_64HIto32, mkexpr(t1)));
}
} else {
ILLEGAL_INSTRUCTON
}
break;
}
break;
case 0x1C: /* Doubleword Multiply - DMULT; MIPS64 */
switch (sa) {
case 0:
DIP("dmult r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
t0 = newTemp(Ity_I128);
assign(t0, binop(Iop_MullS64, getIReg(rs), getIReg(rt)));
putHI(unop(Iop_128HIto64, mkexpr(t0)));
putLO(unop(Iop_128to64, mkexpr(t0)));
break;
case 2: /* DMUL */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dmul r%u, r%u, r%u", rd, rs, rt);
putIReg(rd, unop(Iop_128to64,
binop(Iop_MullS64, getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 3: /* DMUH */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dmuh r%u, r%u, r%u", rd, rs, rt);
putIReg(rd, unop(Iop_128HIto64,
binop(Iop_MullS64, getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
break;
case 0x1D: /* Doubleword Multiply Unsigned - DMULTU; MIPS64 */
switch (sa) {
case 0:
DIP("dmultu r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
t0 = newTemp(Ity_I128);
assign(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt)));
putHI(unop(Iop_128HIto64, mkexpr(t0)));
putLO(unop(Iop_128to64, mkexpr(t0)));
break;
case 2: /* DMULU */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dmulu r%u, r%u, r%u", rd, rs, rt);
putIReg(rd, unop(Iop_128to64,
binop(Iop_MullU64, getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 3: /* DMUHU */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dmuhu r%u, r%u, r%u", rd, rs, rt);
putIReg(rd, unop(Iop_128HIto64,
binop(Iop_MullU64, getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
break;
case 0x1E: /* Doubleword Divide DDIV; MIPS64 */
switch (sa) {
case 0:
DIP("ddiv r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
t1 = newTemp(Ity_I128);
assign(t1, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt)));
putHI(unop(Iop_128HIto64, mkexpr(t1)));
putLO(unop(Iop_128to64, mkexpr(t1)));
break;
case 2: /* DDIV r6 */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("ddiv r%u, r%u, r%u", rs, rt, rd);
putIReg(rd, unop(Iop_128to64,
binop(Iop_DivModS64to64,
getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 3: /* DMOD r6 */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dmod r%u, r%u, r%u", rs, rt, rd);
t2 = newTemp(Ity_I128);
assign(t2, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt)));
putIReg(rd, unop(Iop_128HIto64, mkexpr(t2)));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
break;
case 0x1F: /* Doubleword Divide Unsigned DDIVU; MIPS64 check this */
switch (sa) {
case 0:
DIP("ddivu r%u, r%u", rs, rt);
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) &&
!VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
t1 = newTemp(Ity_I128);
assign(t1, binop(Iop_DivModU64to64, getIReg(rs), getIReg(rt)));
putHI(unop(Iop_128HIto64, mkexpr(t1)));
putLO(unop(Iop_128to64, mkexpr(t1)));
break;
case 2:
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("ddivu r%u, r%u, r%u", rs, rt, rd);
putIReg(rd, unop(Iop_128to64, binop(Iop_DivModU64to64,
getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 3:
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dmodu r%u, r%u, r%u", rs, rt, rd);
putIReg(rd, unop(Iop_128HIto64, binop(Iop_DivModU64to64,
getIReg(rs), getIReg(rt))));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
break;
case 0x20: { /* ADD */
DIP("add r%u, r%u, r%u", rd, rs, rt);
IRTemp tmpRs32 = newTemp(Ity_I32);
IRTemp tmpRt32 = newTemp(Ity_I32);
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
/* dst = src0 + src1
if (sign(src0 ) != sign(src1 ))
goto no overflow;
if (sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
assign(t2, unop(Iop_1Uto32,
binop(Iop_CmpEQ32,
binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
mkU32(0x80000000))));
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
assign(t4, unop(Iop_1Uto32,
binop(Iop_CmpNE32,
binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
mkU32(0x80000000))));
stmt(IRStmt_Exit(binop(Iop_CmpEQ32,
binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
mkU32(0)),
Ijk_SigFPE_IntOvf,
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True));
break;
}
case 0x21: /* ADDU */
DIP("addu r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
ALU_PATTERN64(Iop_Add32);
} else {
ALU_PATTERN(Iop_Add32);
}
break;
case 0x22: { /* SUB */
DIP("sub r%u, r%u, r%u", rd, rs, rt);
IRTemp tmpRs32 = newTemp(Ity_I32);
IRTemp tmpRt32 = newTemp(Ity_I32);
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
/* dst = src0 + (-1 * src1)
if(sign(src0 ) != sign((-1 * src1) ))
goto no overflow;
if(sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t5, binop(Iop_Mul32, mkexpr(tmpRt32), mkU32(-1)));
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(t5)));
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(t5)));
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpEQ32, binop(Iop_And32,
mkexpr(t1), mkU32(0x80000000)), mkU32(0x80000000))));
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
assign(t4, unop(Iop_1Sto32, binop(Iop_CmpNE32, binop(Iop_And32,
mkexpr(t3), mkU32(0x80000000)), mkU32(0x80000000))));
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, binop(Iop_Or32, mkexpr(t2),
mkexpr(t4)), mkU32(0)), Ijk_SigFPE_IntOvf,
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True));
break;
}
case 0x23: /* SUBU */
DIP("subu r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
ALU_PATTERN64(Iop_Sub32);
} else {
ALU_PATTERN(Iop_Sub32);
}
break;
case 0x24: /* AND */
DIP("and r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
ALU_PATTERN(Iop_And64);
} else {
ALU_PATTERN(Iop_And32);
}
break;
case 0x25: /* OR */
DIP("or r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
ALU_PATTERN(Iop_Or64);
} else {
ALU_PATTERN(Iop_Or32);
}
break;
case 0x26: /* XOR */
DIP("xor r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
ALU_PATTERN(Iop_Xor64);
} else {
ALU_PATTERN(Iop_Xor32);
}
break;
case 0x27: /* NOR */
DIP("nor r%u, r%u, r%u", rd, rs, rt);
if (mode64)
putIReg(rd, unop(Iop_Not64, binop(Iop_Or64, getIReg(rs),
getIReg(rt))));
else
putIReg(rd, unop(Iop_Not32, binop(Iop_Or32, getIReg(rs),
getIReg(rt))));
break;
case 0x2A: /* SLT */
DIP("slt r%u, r%u, r%u", rd, rs, rt);
if (mode64)
putIReg(rd, unop(Iop_1Uto64, binop(Iop_CmpLT64S, getIReg(rs),
getIReg(rt))));
else
putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
getIReg(rt))));
break;
case 0x2B: /* SLTU */
DIP("sltu r%u, r%u, r%u", rd, rs, rt);
if (mode64)
putIReg(rd, unop(Iop_1Uto64, binop(Iop_CmpLT64U, getIReg(rs),
getIReg(rt))));
else
putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
getIReg(rt))));
break;
case 0x2C: { /* Doubleword Add - DADD; MIPS64 */
DIP("dadd r%u, r%u, r%u", rd, rs, rt);
IRTemp tmpRs64 = newTemp(Ity_I64);
IRTemp tmpRt64 = newTemp(Ity_I64);
assign(tmpRs64, getIReg(rs));
assign(tmpRt64, getIReg(rt));
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
/* dst = src0 + src1
if(sign(src0 ) != sign(src1 ))
goto no overflow;
if(sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t0, binop(Iop_Add64, mkexpr(tmpRs64), mkexpr(tmpRt64)));
assign(t1, binop(Iop_Xor64, mkexpr(tmpRs64), mkexpr(tmpRt64)));
assign(t2, unop(Iop_1Uto64,
binop(Iop_CmpEQ64,
binop(Iop_And64, mkexpr(t1),
mkU64(0x8000000000000000ULL)),
mkU64(0x8000000000000000ULL))));
assign(t3, binop(Iop_Xor64, mkexpr(t0), mkexpr(tmpRs64)));
assign(t4, unop(Iop_1Uto64,
binop(Iop_CmpNE64,
binop(Iop_And64, mkexpr(t3),
mkU64(0x8000000000000000ULL)),
mkU64(0x8000000000000000ULL))));
stmt(IRStmt_Exit(binop(Iop_CmpEQ64,
binop(Iop_Or64, mkexpr(t2), mkexpr(t4)),
mkU64(0)),
Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
putIReg(rd, mkexpr(t0));
break;
}
case 0x2D: /* Doubleword Add Unsigned - DADDU; MIPS64 */
DIP("daddu r%u, r%u, r%u", rd, rs, rt);
ALU_PATTERN(Iop_Add64);
break;
case 0x2E: { /* Doubleword Subtract - DSUB; MIPS64 */
DIP("dsub r%u, r%u, r%u", rd, rs, rt);
IRTemp tmpRs64 = newTemp(Ity_I64);
IRTemp tmpRt64 = newTemp(Ity_I64);
assign(tmpRs64, getIReg(rs));
assign(tmpRt64, getIReg(rt));
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
/* dst = src0 + (-1 * src1)
if(sign(src0 ) != sign((-1 * src1) ))
goto no overflow;
if(sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t5, binop(Iop_Mul64,
mkexpr(tmpRt64),
mkU64(0xffffffffffffffffULL)));
assign(t0, binop(Iop_Add64, mkexpr(tmpRs64), mkexpr(t5)));
assign(t1, binop(Iop_Xor64, mkexpr(tmpRs64), mkexpr(t5)));
assign(t2, unop(Iop_1Sto64,
binop(Iop_CmpEQ64,
binop(Iop_And64,
mkexpr(t1),
mkU64(0x8000000000000000ULL)),
mkU64(0x8000000000000000ULL))));
assign(t3, binop(Iop_Xor64, mkexpr(t0), mkexpr(tmpRs64)));
assign(t4, unop(Iop_1Sto64,
binop(Iop_CmpNE64,
binop(Iop_And64,
mkexpr(t3),
mkU64(0x8000000000000000ULL)),
mkU64(0x8000000000000000ULL))));
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, binop(Iop_Or64, mkexpr(t2),
mkexpr(t4)), mkU64(0)), Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
putIReg(rd, binop(Iop_Sub64, getIReg(rs), getIReg(rt)));
break;
}
case 0x2F: /* Doubleword Subtract Unsigned - DSUBU; MIPS64 */
DIP("dsub r%u, r%u,r%u", rd, rt, rt);
ALU_PATTERN(Iop_Sub64);
break;
case 0x30: { /* TGE */
DIP("tge r%u, r%u %u", rs, rt, trap_code);
if (mode64) {
if (trap_code == 7)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64S,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntDiv,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64S,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64S,
getIReg (rs),
getIReg (rt))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
if (trap_code == 7)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32S,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntDiv,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32S,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntOvf,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32S,
getIReg (rs),
getIReg (rt))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x31: { /* TGEU */
DIP("tgeu r%u, r%u %u", rs, rt, trap_code);
if (mode64) {
if (trap_code == 7)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64U,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntDiv,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64U,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64U,
getIReg (rs),
getIReg (rt))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
if (trap_code == 7)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32U,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntDiv,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32U,
getIReg (rs),
getIReg (rt))),
Ijk_SigFPE_IntOvf,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32U,
getIReg (rs),
getIReg (rt))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x32: { /* TLT */
DIP("tlt r%u, r%u %u", rs, rt, trap_code);
if (mode64) {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpLT64S, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpLT64S, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpLT64S, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpLT32S, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpLT32S, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpLT32S, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x33: { /* TLTU */
DIP("tltu r%u, r%u %u", rs, rt, trap_code);
if (mode64) {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpLT64U, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpLT64U, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpLT64U, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpLT32U, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpLT32U, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpLT32U, getIReg(rs),
getIReg (rt)), Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x34: { /* TEQ */
DIP("teq r%u, r%u, %u", rs, rt, trap_code);
if (mode64) {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x35: { /* SELEQZ */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("seleqz r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
putIReg(rd, binop(Iop_And64,
unop(Iop_Not64,
unop(Iop_CmpwNEZ64, getIReg(rt))),
getIReg(rs)));
} else {
putIReg(rd, binop(Iop_And32,
unop(Iop_Not32,
unop(Iop_CmpwNEZ32, getIReg(rt))),
getIReg(rs)));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
}
case 0x36: { /* TNE */
DIP("tne r%u, r%u %u", rs, rt, trap_code);
if (mode64) {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpNE64, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpNE64, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpNE64, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
if (trap_code == 7)
stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntDiv,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else if (trap_code == 6)
stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
getIReg(rt)), Ijk_SigFPE_IntOvf,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
else
stmt(IRStmt_Exit(binop(Iop_CmpNE32, getIReg(rs),
getIReg(rt)), Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x37: { /* SELNEZ */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("selnez r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
putIReg(rd, binop(Iop_And64,
unop(Iop_CmpwNEZ64, getIReg(rt)), getIReg(rs)));
} else {
putIReg(rd, binop(Iop_And32,
unop(Iop_CmpwNEZ32, getIReg(rt)), getIReg(rs)));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
}
case 0x14:
case 0x16:
case 0x17: /* DSLLV, DROTRV:DSRLV, DSRAV */
case 0x38:
case 0x3A:
case 0x3B: /* DSLL, DROTL:DSRL, DSRA */
case 0x3C:
case 0x3E:
case 0x3F: /* DSLL32, DROTR32:DSRL32, DSRA32 */
if (dis_instr_shrt(cins))
break;
return -1;
default:
return -1;
}
return 0;
}
static UInt disInstr_MIPS_WRK_Special2(UInt cins, const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo, DisResult* dres,
IRStmt** bstmt, IRExpr** lastn)
{
IRTemp t0, t1 = 0, t2, t3, t4, t5, t6;
UInt rs, rt, rd, function;
/* Additional variables for instruction fields in DSP ASE insructions */
UInt ac;
rs = get_rs(cins);
rt = get_rt(cins);
rd = get_rd(cins);
function = get_function(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
ac = get_acNo(cins);
switch (function) {
/* Cavium Specific instructions */
case 0x03:
case 0x32:
case 0x33: /* DMUL, CINS , CINS32 */
case 0x3A:
case 0x3B:
case 0x2B: /* EXT, EXT32, SNE */
/* CVM Compare Instructions */
case 0x2A:
case 0x2E:
case 0x2F: /* SEQ, SEQI, SNEI */
/* CPU Load, Store, Memory, and Control Instructions */
case 0x18:
case 0x19: /* SAA, SAAD */
case 0x1F: /* LAA, LAAD, LAI, LAID */
case 0x28:
case 0x2C:
case 0x2D: /* BADDU, POP, DPOP */
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
if (dis_instr_CVM(cins))
break;
return -1;
} else {
return -1;
}
break;
case 0x02: { /* MUL */
DIP("mul r%u, r%u, r%u", rd, rs, rt);
if (mode64) {
IRTemp tmpRs32 = newTemp(Ity_I32);
IRTemp tmpRt32 = newTemp(Ity_I32);
IRTemp tmpRes = newTemp(Ity_I32);
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt)));
assign(tmpRes, binop(Iop_Mul32,
mkexpr(tmpRs32), mkexpr(tmpRt32)));
putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpRes), True));
} else
putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
break;
}
case 0x00: { /* MADD */
if (mode64) {
DIP("madd r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
t6 = newTemp(Ity_I32);
assign(t1, mkNarrowTo32(ty, getHI()));
assign(t2, mkNarrowTo32(ty, getLO()));
assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2)));
assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4)));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
} else {
if ( (1 <= ac) && ( 3 >= ac) ) {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MADD */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
} else {
DIP("madd r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
t6 = newTemp(Ity_I32);
assign(t1, getHI());
assign(t2, getLO());
assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
mkexpr(t3))));
assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
unop(Iop_64to32, mkexpr(t3)))));
assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32,
mkexpr(t3))));
putLO(mkexpr(t4));
break;
}
}
break;
}
case 0x01: { /* MADDU */
if (mode64) {
DIP("maddu r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
t6 = newTemp(Ity_I32);
assign(t1, mkNarrowTo32(ty, getHI()));
assign(t2, mkNarrowTo32(ty, getLO()));
assign(t3, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2)));
assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4)));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
} else {
if ( (1 <= ac) && ( 3 >= ac) ) {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MADDU */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
} else {
DIP("maddu r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
t6 = newTemp(Ity_I32);
assign(t1, getHI());
assign(t2, getLO());
assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
mkexpr(t3))));
assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
unop(Iop_64to32, mkexpr(t3)))));
assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32,
mkexpr(t3))));
putLO(mkexpr(t4));
break;
}
}
break;
}
case 0x04: { /* MSUB */
if (mode64) {
DIP("msub r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
t6 = newTemp(Ity_I32);
assign(t1, mkNarrowTo32(ty, getHI()));
assign(t2, mkNarrowTo32(ty, getLO()));
assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
mkNarrowTo32(ty, getIReg(rt))));
assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2)));
assign(t5, binop(Iop_Sub64, mkexpr(t4), mkexpr(t3)));
putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t5)), True));
putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t5)), True));
} else {
if ( (1 <= ac) && ( 3 >= ac) ) {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MSUB */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
} else {
DIP("msub r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I1);
t6 = newTemp(Ity_I32);
assign(t1, getHI());
assign(t2, getLO());
assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */
/* if lo= ac) ) {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
/* If DSP is present -> DSP ASE MSUBU */
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
} else {
DIP("msubu r%u, r%u", rs, rt);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I1);
t6 = newTemp(Ity_I32);
assign(t1, getHI());
assign(t2, getLO());
assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */
/* if lo= 32 && srcPos < 64);
vassert(dstSz > 0 && dstSz <= 32);
vassert((srcPos + dstSz) > 32 && (srcPos + dstSz) <= 64);
UChar lsAmt = 64 - (srcPos + dstSz); /* left shift amount; */
UChar rsAmt = 64 - dstSz; /* right shift amount; */
assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt)));
putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt)));
break;
}
case 0x05: { /* Doubleword Insert Bit Field Middle - DINSM; MIPS64r2 */
msb = get_msb(cins);
lsb = get_lsb(cins);
size = msb + 1;
UInt dstPos = lsb;
UInt srcSz = msb - lsb + 33;
t1 = newTemp(ty);
t2 = newTemp(ty);
t3 = newTemp(ty);
t4 = newTemp(ty);
IRTemp tmpT1 = newTemp(ty);
IRTemp tmpT2 = newTemp(ty);
IRTemp tmpT3 = newTemp(ty);
IRTemp tmpT4 = newTemp(ty);
IRTemp tmpT5 = newTemp(ty);
IRTemp tmpT6 = newTemp(ty);
IRTemp tmpT7 = newTemp(ty);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp tmpRd = newTemp(ty);
assign(tmpRs, getIReg(rs));
assign(tmpRt, getIReg(rt));
DIP("dinsm r%u, r%u, %u, %u", rt, rs, lsb, msb);
UChar lsAmt = dstPos + srcSz - 1; /* left shift amount; */
UChar rsAmt = dstPos + srcSz - 1; /* right shift amount; */
assign(t1, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(rsAmt)));
assign(tmpT1, binop(Iop_Shr64, mkexpr(t1), mkU8(1)));
assign(t2, binop(Iop_Shl64, mkexpr(tmpT1), mkU8(lsAmt)));
assign(tmpT2, binop(Iop_Shl64, mkexpr(t2), mkU8(1)));
lsAmt = 63 - dstPos; /* left shift amount; */
rsAmt = 63 - dstPos; /* right shift amount; */
assign(t3, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(lsAmt)));
assign(tmpT3, binop(Iop_Shl64, mkexpr(t3), mkU8(1)));
assign(t4, binop(Iop_Shr64, mkexpr(tmpT3), mkU8(rsAmt)));
assign(tmpT4, binop(Iop_Shr64, mkexpr(t4), mkU8(1)));
/* extract size from src register */
lsAmt = 64 - srcSz; /* left shift amount; */
rsAmt = 64 - (lsb + srcSz); /* right shift amount; */
assign(tmpT5, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
assign(tmpT6, binop(Iop_Shr64, mkexpr(tmpT5), mkU8(rsAmt)));
assign(tmpT7, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT4)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT6), mkexpr(tmpT7)));
putIReg(rt, mkexpr(tmpRd));
break;
}
case 0x06: { /* Doubleword Insert Bit Field Upper - DINSU; MIPS64r2 */
msb = get_msb(cins);
lsb = get_lsb(cins);
size = msb + 1;
UInt dstPos = lsb + 32;
UInt srcSz = msb - lsb + 1;
IRTemp tmpT1 = newTemp(ty);
IRTemp tmpT2 = newTemp(ty);
IRTemp tmpT3 = newTemp(ty);
IRTemp tmpT4 = newTemp(ty);
IRTemp tmpT5 = newTemp(ty);
IRTemp tmpT6 = newTemp(ty);
IRTemp tmpT7 = newTemp(ty);
IRTemp tmpT8 = newTemp(ty);
IRTemp tmpT9 = newTemp(ty);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp tmpRd = newTemp(ty);
assign(tmpRs, getIReg(rs));
assign(tmpRt, getIReg(rt));
DIP("dinsu r%u, r%u, %u, %u", rt, rs, lsb, msb);
UChar lsAmt = 64 - srcSz; /* left shift amount; */
UChar rsAmt = 64 - (dstPos + srcSz); /* right shift amount; */
assign(tmpT1, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(rsAmt)));
lsAmt = 64 - dstPos; /* left shift amount; */
rsAmt = 64 - dstPos; /* right shift amount; */
assign(tmpT3, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(lsAmt)));
assign(tmpT4, binop(Iop_Shr64, mkexpr(tmpT3), mkU8(rsAmt)));
lsAmt = dstPos; /* left shift amount; */
rsAmt = srcSz; /* right shift amount; */
assign(tmpT5, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(rsAmt)));
assign(tmpT6, binop(Iop_Shr64, mkexpr(tmpT5), mkU8(lsAmt)));
assign(tmpT7, binop(Iop_Shl64, mkexpr(tmpT6), mkU8(rsAmt)));
assign(tmpT8, binop(Iop_Shl64, mkexpr(tmpT7), mkU8(lsAmt)));
assign(tmpT9, binop(Iop_Or64, mkexpr(tmpT8), mkexpr(tmpT4)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT9)));
putIReg(rt, mkexpr(tmpRd));
break;
}
case 0x07: { /* Doubleword Insert Bit Field - DINS; MIPS64r2 */
IRTemp tmp1 = newTemp(ty);
IRTemp tmpT1 = newTemp(ty);
IRTemp tmpT2 = newTemp(ty);
IRTemp tmpT3 = newTemp(ty);
IRTemp tmpT4 = newTemp(ty);
IRTemp tmpT5 = newTemp(ty);
IRTemp tmpT6 = newTemp(ty);
IRTemp tmpT7 = newTemp(ty);
IRTemp tmpT8 = newTemp(ty);
IRTemp tmpT9 = newTemp(ty);
IRTemp tmp = newTemp(ty);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp tmpRd = newTemp(ty);
assign(tmpRs, getIReg(rs));
assign(tmpRt, getIReg(rt));
msb = get_msb(cins);
lsb = get_lsb(cins);
size = msb + 1;
DIP("dins r%u, r%u, %u, %u", rt, rs, lsb,
msb - lsb + 1);
UChar lsAmt = 63 - lsb; /* left shift amount; */
UChar rsAmt = 63 - lsb; /* right shift amount; */
assign(tmp, binop(Iop_Shl64, mkexpr(tmpRt), mkU8(lsAmt)));
assign(tmpT1, binop(Iop_Shl64, mkexpr(tmp), mkU8(1)));
assign(tmp1, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(rsAmt)));
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmp1), mkU8(1)));
lsAmt = msb; /* left shift amount; */
rsAmt = 1; /*right shift amount; */
assign(tmpT3, binop(Iop_Shr64, mkexpr(tmpRt), mkU8(rsAmt)));
assign(tmpT4, binop(Iop_Shr64, mkexpr(tmpT3), mkU8(lsAmt)));
assign(tmpT5, binop(Iop_Shl64, mkexpr(tmpT4), mkU8(rsAmt)));
assign(tmpT6, binop(Iop_Shl64, mkexpr(tmpT5), mkU8(lsAmt)));
lsAmt = 64 - (msb - lsb + 1); /* left shift amount; */
rsAmt = 64 - (msb + 1); /* right shift amount; */
assign(tmpT7, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt)));
assign(tmpT8, binop(Iop_Shr64, mkexpr(tmpT7), mkU8(rsAmt)));
assign(tmpT9, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT8)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT6), mkexpr(tmpT9)));
putIReg(rt, mkexpr(tmpRd));
break;
}
case 0x24: /* DBSHFL */
lsb = get_lsb(cins);
IRTemp tmpRs = newTemp(ty);
IRTemp tmpRt = newTemp(ty);
IRTemp tmpRd = newTemp(ty);
assign(tmpRs, getIReg(rs));
assign(tmpRt, getIReg(rt));
switch (lsb) {
case 0x02: { /* DSBH */
DIP("dsbh r%u, r%u", rd, rt);
IRTemp tmpT1 = newTemp(ty);
IRTemp tmpT2 = newTemp(ty);
IRTemp tmpT3 = newTemp(ty);
IRTemp tmpT4 = newTemp(ty);
IRTemp tmpT5 = newTemp(Ity_I64);
IRTemp tmpT6 = newTemp(ty);
assign(tmpT5, mkU64(0xFF00FF00FF00FF00ULL));
assign(tmpT6, mkU64(0x00FF00FF00FF00FFULL));
assign(tmpT1, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT5)));
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(8)));
assign(tmpT3, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT6)));
assign(tmpT4, binop(Iop_Shl64, mkexpr(tmpT3), mkU8(8)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT4), mkexpr(tmpT2)));
putIReg(rd, mkexpr(tmpRd));
break;
}
case 0x05: { /* DSHD */
DIP("dshd r%u, r%u\n", rd, rt);
IRTemp tmpT1 = newTemp(ty);
IRTemp tmpT2 = newTemp(ty);
IRTemp tmpT3 = newTemp(ty);
IRTemp tmpT4 = newTemp(ty);
IRTemp tmpT5 = newTemp(Ity_I64);
IRTemp tmpT6 = newTemp(ty);
IRTemp tmpT7 = newTemp(ty);
IRTemp tmpT8 = newTemp(ty);
IRTemp tmpT9 = newTemp(ty);
assign(tmpT5, mkU64(0xFFFF0000FFFF0000ULL));
assign(tmpT6, mkU64(0x0000FFFF0000FFFFULL));
assign(tmpT1, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT5)));
assign(tmpT2, binop(Iop_Shr64, mkexpr(tmpT1), mkU8(16)));
assign(tmpT3, binop(Iop_And64, mkexpr(tmpRt), mkexpr(tmpT6)));
assign(tmpT4, binop(Iop_Shl64, mkexpr(tmpT3), mkU8(16)));
assign(tmpT7, binop(Iop_Or64, mkexpr(tmpT4), mkexpr(tmpT2)));
assign(tmpT8, binop(Iop_Shl64, mkexpr(tmpT7), mkU8(32)));
assign(tmpT9, binop(Iop_Shr64, mkexpr(tmpT7), mkU8(32)));
assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT8), mkexpr(tmpT9)));
putIReg(rd, mkexpr(tmpRd));
break;
}
case 0x08 ... 0x0f: { /* DALIGN */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dalign r%u, r%u, r%u, %u", rd, rs, rt, lsb & 0x7);
UInt bp = (lsb & 0x7) << 3;
if (bp) {
putIReg(rd, binop(Iop_Or64,
binop(Iop_Shl64, getIReg(rt), mkU8(bp)),
binop(Iop_Shr64,
getIReg(rs), mkU8(64 - bp))));
} else
putIReg(rd, getIReg(rt));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
case 0: /* DBITSWAP */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dbitswap r%u, r%u", rd, rt);
putIReg(rd, qop(Iop_Rotx64, getIReg(rt), mkU8(7), mkU8(8), mkU8(1)));
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;;
}
break;
case 0x3B: /* RDHWR */
DIP("rdhwr r%u, r%u", rt, rd);
if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps) ||
VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) ||
(VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_BROADCOM)) {
if (rd == 29) {
putIReg(rt, getULR());
} else if (rd <= 3
|| (rd == 31
&& VEX_MIPS_COMP_ID(archinfo->hwcaps)
== VEX_PRID_COMP_CAVIUM)) {
IRExpr** arg = mkIRExprVec_1(mkU32(rd));
IRTemp val = newTemp(ty);
IRDirty *d = unsafeIRDirty_1_N(val,
0,
"mips_dirtyhelper_rdhwr",
&mips_dirtyhelper_rdhwr,
arg);
stmt(IRStmt_Dirty(d));
putIReg(rt, mkexpr(val));
} else
return -1;
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x04: /* INS */
msb = get_msb(cins);
lsb = get_lsb(cins);
size = msb - lsb + 1;
DIP("ins size:%u msb:%u lsb:%u", size, msb, lsb);
vassert(lsb + size <= 32);
vassert(lsb + size > 0);
/* put size bits from rs at the pos in temporary */
t0 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
/* shift left for 32 - size to clear leading bits and get zeros
at the end */
assign(t0, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rs)),
mkU8(32 - size)));
/* now set it at pos */
t1 = newTemp(Ity_I32);
assign(t1, binop(Iop_Shr32, mkexpr(t0), mkU8(32 - size - lsb)));
if (lsb > 0) {
t2 = newTemp(Ity_I32);
/* clear everything but lower pos bits from rt */
assign(t2, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rt)),
mkU8(32 - lsb)));
assign(t3, binop(Iop_Shr32, mkexpr(t2), mkU8(32 - lsb)));
} else
assign(t3, mkU32(0));
if (msb < 31) {
t4 = newTemp(Ity_I32);
/* clear everything but upper msb + 1 bits from rt */
assign(t4, binop(Iop_Shr32, mkNarrowTo32(ty, getIReg(rt)),
mkU8(msb + 1)));
t5 = newTemp(Ity_I32);
assign(t5, binop(Iop_Shl32, mkexpr(t4), mkU8(msb + 1)));
/* now combine these registers */
if (lsb > 0) {
t6 = newTemp(Ity_I32);
assign(t6, binop(Iop_Or32, mkexpr(t5), mkexpr(t1)));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t6),
mkexpr(t3)), True));
} else {
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t1),
mkexpr(t5)), True));
}
} else {
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t1),
mkexpr(t3)), True));
}
break;
case 0x00: /* EXT */
msb = get_msb(cins);
lsb = get_lsb(cins);
size = msb + 1;
DIP("ext size:%u msb:%u lsb:%u", size, msb, lsb);
vassert(lsb + size <= 32);
vassert(lsb + size > 0);
/* put size bits from rs at the top of in temporary */
if (lsb + size < 32) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_Shl32, mkNarrowTo32(ty, getIReg(rs)),
mkU8(32 - lsb - size)));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Shr32, mkexpr(t0),
mkU8(32 - size)), True));
} else {
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Shr32,
mkNarrowTo32(ty, getIReg(rs)),
mkU8(32 - size)), True));
}
break;
case 0x03: /* Doubleword Extract Bit Field - DEXT; MIPS64r2 */
msb = get_msb(cins);
lsb = get_lsb(cins);
size = msb + 1;
DIP("dext r%u, r%u, %u, %u", rt, rs, lsb, msb + 1);
t1 = newTemp(Ity_I64);
vassert(lsb >= 0 && lsb < 32);
vassert(size > 0 && size <= 32);
vassert((lsb + size) > 0 && (lsb + size) <= 63);
UChar lsAmt = 63 - (lsb + msb); /* left shift amount; */
UChar rsAmt = 63 - msb; /* right shift amount; */
assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt)));
putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt)));
break;
case 0x20: /* BSHFL */
switch (sa) {
case 0x0: /* BITSWAP */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("bitswap r%u, r%u", rd, rt);
if (mode64) {
putIReg(rd, unop(Iop_32Uto64, qop(Iop_Rotx32, unop(Iop_64to32, getIReg(rt)),
mkU8(7), mkU8(8), mkU8(1))));
} else {
putIReg(rd, qop(Iop_Rotx32, getIReg(rt), mkU8(7),
mkU8(8), mkU8(1)));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x02: /* WSBH */
DIP("wsbh r%u, r%u", rd, rt);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
assign(t0, binop(Iop_Shl32, binop(Iop_And32, mkNarrowTo32(ty,
getIReg(rt)), mkU32(0x00FF0000)),
mkU8(0x8)));
assign(t1, binop(Iop_Shr32, binop(Iop_And32, mkNarrowTo32(ty,
getIReg(rt)), mkU32(0xFF000000)), mkU8(0x8)));
assign(t2, binop(Iop_Shl32, binop(Iop_And32, mkNarrowTo32(ty,
getIReg(rt)), mkU32(0x000000FF)), mkU8(0x8)));
assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkNarrowTo32(ty,
getIReg(rt)), mkU32(0x0000FF00)), mkU8(0x8)));
putIReg(rd, mkWidenFrom32(ty, binop(Iop_Or32, binop(Iop_Or32,
mkexpr(t0), mkexpr(t1)),
binop(Iop_Or32, mkexpr(t2),
mkexpr(t3))), True));
break;
case 0x10: /* SEB */
DIP("seb r%u, r%u", rd, rt);
if (mode64)
putIReg(rd, unop(Iop_8Sto64, unop(Iop_64to8, getIReg(rt))));
else
putIReg(rd, unop(Iop_8Sto32, unop(Iop_32to8, getIReg(rt))));
break;
case 0x18: /* SEH */
DIP("seh r%u, r%u", rd, rt);
if (mode64)
putIReg(rd, unop(Iop_16Sto64, unop(Iop_64to16, getIReg(rt))));
else
putIReg(rd, unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt))));
break;
case 0x08 ... 0x0b: /* ALIGN */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (mode64) {
UInt bp = (sa & 0x3) << 3;
if (bp) {
putIReg(rd, unop(Iop_32Sto64,
binop(Iop_Or32,
binop(Iop_Shl32,
unop(Iop_64to32,
getIReg(rt)),
mkU8(bp)),
binop(Iop_Shr32,
unop(Iop_64to32,
getIReg(rs)),
mkU8(32 - bp)))));
} else
putIReg(rd, getIReg(rt));
} else {
UInt bp = (sa & 0x3) << 3;
if (bp) {
putIReg(rd, binop(Iop_Or32,
binop(Iop_Shl32,
getIReg(rt), mkU8(bp)),
binop(Iop_Shr32,
getIReg(rs), mkU8(32 - bp))));
} else
putIReg(rd, getIReg(rt));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
default:
return -1;
}
break; /* BSHFL */
/* --- MIPS32(r2) DSP ASE(r2) / Cavium Specfic (LX) instructions --- */
case 0xA: /* LX */
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
if (dis_instr_CVM(cins))
break;
return -1;
}
/* fallthrough */
case 0xC: /* INSV */
case 0x38: { /* EXTR.W */
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
case 0x10: { /* ADDU.QB */
switch (sa) {
case 0xC: /* SUBU_S.PH */
case 0xD: /* ADDU_S.PH */
case 0x1E: { /* MULQ_S.PH */
if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
default: {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
}
break;
}
case 0x11: { /* CMPU.EQ.QB */
switch (sa) {
case 0x18: /* CMPGDU.EQ.QB */
case 0x19: /* CMPGDU.LT.QB */
case 0x1A: /* CMPGDU.LE.QB */
case 0x0D: /* PRECR.QB.PH */
case 0x1E: /* PRECR_SRA.PH.W */
case 0x1F: { /* PRECR_SRA_R.PH.W */
if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
default: {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
}
break;
}
case 0x12: { /* ABSQ_S.PH */
switch (sa) {
case 0x1: { /* ABSQ_S.QB */
if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
default: {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
}
break;
}
case 0x13: { /* SHLL.QB */
switch (sa) {
case 0x04: /* SHRA.QB */
case 0x05: /* SHRA_R.QB */
case 0x06: /* SHRAV.QB */
case 0x07: /* SHRAV_R.QB */
case 0x19: /* SHLR.PH */
case 0x1B: { /* SHLRV.PH */
if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
default: {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
}
break;
}
case 0x30: { /* DPAQ.W.PH */
switch (sa) {
case 0x0: /* DPA.W.PH */
case 0x18: /* DPAQX_S.W.PH */
case 0x1A: /* DPAQX_SA.W.PH */
case 0x8: /* DPAX.W.PH */
case 0x1: /* DPS.W.PH */
case 0x19: /* DPSQX_S.W.PH */
case 0x1B: /* DPSQX_SA.W.PH */
case 0x9: /* DPSX.W.PH */
case 0x2: { /* MULSA.W.PH */
if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
default: {
if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
break;
}
}
break;
}
case 0x18: /* ADDUH.QB/MUL.PH */
case 0x31: { /* APPEND */
if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) {
UInt retVal = disDSPInstr_MIPS_WRK ( cins );
if (0 != retVal ) {
return -2;
}
break;
} else {
return -2;
}
}
case 0x35: { /* PREF r6*/
DIP("pref");
break;
}
case 0x36: { /* LL */
imm = extend_s_9to16((instr_index >> 7) & 0x1ff);
DIP("ll r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
t2 = newTemp(ty);
assign(t2, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True));
putLLaddr(mkexpr(t1));
putLLdata(mkexpr(t2));
putIReg(rt, mkexpr(t2));
break;
}
case 0x26: { /* SC */
imm = extend_s_9to16((instr_index >> 7) & 0x1ff);
DIP("sc r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
t2 = newTemp(Ity_I1);
t3 = newTemp(Ity_I32);
assign(t2, binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
mkexpr(t1), getLLaddr()));
assign(t3, mkNarrowTo32(ty, getIReg(rt)));
putLLaddr(LLADDR_INVALID);
putIReg(rt, getIReg(0));
mips_next_insn_if(mkexpr(t2));
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
assign(t5, mkNarrowTo32(ty, getLLdata()));
stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */
MIPS_IEND, mkexpr(t1), /* addr */
NULL, mkexpr(t5), /* expected value */
NULL, mkexpr(t3) /* new value */)));
putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32,
binop(Iop_CmpEQ32, mkexpr(t4), mkexpr(t5))));
break;
}
case 0x37: { /* LLD */
imm = extend_s_9to16((instr_index >> 7) & 0x1ff);
DIP("lld r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
t2 = newTemp(Ity_I64);
assign(t2, load(Ity_I64, mkexpr(t1)));
putLLaddr(mkexpr(t1));
putLLdata(mkexpr(t2));
putIReg(rt, mkexpr(t2));
break;
}
case 0x27: { /* SCD */
imm = extend_s_9to16((instr_index >> 7) & 0x1ff);
DIP("sdc r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
t2 = newTemp(Ity_I1);
t3 = newTemp(Ity_I64);
assign(t2, binop(Iop_CmpNE64, mkexpr(t1), getLLaddr()));
assign(t3, getIReg(rt));
putLLaddr(LLADDR_INVALID);
putIReg(rt, getIReg(0));
mips_next_insn_if(mkexpr(t2));
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
assign(t5, getLLdata());
stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */
MIPS_IEND, mkexpr(t1), /* addr */
NULL, mkexpr(t5), /* expected value */
NULL, mkexpr(t3) /* new value */)));
putIReg(rt, unop(Iop_1Uto64,
binop(Iop_CmpEQ64, mkexpr(t4), mkexpr(t5))));
break;
}
default:
return -1;
}
return 0;
}
static UInt disInstr_MIPS_WRK_00(UInt cins, const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo, DisResult* dres,
IRStmt** bstmt, IRExpr** lastn)
{
IRTemp t0;
UInt opcode, rs, rt, trap_code, imm, instr_index, p;
/* Additional variables for instruction fields in DSP ASE insructions */
opcode = get_opcode(cins);
imm = get_imm(cins);
rs = get_rs(cins);
rt = get_rt(cins);
instr_index = get_instr_index(cins);
trap_code = get_code(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
switch (opcode & 0x0F) {
case 0x00: /* Special */
return disInstr_MIPS_WRK_Special(cins, archinfo, abiinfo,
dres, bstmt, lastn);
case 0x01: /* Regimm */
switch (rt) {
case 0x00: /* BLTZ */
DIP("bltz r%u, %u", rs, imm);
if (mode64) {
if (!dis_instr_branch(cins, dres, bstmt))
return -1;
} else
dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
mkU32(0x80000000)), mkU32(0x80000000)), imm, bstmt);
break;
case 0x01: /* BGEZ */
DIP("bgez r%u, %u", rs, imm);
if (mode64) {
if (!dis_instr_branch(cins, dres, bstmt))
return -1;
} else
dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
mkU32(0x80000000)), mkU32(0x0)), imm, bstmt);
break;
case 0x02: /* BLTZL */
DIP("bltzl r%u, %u", rs, imm);
*lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
binop(mode64 ? Iop_And64 : Iop_And32, getIReg(rs),
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
imm);
break;
case 0x03: /* BGEZL */
DIP("bgezl r%u, %u", rs, imm);
*lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
binop(mode64 ? Iop_And64 : Iop_And32, getIReg(rs),
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
mode64 ? mkU64(0x0) : mkU32(0x0)), imm);
break;
case 0x06: { /* DAHI */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dahi r%u, %x", rs, imm);
putIReg(rs, binop(Iop_Add64,
getIReg(rs), mkU64(extend_s_16to64 (imm) << 32)));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
case 0x08: /* TGEI */
DIP("tgei r%u, %u %u", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64S,
getIReg (rs),
mkU64 (extend_s_16to64 (imm)))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32S,
getIReg (rs),
mkU32 (extend_s_16to32 (imm)))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
case 0x09: { /* TGEIU */
DIP("tgeiu r%u, %u %u", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT64U,
getIReg (rs),
mkU64 (extend_s_16to64 (imm)))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
stmt (IRStmt_Exit (unop (Iop_Not1,
binop (Iop_CmpLT32U,
getIReg (rs),
mkU32 (extend_s_16to32 (imm)))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x0A: { /* TLTI */
DIP("tlti r%u, %u %u", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (binop (Iop_CmpLT64S, getIReg (rs),
mkU64 (extend_s_16to64 (imm))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs),
mkU32 (extend_s_16to32 (imm))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x0B: { /* TLTIU */
DIP("tltiu r%u, %u %u", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (binop (Iop_CmpLT64U, getIReg (rs),
mkU64 (extend_s_16to64 (imm))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs),
mkU32 (extend_s_16to32 (imm))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x0C: { /* TEQI */
DIP("teqi r%u, %u %u", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (binop (Iop_CmpEQ64, getIReg (rs),
mkU64 (extend_s_16to64 (imm))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
stmt (IRStmt_Exit (binop (Iop_CmpEQ32, getIReg (rs),
mkU32 (extend_s_16to32 (imm))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x0E: { /* TNEI */
DIP("tnei r%u, %u %u", rs, imm, trap_code);
if (mode64) {
stmt (IRStmt_Exit (binop (Iop_CmpNE64, getIReg (rs),
mkU64 (extend_s_16to64 (imm))),
Ijk_SigTRAP,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
} else {
stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs),
mkU32 (extend_s_16to32 (imm))),
Ijk_SigTRAP,
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
}
break;
}
case 0x10: /* BLTZAL */
DIP("bltzal r%u, %u", rs, imm);
if (mode64) {
if (!dis_instr_branch(cins, dres, bstmt))
return -1;
} else
dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
mkU32(0x80000000)), mkU32(0x80000000)), imm, bstmt);
break;
case 0x11: /* BGEZAL */
DIP("bgezal r%u, %u", rs, imm);
if (mode64) {
if (!dis_instr_branch(cins, dres, bstmt))
return -1;
} else
dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
mkU32(0x80000000)), mkU32(0x0)), imm, bstmt);
break;
case 0x12: /* BLTZALL */
DIP("bltzall r%u, %u", rs, imm);
putIReg(31, mode64 ? mkU64(guest_PC_curr_instr + 8) :
mkU32(guest_PC_curr_instr + 8));
*lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
binop(mode64 ? Iop_And64 : Iop_And32, getIReg(rs),
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
mode64 ? mkU64(0x8000000000000000ULL) : mkU32(0x80000000)),
imm);
break;
case 0x13: /* BGEZALL */
DIP("bgezall r%u, %u", rs, imm);
if (mode64) {
putIReg(31, mkU64(guest_PC_curr_instr + 8));
*lastn = dis_branch_likely(binop(Iop_CmpNE64,
binop(Iop_And64,
getIReg(rs),
mkU64(0x8000000000000000ULL)),
mkU64(0x0)),
imm);
} else {
putIReg(31, mkU32(guest_PC_curr_instr + 8));
*lastn = dis_branch_likely(binop(Iop_CmpNE32, binop(Iop_And32,
getIReg(rs), mkU32(0x80000000)),
mkU32(0x0)), imm);
}
break;
case 0x1C: { /* BPOSGE32 */
DIP("bposge32 %u", imm);
vassert(!mode64);
t0 = newTemp(Ity_I32);
/* Get pos field from DSPControl register. */
assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f)));
dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLT32U, mkexpr(t0),
mkU32(32))), imm, bstmt);
break;
}
case 0x1E: { /* DATI */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("dati r%u, %x", rs, imm);
putIReg(rs, binop(Iop_Add64,
getIReg(rs), mkU64((long long)imm << 48)));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
case 0x1F: /* SYNCI */
/* Just ignore it */
break;
default:
return -1;
}
break;
case 0x02: /* J */
DIP("j 0x%x", instr_index);
t0 = newTemp(ty);
if (mode64)
assign(t0, mkU64((guest_PC_curr_instr & 0xFFFFFFFFF0000000ULL) |
(instr_index << 2)));
else
assign(t0, mkU32((guest_PC_curr_instr & 0xF0000000) |
(instr_index << 2)));
*lastn = mkexpr(t0);
break;
case 0x03: /* JAL */
DIP("jal 0x%x", instr_index);
if (mode64) {
putIReg(31, mkU64(guest_PC_curr_instr + 8));
t0 = newTemp(ty);
assign(t0, mkU64((guest_PC_curr_instr & 0xFFFFFFFFF0000000ULL) |
(instr_index << 2)));
} else {
putIReg(31, mkU32(guest_PC_curr_instr + 8));
t0 = newTemp(ty);
assign(t0, mkU32((guest_PC_curr_instr & 0xF0000000) |
(instr_index << 2)));
}
*lastn = mkexpr(t0);
break;
case 0x04: /* BEQ, B */
if (rs == 0 && rt == 0) {
ULong branch_offset;
t0 = newTemp(ty);
DIP("b %u", imm);
if (mode64) {
branch_offset = extend_s_18to64(imm << 2);
assign(t0, mkU64(guest_PC_curr_instr + 4 + branch_offset));
} else {
branch_offset = extend_s_18to32(imm << 2);
assign(t0, mkU32(guest_PC_curr_instr + 4 + branch_offset));
}
*lastn = mkexpr(t0);
} else {
DIP("beq r%u, r%u, %u", rs, rt, imm);
if (mode64)
dis_branch(False, binop(Iop_CmpEQ64, getIReg(rs), getIReg(rt)),
imm, bstmt);
else
dis_branch(False, binop(Iop_CmpEQ32, getIReg(rs), getIReg(rt)),
imm, bstmt);
}
break;
case 0x05: /* BNE */
DIP("bne r%u, r%u, %u", rs, rt, imm);
if (mode64)
dis_branch(False, binop(Iop_CmpNE64, getIReg(rs), getIReg(rt)),
imm, bstmt);
else
dis_branch(False, binop(Iop_CmpNE32, getIReg(rs), getIReg(rt)),
imm, bstmt);
break;
case 0x06: /* BLEZ, BLEZALC, BGEZALC, BGEUC */
if (rt == 0) { /* BLEZ */
DIP("blez r%u, %u", rs, imm);
if (mode64)
dis_branch(False, binop(Iop_CmpLE64S, getIReg(rs), mkU64(0x0)),
imm, bstmt);
else
dis_branch(False, binop(Iop_CmpLE32S, getIReg(rs), mkU32(0x0)), imm,
bstmt);
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (rs == 0) { /* BLEZALC */
DIP("blezalc r%u, %u", rt, imm);
if (mode64)
dis_branch_compact(True,
binop(Iop_CmpLE64S, getIReg(rt), mkU64(0x0)),
imm, dres);
else
dis_branch_compact(True,
binop(Iop_CmpLE32S, getIReg(rt), mkU32(0x0)),
imm, dres);
} else if (rt == rs) { /* BGEZALC */
DIP("bgezalc r%u, %u", rt, imm);
if (mode64)
dis_branch_compact(True,
binop(Iop_CmpLE64S, mkU64(0x0), getIReg(rt)),
imm, dres);
else
dis_branch_compact(True,
binop(Iop_CmpLE32S, mkU32(0x0), getIReg(rt)),
imm, dres);
} else { /* BGEUC */
DIP("bgeuc r%u, r%u, %u", rt, rs, imm);
if (mode64)
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLT64U,
getIReg(rs), getIReg(rt))),
imm, dres);
else
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLT32U,
getIReg(rs), getIReg(rt))),
imm, dres);
}
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x07: /* BGTZ, BGTZALC, BLTZALC, BLTUC */
if (rt == 0) { /* BGTZ */
DIP("bgtz r%u, %u", rs, imm);
if (mode64)
dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE64S, getIReg(rs),
mkU64(0x00))), imm, bstmt);
else
dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE32S, getIReg(rs),
mkU32(0x00))), imm, bstmt);
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (rs == 0) { /* BGTZALC */
DIP("bgtzalc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(True,
unop(Iop_Not1,
binop(Iop_CmpLE64S,
getIReg(rt), mkU64(0x0))),
imm, dres);
} else {
dis_branch_compact(True,
unop(Iop_Not1,
binop(Iop_CmpLE32S,
getIReg(rt), mkU32(0x0))),
imm, dres);
}
} else if (rs == rt) { /* BLTZALC */
DIP("bltzalc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(True,
unop(Iop_Not1,
binop(Iop_CmpLE64S,
mkU64(0x0), getIReg(rt))),
imm, dres);
} else {
dis_branch_compact(True,
unop(Iop_Not1,
binop(Iop_CmpLE32S,
mkU32(0x0), getIReg(rt))),
imm, dres);
}
} else { /* BLTUC */
DIP("bltuc r%u, r%u, %u", rt, rs, imm);
if (mode64) {
dis_branch_compact(False,
binop(Iop_CmpLT64U, getIReg(rs), getIReg(rt)),
imm, dres);
} else {
dis_branch_compact(False,
binop(Iop_CmpLT32U, getIReg(rs), getIReg(rt)),
imm, dres);
}
}
} else {
ILLEGAL_INSTRUCTON
}
break;
#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev < 6))
case 0x08: { /* ADDI */
DIP("addi r%u, r%u, %u", rt, rs, imm);
IRTemp tmpRs32, t1, t2, t3, t4;
tmpRs32 = newTemp(Ity_I32);
assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs)));
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
/* dst = src0 + sign(imm)
if(sign(src0 ) != sign(imm ))
goto no overflow;
if(sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32),
mkU32(extend_s_16to32(imm))));
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32),
mkU32(extend_s_16to32(imm))));
assign(t2, unop(Iop_1Sto32, binop(Iop_CmpEQ32, binop(Iop_And32,
mkexpr(t1), mkU32(0x80000000)), mkU32(0x80000000))));
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
assign(t4, unop(Iop_1Sto32, binop(Iop_CmpNE32, binop(Iop_And32,
mkexpr(t3), mkU32(0x80000000)), mkU32(0x80000000))));
stmt(IRStmt_Exit(binop(Iop_CmpEQ32, binop(Iop_Or32, mkexpr(t2),
mkexpr(t4)), mkU32(0)), Ijk_SigFPE_IntOvf,
mode64 ? IRConst_U64(guest_PC_curr_instr + 4) :
IRConst_U32(guest_PC_curr_instr + 4),
OFFB_PC));
putIReg(rt, mkWidenFrom32(ty, mkexpr(t0), True));
break;
}
#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6))
case 0x08: { /* BEQZALC, BEQC, BOVC */
IRTemp t1, t2, t3, t4;
if (rs == 0) { /* BEQZALC */
DIP("beqzalc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(True,
binop(Iop_CmpEQ64, getIReg(rt), mkU64(0x0)),
imm, dres);
} else {
dis_branch_compact(True,
binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x0)),
imm, dres);
}
} else if (rs < rt) { /* BEQC */
DIP("beqc r%u, r%u, %u", rs, rt, imm);
if (mode64) {
dis_branch_compact(False,
binop(Iop_CmpEQ64, getIReg(rt), getIReg(rs)),
imm, dres);
} else {
dis_branch_compact(False,
binop(Iop_CmpEQ32, getIReg(rt), getIReg(rs)),
imm, dres);
}
} else { /* BOVC */
DIP("bovc r%u, r%u, %u", rs, rt, imm);
if (mode64) {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
assign(t0, IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rt),
mkU64(0xffffffff80000000ULL)),
mkU32(1),
IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rt),
mkU64(0x7FFFFFFFULL)),
mkU32(0), mkU32(1))));
assign(t1, IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rs),
mkU64(0xffffffff80000000ULL)),
mkU32(1),
IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rs),
mkU64(0x7FFFFFFFULL)),
mkU32(0), mkU32(1))));
assign(t2, IRExpr_ITE(binop(Iop_CmpLT64S,
binop(Iop_Add64,
getIReg(rt), getIReg(rs)),
mkU64(0xffffffff80000000ULL)),
mkU32(1),
IRExpr_ITE(binop(Iop_CmpLT64S,
binop(Iop_Add64,
getIReg(rt),
getIReg(rs)),
mkU64(0x7FFFFFFFULL)),
mkU32(0), mkU32(1))));
assign(t3, binop(Iop_Add32,
mkexpr(t0),
binop(Iop_Add32, mkexpr(t1), mkexpr(t2))));
dis_branch_compact(False,
binop(Iop_CmpNE32, mkexpr(t3), mkU32(0)),
imm, dres);
} else {
IRTemp tmpRs32 = newTemp(Ity_I32);
IRTemp tmpRt32 = newTemp(Ity_I32);
assign(tmpRs32, getIReg(rs));
assign(tmpRt32, getIReg(rt));
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
/* dst = src0 + src1
if (sign(src0 ) != sign(src1 ))
goto no overflow;
if (sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
assign(t2, unop(Iop_1Uto32,
binop(Iop_CmpEQ32,
binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
mkU32(0x80000000))));
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
assign(t4, unop(Iop_1Uto32,
binop(Iop_CmpNE32,
binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
mkU32(0x80000000))));
dis_branch_compact(False, binop(Iop_CmpEQ32,
binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
mkU32(0)), imm, dres);
}
}
break;
/* In documentation for BEQC stands rs > rt and for BOVC stands rs >= rt! */
}
#endif
case 0x09: /* ADDIU */
DIP("addiu r%u, r%u, %u", rt, rs, imm);
if (mode64) {
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Add32,
mkNarrowTo32(ty, getIReg(rs)), mkU32(extend_s_16to32(imm))),
True));
} else
putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
break;
case 0x0A: /* SLTI */
DIP("slti r%u, r%u, %u", rt, rs, imm);
if (mode64)
putIReg(rt, unop(Iop_1Uto64, binop(Iop_CmpLT64S, getIReg(rs),
mkU64(extend_s_16to64(imm)))));
else
putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
mkU32(extend_s_16to32(imm)))));
break;
case 0x0B: /* SLTIU */
DIP("sltiu r%u, r%u, %u", rt, rs, imm);
if (mode64)
putIReg(rt, unop(Iop_1Uto64, binop(Iop_CmpLT64U, getIReg(rs),
mkU64(extend_s_16to64(imm)))));
else
putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
mkU32(extend_s_16to32(imm)))));
break;
case 0x0C: /* ANDI */
DIP("andi r%u, r%u, %u", rt, rs, imm);
if (mode64) {
ALUI_PATTERN64(Iop_And64);
} else {
ALUI_PATTERN(Iop_And32);
}
break;
case 0x0D: /* ORI */
DIP("ori r%u, r%u, %u", rt, rs, imm);
if (mode64) {
ALUI_PATTERN64(Iop_Or64);
} else {
ALUI_PATTERN(Iop_Or32);
}
break;
case 0x0E: /* XORI */
DIP("xori r%u, r%u, %u", rt, rs, imm);
if (mode64) {
ALUI_PATTERN64(Iop_Xor64);
} else {
ALUI_PATTERN(Iop_Xor32);
}
break;
case 0x0F: /* LUI */
if (rs == 0) {
p = (imm << 16);
DIP("lui r%u, imm: 0x%x", rt, imm);
if (mode64)
putIReg(rt, mkU64(extend_s_32to64(p)));
else
putIReg(rt, mkU32(p));
break;
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { /* AUI */
DIP("aui r%u, imm: 0x%x", rt, imm);
if (mode64) {
putIReg(rt, unop(Iop_32Sto64,
unop(Iop_64to32,
binop(Iop_Add64,
getIReg(rs),
mkU64(extend_s_32to64(imm << 16))))));
} else {
putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(imm << 16)));
}
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;
}
return 0;
}
static UInt disInstr_MIPS_WRK_10(UInt cins, const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo, DisResult* dres,
IRStmt** bstmt, IRExpr** lastn)
{
IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7;
UInt opcode, rs, rt, ft, fs, fd, fmt, tf, nd, function, imm;
/* Additional variables for instruction fields in DSP ASE insructions */
opcode = get_opcode(cins);
imm = get_imm(cins);
rs = get_rs(cins);
rt = get_rt(cins);
fs = get_fs(cins);
fd = get_fd(cins);
ft = get_ft(cins);
tf = get_tf(cins);
nd = get_nd(cins);
fmt = get_fmt(cins);
function = get_function(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
IRType tyF = fp_mode64 ? Ity_F64 : Ity_F32;
switch (opcode & 0x0F) {
case 0x01: { /* COP1 */
if (fmt == 0x3 && fd == 0 && function == 0) { /* MFHC1 */
DIP("mfhc1 r%u, f%u", rt, fs);
if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps) ||
VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
assign(t0, unop(Iop_ReinterpF64asI64, getDReg(fs)));
assign(t1, unop(Iop_64HIto32, mkexpr(t0)));
putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
} else {
putIReg(rt, mkWidenFrom32(ty, unop(Iop_ReinterpF32asI32,
getFReg(fs | 1)), True));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if (fmt == 0x7 && fd == 0 && function == 0) { /* MTHC1 */
DIP("mthc1 r%u, f%u", rt, fs);
if (VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps) ||
VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (fp_mode64) {
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_32HLto64, mkNarrowTo32(ty, getIReg(rt)),
unop(Iop_ReinterpF32asI32,
getLoFromF64(Ity_F64, getDReg(fs)))));
putDReg(fs, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
} else {
putFReg(fs | 1, unop(Iop_ReinterpI32asF32,
mkNarrowTo32(ty, getIReg(rt))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if (fmt == 0x8) { /* BC */
/* FcConditionalCode(bc1_cc) */
UInt bc1_cc = get_bc1_cc(cins);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(bc1_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(), mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + bc1_cc)),
mkU32(0x1))));
if (tf == 1 && nd == 0) {
/* branch on true */
DIP("bc1t %u, %u", bc1_cc, imm);
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
dis_branch(False, mkexpr(t3), imm, bstmt);
break;
} else if (tf == 0 && nd == 0) {
/* branch on false */
DIP("bc1f %u, %u", bc1_cc, imm);
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
dis_branch(False, mkexpr(t3), imm, bstmt);
break;
} else if (nd == 1 && tf == 0) {
DIP("bc1fl %u, %u", bc1_cc, imm);
*lastn = dis_branch_likely(binop(Iop_CmpNE32, mkexpr(t2),
mkU32(0x0)), imm);
break;
} else if (nd == 1 && tf == 1) {
DIP("bc1tl %u, %u", bc1_cc, imm);
*lastn = dis_branch_likely(binop(Iop_CmpEQ32, mkexpr(t2),
mkU32(0x0)), imm);
break;
} else
return -1;
} else if (fmt >= 0x1c && has_msa) { /* BNZ.df */
Int df = fmt & 3;
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ft));
assign(t2, binop(Iop_64HLtoV128, mkU64(0), mkU64(0)));
switch (df) {
case 0x00: { /* BNZ.B */
DIP("BNZ.B w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x01: { /* BNZ.H */
DIP("BNZ.H w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x02: { /* BNZ.W */
DIP("BNZ.W w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x03: { /* BNZ.D */
DIP("BNZ.D w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
break;
}
}
assign(t0,
binop(Iop_Or32,
binop(Iop_Or32,
unop(Iop_V128to32, mkexpr(t3)),
unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t3)))),
binop(Iop_Or32,
unop(Iop_64to32,
unop(Iop_V128HIto64, mkexpr(t3))),
unop(Iop_64HIto32,
unop(Iop_V128HIto64, mkexpr(t3))))));
dis_branch(False,
binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0)), imm, bstmt);
} else if (fmt == 0x0F && has_msa) { /* BNZ.V */
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_V128);
assign(t1, getWReg(ft));
assign(t0,
binop(Iop_Or32,
binop(Iop_Or32,
unop(Iop_V128to32, mkexpr(t1)),
unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t1)))),
binop(Iop_Or32,
unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(t1))),
unop(Iop_64HIto32,
unop(Iop_V128HIto64, mkexpr(t1))))));
dis_branch(False,
binop(Iop_CmpNE32, mkexpr(t0), mkU32(0)), imm, bstmt);
} else if (fmt >= 0x18 && has_msa) { /* BZ.df */
Int df = fmt & 3;
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_V128);
t2 = newTemp(Ity_V128);
t3 = newTemp(Ity_V128);
assign(t1, getWReg(ft));
assign(t2, binop(Iop_64HLtoV128, mkU64(0), mkU64(0)));
switch (df) {
case 0x00: { /* BZ.B */
DIP("BZ.B w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x01: { /* BZ.H */
DIP("BZ.H w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x02: { /* BZ.W */
DIP("BZ.W w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2)));
break;
}
case 0x03: { /* BZ.D */
DIP("BZ.D w%u, %u", ft, imm);
assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2)));
break;
}
}
assign(t0,
binop(Iop_Or32,
binop(Iop_Or32,
unop(Iop_V128to32, mkexpr(t3)),
unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t3)))),
binop(Iop_Or32,
unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(t3))),
unop(Iop_64HIto32,
unop(Iop_V128HIto64, mkexpr(t3))))));
dis_branch(False,
binop(Iop_CmpNE32, mkexpr(t0), mkU32(0)), imm, bstmt);
} else if (fmt == 0x0B && has_msa) { /* BZ.V */
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_V128);
assign(t1, getWReg(ft));
assign(t0,
binop(Iop_Or32,
binop(Iop_Or32,
unop(Iop_V128to32, mkexpr(t1)),
unop(Iop_64HIto32, unop(Iop_V128to64, mkexpr(t1)))),
binop(Iop_Or32,
unop(Iop_64to32, unop(Iop_V128HIto64, mkexpr(t1))),
unop(Iop_64HIto32,
unop(Iop_V128HIto64, mkexpr(t1))))));
dis_branch(False,
binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0)), imm, bstmt);
} else if (fmt == 0x09) { /* BC1EQZ */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("bc1eqz f%u, %u", ft, imm);
t1 = newTemp(Ity_I1);
if (mode64) {
assign(t1, binop(Iop_CmpEQ64,
binop(Iop_And64,
unop(Iop_ReinterpF64asI64, getDReg(ft)),
mkU64(1)),
mkU64(0)));
} else {
assign(t1, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_64to32,
unop(Iop_ReinterpF64asI64,
getDReg(ft))),
mkU32(1)),
mkU32(0)));
}
dis_branch(False, mkexpr(t1), imm, bstmt);
} else {
ILLEGAL_INSTRUCTON
}
} else if (fmt == 0x0D) { /* BC1NEZ */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("bc1nez f%u, %u", ft, imm);
t1 = newTemp(Ity_I1);
if (mode64) {
assign(t1, binop(Iop_CmpNE64,
binop(Iop_And64,
unop(Iop_ReinterpF64asI64, getDReg(ft)),
mkU64(1)),
mkU64(0)));
} else {
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, getDReg(ft))),
mkU32(1)),
mkU32(0)));
}
dis_branch(False, mkexpr(t1), imm, bstmt);
} else {
ILLEGAL_INSTRUCTON;
break;
}
} else {
if (fmt == 0x15) { /* CMP.cond.d */
Bool comparison = True;
UInt signaling = CMPAFD;
DIP("cmp.cond.d f%u, f%u, f%u, cond %u", fd, fs, ft, function);
t0 = newTemp(Ity_I32);
/* Conditions starting with S should signal exception on QNaN inputs. */
switch (function) {
case 0x08: /* SAF */
signaling = CMPSAFD; /* fallthrough */
case 0x00: /* AF */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0)));
break;
case 0x09: /* SUN */
signaling = CMPSAFD; /* fallthrough */
case 0x01: /* UN */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0))));
break;
case 0x19: /* SOR */
signaling = CMPSAFD; /* fallthrough */
case 0x11: /* OR */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL))));
break;
case 0x0A: /* SEQ */
signaling = CMPSAFD; /* fallthrough */
case 0x02: /* EQ */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0))));
break;
case 0x1A: /* SNEQ */
signaling = CMPSAFD; /* fallthrough */
case 0x12: /* NEQ */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL))));
break;
case 0x0B: /* SUEQ */
signaling = CMPSAFD; /* fallthrough */
case 0x03: /* UEQ */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x45)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(),
mkU64(0)))));
break;
case 0x1B: /* SNEQ */
signaling = CMPSAFD; /* fallthrough */
case 0x13: /* NEQ */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x00)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(),
mkU64(0)))));
break;
case 0x0C: /* SLT */
signaling = CMPSAFD; /* fallthrough */
case 0x04: /* LT */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0))));
break;
case 0x0D: /* SULT */
signaling = CMPSAFD; /* fallthrough */
case 0x05: /* ULT */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x45)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(),
mkU64(0)))));
break;
case 0x0E: /* SLE */
signaling = CMPSAFD; /* fallthrough */
case 0x06: /* LE */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x40)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL)),
binop(Iop_I64StoF64,
get_IR_roundingmode(),
mkU64(0)))));
break;
case 0x0F: /* SULE */
signaling = CMPSAFD; /* fallthrough */
case 0x07: /* ULE */
assign(t0, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
calculateFCSR(fs, ft, signaling, False, 2);
putDReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0)),
unop(Iop_ReinterpI64asF64,
mkU64(0xFFFFFFFFFFFFFFFFULL))));
break;
default:
comparison = False;
}
if (comparison) {
if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
break;
}
} else if (fmt == 0x14) {
Bool comparison = True;
UInt signaling = CMPAFS;
DIP("cmp.cond.s f%u, f%u, f%u, cond %u", fd, fs, ft, function);
t0 = newTemp(Ity_I32);
/* Conditions starting with S should signal exception on QNaN inputs. */
switch (function) {
case 0x08: /* SAF */
signaling = CMPSAFS; /* fallthrough */
case 0x00: /* AF */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(), mkU32(0))));
break;
case 0x09: /* SUN */
signaling = CMPSAFS; /* fallthrough */
case 0x01: /* UN */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0)))));
break;
case 0x19: /* SOR */
signaling = CMPSAFS; /* fallthrough */
case 0x11: /* OR */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x45)),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU)))));
break;
case 0x0A: /* SEQ */
signaling = CMPSAFS; /* fallthrough */
case 0x02: /* EQ */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0)))));
break;
case 0x1A: /* SNEQ */
signaling = CMPSAFS; /* fallthrough */
case 0x12: /* NEQ */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU)))));
break;
case 0x0B: /* SUEQ */
signaling = CMPSAFS; /* fallthrough */
case 0x03: /* UEQ */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x40)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x45)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))))));
break;
case 0x1B: /* SNEQ */
signaling = CMPSAFS; /* fallthrough */
case 0x13: /* NEQ */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x00)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))))));
break;
case 0x0C: /* SLT */
signaling = CMPSAFS; /* fallthrough */
case 0x04: /* LT */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0)))));
break;
case 0x0D: /* SULT */
signaling = CMPSAFS; /* fallthrough */
case 0x05: /* ULT */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x45)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))))));
break;
case 0x0E: /* SLE */
signaling = CMPSAFS; /* fallthrough */
case 0x06: /* LE */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x01)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
IRExpr_ITE(binop(Iop_CmpEQ32,
mkexpr(t0), mkU32(0x40)),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU))),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))))));
break;
case 0x0F: /* SULE */
signaling = CMPSAFS; /* fallthrough */
case 0x07: /* ULE */
assign(t0, binop(Iop_CmpF32,
getLoFromF64(Ity_F64, getFReg(fs)),
getLoFromF64(Ity_F64, getFReg(ft))));
calculateFCSR(fs, ft, signaling, True, 2);
putFReg(fd,
IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0)),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))),
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
mkU32(0xFFFFFFFFU)))));
break;
default:
comparison = False;
}
if (comparison) {
if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
ILLEGAL_INSTRUCTON
}
break;
}
}
switch (function) {
case 0x04: { /* SQRT.fmt */
switch (fmt) {
case 0x10: { /* S */
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_SqrtF32, rm,
getLoFromF64(tyF, getFReg(fs)))));
break;
}
case 0x11: { /* D */
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, binop(Iop_SqrtF64, rm, getDReg(fs)));
break;
}
default:
return -1;
}
}
break; /* SQRT.fmt */
case 0x05: /* ABS.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("abs.s f%u, f%u", fd, fs);
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_AbsF32,
getLoFromF64(tyF, getFReg(fs)))));
break;
case 0x11: /* D */
DIP("abs.d f%u, f%u", fd, fs);
putDReg(fd, unop(Iop_AbsF64, getDReg(fs)));
break;
default:
return -1;
}
break; /* ABS.fmt */
case 0x02: /* MUL.fmt */
switch (fmt) {
case 0x11: { /* D */
DIP("mul.d f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_MulF64, rm, getDReg(fs),
getDReg(ft)));
break;
}
case 0x10: { /* S */
DIP("mul.s f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_MulF32, rm,
getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)))));
break;
}
default:
return -1;
}
break; /* MUL.fmt */
case 0x03: /* DIV.fmt */
switch (fmt) {
case 0x11: { /* D */
DIP("div.d f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_DivF64, rm, getDReg(fs),
getDReg(ft)));
break;
}
case 0x10: { /* S */
DIP("div.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, DIVS, False, 2);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32, rm,
getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)))));
break;
}
default:
return -1;
}
break; /* DIV.fmt */
case 0x01: /* SUB.fmt */
switch (fmt) {
case 0x11: { /* D */
DIP("sub.d f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, SUBD, False, 2);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_SubF64, rm, getDReg(fs),
getDReg(ft)));
break;
}
case 0x10: { /* S */
DIP("sub.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, SUBS, True, 2);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_SubF32, rm,
getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)))));
break;
}
default:
return -1;
}
break; /* SUB.fmt */
case 0x06: /* MOV.fmt */
switch (fmt) {
case 0x11: /* D */
DIP("mov.d f%u, f%u", fd, fs);
if (fp_mode64) {
putDReg(fd, getDReg(fs));
} else {
putFReg(fd, getFReg(fs));
putFReg(fd + 1, getFReg(fs + 1));
}
break;
case 0x10: /* S */
DIP("mov.s f%u, f%u", fd, fs);
putFReg(fd, getFReg(fs));
break;
default:
return -1;
}
break; /* MOV.fmt */
case 0x07: /* NEG.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("neg.s f%u, f%u", fd, fs);
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32,
getLoFromF64(tyF, getFReg(fs)))));
break;
case 0x11: /* D */
DIP("neg.d f%u, f%u", fd, fs);
putDReg(fd, unop(Iop_NegF64, getDReg(fs)));
break;
default:
return -1;
}
break; /* NEG.fmt */
case 0x08: /* ROUND.L.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("round.l.s f%u, f%u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, ROUNDLS, True, 1);
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_F32toI64S, mkU32(0x0),
getLoFromF64(Ity_F64, getFReg(fs))));
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x11: /* D */
DIP("round.l.d f%u, f%u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, ROUNDLD, False, 1);
putDReg(fd, unop(Iop_ReinterpI64asF64,
binop(Iop_F64toI64S,
mkU32(0x0),
getDReg(fs))));
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;
}
break; /* ROUND.L.fmt */
case 0x09: /* TRUNC.L.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("trunc.l.s f%u, f%u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, TRUNCLS, True, 1);
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_F32toI64S, mkU32(0x3),
getLoFromF64(Ity_F64, getFReg(fs))));
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x11: /* D */
DIP("trunc.l.d f%u, f%u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, TRUNCLD, False, 1);
putDReg(fd, unop(Iop_ReinterpI64asF64,
binop(Iop_F64toI64S,
mkU32(0x3),
getDReg(fs))));
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;
}
break; /* TRUNC.L.fmt */
case 0x15: /* RECIP.fmt */
switch (fmt) {
case 0x10: { /* S */
DIP("recip.s f%u, f%u", fd, fs);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32,
rm, unop(Iop_ReinterpI32asF32,
mkU32(ONE_SINGLE)), getLoFromF64(tyF,
getFReg(fs)))));
break;
}
case 0x11: { /* D */
DIP("recip.d f%u, f%u", fd, fs);
IRExpr *rm = get_IR_roundingmode();
/* putDReg(fd, 1.0/getDreg(fs)); */
putDReg(fd, triop(Iop_DivF64, rm,
unop(Iop_ReinterpI64asF64,
mkU64(ONE_DOUBLE)), getDReg(fs)));
break;
}
default:
return -1;
}
break; /* RECIP.fmt */
case 0x13: /* MOVN.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("movn.s f%u, f%u, r%u", fd, fs, rt);
t1 = newTemp(Ity_I1);
if (mode64)
assign(t1, binop(Iop_CmpNE64, mkU64(0), getIReg(rt)));
else
assign(t1, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
putFReg(fd, IRExpr_ITE(mkexpr(t1), getFReg(fs), getFReg(fd)));
break;
case 0x11: /* D */
DIP("movn.d f%u, f%u, r%u", fd, fs, rt);
t1 = newTemp(Ity_I1);
if (mode64)
assign(t1, binop(Iop_CmpNE64, mkU64(0), getIReg(rt)));
else
assign(t1, binop(Iop_CmpNE32, mkU32(0), getIReg(rt)));
putDReg(fd, IRExpr_ITE(mkexpr(t1), getDReg(fs), getDReg(fd)));
break;
default:
return -1;
}
break; /* MOVN.fmt */
case 0x12: /* MOVZ.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("movz.s f%u, f%u, r%u", fd, fs, rt);
t1 = newTemp(Ity_I1);
if (mode64)
assign(t1, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt)));
else
assign(t1, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt)));
putFReg(fd, IRExpr_ITE(mkexpr(t1), getFReg(fs), getFReg(fd)));
break;
case 0x11: /* D */
DIP("movz.d f%u, f%u, r%u", fd, fs, rt);
t1 = newTemp(Ity_I1);
if (mode64)
assign(t1, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt)));
else
assign(t1, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt)));
putDReg(fd, IRExpr_ITE(mkexpr(t1), getDReg(fs), getDReg(fd)));
break;
default:
return -1;
}
break; /* MOVZ.fmt */
case 0x11: /* MOVT.fmt */
if (tf == 1) {
UInt mov_cc = get_mov_cc(cins);
switch (fmt) { /* MOVCF = 010001 */
case 0x11: /* D */
DIP("movt.d f%u, f%u, %u", fd, fs, mov_cc);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
t4 = newTemp(Ity_F64);
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + mov_cc)),
mkU32(0x1))
));
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
assign(t4, IRExpr_ITE(mkexpr(t3),
getDReg(fs), getDReg(fd)));
putDReg(fd, mkexpr(t4));
break;
case 0x10: /* S */
DIP("movt.s f%u, f%u, %u", fd, fs, mov_cc);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
t4 = newTemp(Ity_F64);
t5 = newTemp(Ity_F64);
t6 = newTemp(Ity_F64);
t7 = newTemp(Ity_I64);
if (fp_mode64) {
assign(t5, getFReg(fs));
assign(t6, getFReg(fd));
} else {
assign(t5, unop(Iop_F32toF64, getFReg(fs)));
assign(t6, unop(Iop_F32toF64, getFReg(fd)));
}
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + mov_cc)),
mkU32(0x1))
));
assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
assign(t4, IRExpr_ITE(mkexpr(t3),
mkexpr(t5), mkexpr(t6)));
if (fp_mode64) {
IRTemp f = newTemp(Ity_F64);
IRTemp fd_hi = newTemp(Ity_I32);
assign(f, getFReg(fd));
assign(fd_hi, unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64, mkexpr(f))));
assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, mkexpr(t4))),
True));
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7)));
} else
putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
mkexpr(t4)));
break;
default:
return -1;
}
} else if (tf == 0) { /* MOVF.fmt */
UInt mov_cc = get_mov_cc(cins);
switch (fmt) { /* MOVCF = 010001 */
case 0x11: /* D */
DIP("movf.d f%u, f%u, %u", fd, fs, mov_cc);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
t4 = newTemp(Ity_F64);
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + mov_cc)),
mkU32(0x1))
));
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
assign(t4, IRExpr_ITE(mkexpr(t3),
getDReg(fs), getDReg(fd)));
putDReg(fd, mkexpr(t4));
break;
case 0x10: /* S */
DIP("movf.s f%u, f%u, %u", fd, fs, mov_cc);
t1 = newTemp(Ity_I1);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I1);
t4 = newTemp(Ity_F64);
t5 = newTemp(Ity_F64);
t6 = newTemp(Ity_F64);
if (fp_mode64) {
assign(t5, getFReg(fs));
assign(t6, getFReg(fd));
} else {
assign(t5, unop(Iop_F32toF64, getFReg(fs)));
assign(t6, unop(Iop_F32toF64, getFReg(fd)));
}
assign(t1, binop(Iop_CmpEQ32, mkU32(0), mkU32(mov_cc)));
assign(t2, IRExpr_ITE(mkexpr(t1),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(23)),
mkU32(0x1)),
binop(Iop_And32,
binop(Iop_Shr32, getFCSR(),
mkU8(24 + mov_cc)),
mkU32(0x1))
));
assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
assign(t4, IRExpr_ITE(mkexpr(t3),
mkexpr(t5), mkexpr(t6)));
if (fp_mode64) {
IRTemp f = newTemp(Ity_F64);
IRTemp fd_hi = newTemp(Ity_I32);
t7 = newTemp(Ity_I64);
assign(f, getFReg(fd));
assign(fd_hi, unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64, mkexpr(f))));
assign(t7, mkWidenFrom32(Ity_I64, unop(Iop_64to32,
unop(Iop_ReinterpF64asI64, mkexpr(t4))),
True));
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7)));
} else
putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
mkexpr(t4)));
break;
default:
return -1;
}
}
break; /* MOVT.fmt */
case 0x00: /* ADD.fmt */
switch (fmt) {
case 0x10: { /* S */
DIP("add.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, ADDS, True, 2);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_AddF32, rm,
getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)))));
break;
}
case 0x11: { /* D */
DIP("add.d f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, ADDD, False, 2);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_AddF64, rm, getDReg(fs), getDReg(ft)));
break;
}
case 0x04: /* MTC1 (Move Word to Floating Point) */
DIP("mtc1 r%u, f%u", rt, fs);
if (fp_mode64) {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_F32);
assign(t0, mkNarrowTo32(ty, getIReg(rt)));
assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
putFReg(fs, mkWidenFromF32(tyF, mkexpr(t1)));
} else
putFReg(fs, unop(Iop_ReinterpI32asF32,
mkNarrowTo32(ty, getIReg(rt))));
break;
case 0x05: /* Doubleword Move to Floating Point DMTC1; MIPS64 */
DIP("dmtc1 r%u, f%u", rt, fs);
vassert(mode64);
putDReg(fs, unop(Iop_ReinterpI64asF64, getIReg(rt)));
break;
case 0x00: /* MFC1 */
DIP("mfc1 r%u, f%u", rt, fs);
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
assign(t1, unop(Iop_64to32, mkexpr(t0)));
putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True));
} else
putIReg(rt, mkWidenFrom32(ty,
unop(Iop_ReinterpF32asI32, getFReg(fs)),
True));
break;
case 0x01: /* Doubleword Move from Floating Point DMFC1;
MIPS64 */
DIP("dmfc1 r%u, f%u", rt, fs);
putIReg(rt, unop(Iop_ReinterpF64asI64, getDReg(fs)));
break;
case 0x06: /* CTC1 */
DIP("ctc1 r%u, f%u", rt, fs);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
t6 = newTemp(Ity_I32);
assign(t0, mkNarrowTo32(ty, getIReg(rt)));
if (fs == 25) { /* FCCR */
assign(t1, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
mkU32(0x000000FE)), mkU8(24)));
assign(t2, binop(Iop_And32, mkexpr(t0),
mkU32(0x01000000)));
assign(t3, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
mkU32(0x00000001)), mkU8(23)));
assign(t4, binop(Iop_And32, mkexpr(t0),
mkU32(0x007FFFFF)));
putFCSR(binop(Iop_Or32, binop(Iop_Or32, mkexpr(t1),
mkexpr(t2)), binop(Iop_Or32, mkexpr(t3),
mkexpr(t4))));
} else if (fs == 26) { /* FEXR */
assign(t1, binop(Iop_And32, getFCSR(), mkU32(0xFFFC0000)));
assign(t2, binop(Iop_And32, mkexpr(t0),
mkU32(0x0003F000)));
assign(t3, binop(Iop_And32, getFCSR(), mkU32(0x00000F80)));
assign(t4, binop(Iop_And32, mkexpr(t0),
mkU32(0x0000007C)));
assign(t5, binop(Iop_And32, getFCSR(), mkU32(0x00000003)));
putFCSR(binop(Iop_Or32, binop(Iop_Or32, binop(Iop_Or32,
mkexpr(t1), mkexpr(t2)), binop(Iop_Or32,
mkexpr(t3), mkexpr(t4))), mkexpr(t5)));
} else if (fs == 28) {
assign(t1, binop(Iop_And32, getFCSR(), mkU32(0xFE000000)));
assign(t2, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
mkU32(0x00000002)), mkU8(22)));
assign(t3, binop(Iop_And32, getFCSR(), mkU32(0x00FFF000)));
assign(t4, binop(Iop_And32, mkexpr(t0),
mkU32(0x00000F80)));
assign(t5, binop(Iop_And32, getFCSR(), mkU32(0x0000007C)));
assign(t6, binop(Iop_And32, mkexpr(t0),
mkU32(0x00000003)));
putFCSR(binop(Iop_Or32, binop(Iop_Or32, binop(Iop_Or32,
mkexpr(t1), mkexpr(t2)), binop(Iop_Or32,
mkexpr(t3), mkexpr(t4))), binop(Iop_Or32,
mkexpr(t5), mkexpr(t6))));
} else if (fs == 31) {
putFCSR(mkexpr(t0));
}
break;
case 0x02: /* CFC1 */
DIP("cfc1 r%u, f%u", rt, fs);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
t6 = newTemp(Ity_I32);
assign(t0, getFCSR());
if (fs == 0) {
putIReg(rt, mkWidenFrom32(ty,
IRExpr_Get(offsetof(VexGuestMIPS32State,
guest_FIR),
Ity_I32),
False));
} else if (fs == 25) {
assign(t1, mkU32(0x000000FF));
assign(t2, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
mkU32(0xFE000000)), mkU8(25)));
assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
mkU32(0x00800000)), mkU8(23)));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
mkexpr(t3)), False));
} else if (fs == 26) {
assign(t1, mkU32(0xFFFFF07C));
assign(t2, binop(Iop_And32, mkexpr(t0),
mkU32(0x0003F000)));
assign(t3, binop(Iop_And32, mkexpr(t0),
mkU32(0x0000007C)));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
mkexpr(t3)), False));
} else if (fs == 28) {
assign(t1, mkU32(0x00000F87));
assign(t2, binop(Iop_And32, mkexpr(t0),
mkU32(0x00000F83)));
assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
mkU32(0x01000000)), mkU8(22)));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
mkexpr(t3)), False));
} else if (fs == 31) {
putIReg(rt, mkWidenFrom32(ty, getFCSR(), False));
}
break;
default:
return -1;
}
break;
case 0x21: /* CVT.D */
switch (fmt) {
case 0x10: /* S */
DIP("cvt.d.s f%u, f%u", fd, fs);
calculateFCSR(fs, 0, CVTDS, True, 1);
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_F32);
/* get lo half of FPR */
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
assign(t1, unop(Iop_64to32, mkexpr(t0)));
assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1)));
putFReg(fd, unop(Iop_F32toF64, mkexpr(t3)));
} else
putDReg(fd, unop(Iop_F32toF64, getFReg(fs)));
break;
case 0x14: /* W */
DIP("cvt.d.w %u, %u", fd, fs);
calculateFCSR(fs, 0, CVTDW, True, 1);
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_F32);
/* get lo half of FPR */
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
assign(t1, unop(Iop_64to32, mkexpr(t0)));
putDReg(fd, unop(Iop_I32StoF64, mkexpr(t1)));
break;
} else {
t0 = newTemp(Ity_I32);
assign(t0, unop(Iop_ReinterpF32asI32, getFReg(fs)));
putDReg(fd, unop(Iop_I32StoF64, mkexpr(t0)));
break;
}
case 0x15: { /* L */
if (fp_mode64) {
DIP("cvt.d.l %u, %u", fd, fs);
calculateFCSR(fs, 0, CVTDL, False, 1);
t0 = newTemp(Ity_I64);
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
putFReg(fd, binop(Iop_I64StoF64,
get_IR_roundingmode(), mkexpr(t0)));
break;
} else
return -1;
}
default:
return -1;
}
break; /* CVT.D */
case 0x20: /* CVT.s */
switch (fmt) {
case 0x14: /* W */
DIP("cvt.s.w %u, %u", fd, fs);
calculateFCSR(fs, 0, CVTSW, True, 1);
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_F32);
/* get lo half of FPR */
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
assign(t1, unop(Iop_64to32, mkexpr(t0)));
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_I32StoF32,
get_IR_roundingmode(), mkexpr(t1))));
} else {
t0 = newTemp(Ity_I32);
assign(t0, unop(Iop_ReinterpF32asI32, getFReg(fs)));
putFReg(fd, binop(Iop_I32StoF32, get_IR_roundingmode(),
mkexpr(t0)));
}
break;
case 0x11: /* D */
DIP("cvt.s.d %u, %u", fd, fs);
calculateFCSR(fs, 0, CVTSD, False, 1);
t0 = newTemp(Ity_F32);
assign(t0, binop(Iop_F64toF32, get_IR_roundingmode(),
getDReg(fs)));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t0)));
break;
case 0x15: /* L */
DIP("cvt.s.l %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, CVTSL, False, 1);
t0 = newTemp(Ity_I64);
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(fs)));
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_I64StoF32,
get_IR_roundingmode(), mkexpr(t0))));
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;
}
break; /* CVT.s */
case 0x24: /* CVT.w */
switch (fmt) {
case 0x10: /* S */
DIP("cvt.w.s %u, %u", fd, fs);
calculateFCSR(fs, 0, CVTWS, True, 1);
putFReg(fd,
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
binop(Iop_F32toI32S,
get_IR_roundingmode(),
getLoFromF64(tyF,
getFReg(fs))))));
break;
case 0x11: /* D */
DIP("cvt.w.d %u, %u", fd, fs);
calculateFCSR(fs, 0, CVTWD, False, 1);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_F32);
assign(t0, binop(Iop_F64toI32S, get_IR_roundingmode(),
getDReg(fs)));
assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break;
default:
return -1;
}
break;
case 0x25: /* CVT.l */
switch (fmt) {
case 0x10: /* S */
DIP("cvt.l.s %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, CVTLS, True, 1);
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_F32toI64S, get_IR_roundingmode(),
getLoFromF64(tyF, getFReg(fs))));
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x11: { /* D */
DIP("cvt.l.d %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, CVTLD, False, 1);
putDReg(fd, unop(Iop_ReinterpI64asF64,
binop(Iop_F64toI64S,
get_IR_roundingmode(),
getDReg(fs))));
} else {
ILLEGAL_INSTRUCTON
}
break;
}
default:
return -1;
}
break;
case 0x0B: /* FLOOR.L.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("floor.l.s %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, FLOORLS, True, 1);
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_F32toI64S, mkU32(0x1),
getLoFromF64(tyF, getFReg(fs))));
putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x11: /* D */
DIP("floor.l.d %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, FLOORLD, False, 1);
putDReg(fd, unop(Iop_ReinterpI64asF64,
binop(Iop_F64toI64S,
mkU32(0x01),
getDReg(fs))));
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;
}
break;
case 0x0C: /* ROUND.W.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("round.w.s f%u, f%u", fd, fs);
calculateFCSR(fs, 0, ROUNDWS, True, 1);
putFReg(fd,
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
binop(Iop_F32toI32S,
mkU32(0x0),
getLoFromF64(tyF,
getFReg(fs))))));
break;
case 0x11: /* D */
DIP("round.w.d f%u, f%u", fd, fs);
calculateFCSR(fs, 0, ROUNDWD, False, 1);
if (fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x0),
getDReg(fs)));
putFReg(fd, mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x0),
getDReg(fs)));
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
}
break;
default:
return -1;
}
break; /* ROUND.W.fmt */
case 0x0F: /* FLOOR.W.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("floor.w.s f%u, f%u", fd, fs);
calculateFCSR(fs, 0, FLOORWS, True, 1);
putFReg(fd,
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
binop(Iop_F32toI32S,
mkU32(0x1),
getLoFromF64(tyF,
getFReg(fs))))));
break;
case 0x11: /* D */
DIP("floor.w.d f%u, f%u", fd, fs);
calculateFCSR(fs, 0, FLOORWD, False, 1);
if (fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x1),
getDReg(fs)));
putFReg(fd, mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
break;
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x1),
getDReg(fs)));
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
break;
}
default:
return -1;
}
break; /* FLOOR.W.fmt */
case 0x0D: /* TRUNC.W */
switch (fmt) {
case 0x10: /* S */
DIP("trunc.w.s %u, %u", fd, fs);
calculateFCSR(fs, 0, TRUNCWS, True, 1);
putFReg(fd,
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
binop(Iop_F32toI32S,
mkU32(0x3),
getLoFromF64(tyF,
getFReg(fs))))));
break;
case 0x11: /* D */
DIP("trunc.w.d %u, %u", fd, fs);
calculateFCSR(fs, 0, TRUNCWD, False, 1);
if (fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x3),
getFReg(fs)));
putFReg(fd, mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x3),
getDReg(fs)));
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
}
break;
default:
return -1;
}
break;
case 0x0E: /* CEIL.W.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("ceil.w.s %u, %u", fd, fs);
calculateFCSR(fs, 0, CEILWS, True, 1);
putFReg(fd,
mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32,
binop(Iop_F32toI32S,
mkU32(0x2),
getLoFromF64(tyF,
getFReg(fs))))));
break;
case 0x11: /* D */
DIP("ceil.w.d %u, %u", fd, fs);
calculateFCSR(fs, 0, CEILWD, False, 1);
if (!fp_mode64) {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x2),
getDReg(fs)));
putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_F64toI32S, mkU32(0x2),
getDReg(fs)));
putFReg(fd, mkWidenFromF32(tyF,
unop(Iop_ReinterpI32asF32, mkexpr(t0))));
}
break;
default:
return -1;
}
break;
case 0x0A: /* CEIL.L.fmt */
switch (fmt) {
case 0x10: /* S */
DIP("ceil.l.s %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, CEILLS, True, 1);
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_F32toI64S, mkU32(0x2),
getLoFromF64(tyF, getFReg(fs))));
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0)));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x11: /* D */
DIP("ceil.l.d %u, %u", fd, fs);
if (fp_mode64) {
calculateFCSR(fs, 0, CEILLD, False, 1);
putDReg(fd, unop(Iop_ReinterpI64asF64,
binop(Iop_F64toI64S,
mkU32(0x2),
getDReg(fs))));
} else {
ILLEGAL_INSTRUCTON
}
break;
default:
return -1;
}
break;
case 0x16: /* RSQRT.fmt */
switch (fmt) {
case 0x10: { /* S */
DIP("rsqrt.s %u, %u", fd, fs);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32, rm,
unop(Iop_ReinterpI32asF32, mkU32(ONE_SINGLE)),
binop(Iop_SqrtF32, rm, getLoFromF64(tyF,
getFReg(fs))))));
break;
}
case 0x11: { /* D */
DIP("rsqrt.d %u, %u", fd, fs);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_DivF64, rm,
unop(Iop_ReinterpI64asF64,
mkU64(ONE_DOUBLE)),
binop(Iop_SqrtF64, rm, getDReg(fs))));
break;
}
default:
return -1;
}
break;
case 0x18: /* MADDF.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("maddf.d f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, qop(Iop_MAddF64, rm, getDReg(fs), getDReg(ft),
getDReg(fd)));
break;
}
case 0x10: { /* S */
DIP("maddf.s f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
assign(t1, qop(Iop_MAddF32, rm,
getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)),
getLoFromF64(tyF, getFReg(fd))));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x19: /* MSUBF.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("msubf.d f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, qop(Iop_MSubF64, rm, getDReg(fs),
getDReg(ft), getDReg(fd)));
break;
}
case 0x10: { /* S */
DIP("msubf.s f%u, f%u, f%u", fd, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
assign(t1, qop(Iop_MSubF32, rm,
getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)),
getLoFromF64(tyF, getFReg(fd))));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x1E: /* MAX.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("max.d f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MAXD, False, 2);
putDReg(fd, binop(Iop_MaxNumF64, getDReg(fs), getDReg(ft)));
break;
}
case 0x10: { /* S */
DIP("max.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MAXS, True, 2);
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_MaxNumF32,
getLoFromF64(Ity_F64,
getFReg(fs)),
getLoFromF64(Ity_F64,
getFReg(ft)))));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x1C: /* MIN.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("min.d f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MIND, False, 2);
putDReg(fd, binop(Iop_MinNumF64, getDReg(fs), getDReg(ft)));
break;
}
case 0x10: { /* S */
DIP("min.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MINS, True, 2);
putFReg(fd, mkWidenFromF32(tyF, binop(Iop_MinNumF32,
getLoFromF64(Ity_F64,
getFReg(fs)),
getLoFromF64(Ity_F64,
getFReg(ft)))));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x1F: /* MAXA.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("maxa.d f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MAXAD, False, 2);
t1 = newTemp(Ity_F64);
t2 = newTemp(Ity_F64);
t3 = newTemp(Ity_F64);
t4 = newTemp(Ity_I1);
assign(t1, unop(Iop_AbsF64, getFReg(fs)));
assign(t2, unop(Iop_AbsF64, getFReg(ft)));
assign(t3, binop(Iop_MaxNumF64, mkexpr(t1), mkexpr(t2)));
assign(t4, binop(Iop_CmpEQ32,
binop(Iop_CmpF64, mkexpr(t3), mkexpr(t1)),
mkU32(0x40)));
putFReg(fd, IRExpr_ITE(mkexpr(t4),
getFReg(fs), getFReg(ft)));
break;
}
case 0x10: { /* S */
DIP("maxa.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MAXAS, True, 2);
t1 = newTemp(Ity_F32);
t2 = newTemp(Ity_F32);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_I1);
assign(t1, unop(Iop_AbsF32, getLoFromF64(Ity_F64,
getFReg(fs))));
assign(t2, unop(Iop_AbsF32, getLoFromF64(Ity_F64,
getFReg(ft))));
assign(t3, binop(Iop_MaxNumF32, mkexpr(t1), mkexpr(t2)));
assign(t4, binop(Iop_CmpEQ32,
binop(Iop_CmpF32, mkexpr(t3), mkexpr(t1)),
mkU32(0x40)));
putFReg(fd, IRExpr_ITE(mkexpr(t4),
getFReg(fs), getFReg(ft)));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x1D: /* MINA.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("mina.d f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MINAD, False, 2);
t1 = newTemp(Ity_F64);
t2 = newTemp(Ity_F64);
t3 = newTemp(Ity_F64);
t4 = newTemp(Ity_I1);
assign(t1, unop(Iop_AbsF64, getFReg(fs)));
assign(t2, unop(Iop_AbsF64, getFReg(ft)));
assign(t3, binop(Iop_MinNumF64, mkexpr(t1), mkexpr(t2)));
assign(t4, binop(Iop_CmpEQ32,
binop(Iop_CmpF64, mkexpr(t3), mkexpr(t1)),
mkU32(0x40)));
putFReg(fd, IRExpr_ITE(mkexpr(t4),
getFReg(fs), getFReg(ft)));
break;
}
case 0x10: { /* S */
DIP("mina.s f%u, f%u, f%u", fd, fs, ft);
calculateFCSR(fs, ft, MINAS, True, 2);
t1 = newTemp(Ity_F32);
t2 = newTemp(Ity_F32);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_I1);
assign(t1, unop(Iop_AbsF32, getLoFromF64(Ity_F64,
getFReg(fs))));
assign(t2, unop(Iop_AbsF32, getLoFromF64(Ity_F64,
getFReg(ft))));
assign(t3, binop(Iop_MinNumF32, mkexpr(t1), mkexpr(t2)));
assign(t4, binop(Iop_CmpEQ32,
binop(Iop_CmpF32, mkexpr(t3), mkexpr(t1)),
mkU32(0x40)));
putFReg(fd, IRExpr_ITE(mkexpr(t4),
getFReg(fs), getFReg(ft)));
break;
}
default:
return -1;
}
}
break;
case 0x1A: /* RINT.fmt */
if (ft == 0) {
switch (fmt) {
case 0x11: { /* D */
DIP("rint.d f%u, f%u", fd, fs);
calculateFCSR(fs, 0, RINTS, True, 1);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, binop(Iop_RoundF64toInt, rm, getDReg(fs)));
break;
}
case 0x10: { /* S */
DIP("rint.s f%u, f%u", fd, fs);
calculateFCSR(fs, 0, RINTD, True, 1);
IRExpr *rm = get_IR_roundingmode();
putFReg(fd,
mkWidenFromF32(tyF,
binop(Iop_RoundF32toInt, rm,
getLoFromF64(tyF,
getFReg(fs)))));
break;
}
default:
return -1;
}
}
break;
case 0x10: /* SEL.fmt */
switch (fmt) {
case 0x11: { /* D */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("sel.d f%u, f%u, f%u", fd, fs, ft);
t1 = newTemp(Ity_I1);
if (mode64) {
assign(t1, binop(Iop_CmpNE64,
binop(Iop_And64,
unop(Iop_ReinterpF64asI64,
getDReg(fd)),
mkU64(1)),
mkU64(0)));
} else {
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_64to32,
unop(Iop_ReinterpF64asI64,
getDReg(fd))),
mkU32(1)),
mkU32(0)));
}
putDReg(fd, IRExpr_ITE(mkexpr(t1),
getDReg(ft), getDReg(fs)));
break;
} else {
ILLEGAL_INSTRUCTON;
break;
}
}
case 0x10: { /* S */
DIP("sel.s f%u, f%u, f%u", fd, fs, ft);
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(fd))),
mkU32(1)),
mkU32(0)));
putFReg(fd, IRExpr_ITE( mkexpr(t1),
getFReg(ft), getFReg(fs)));
break;
}
default:
return -1;
}
break;
case 0x14: /* SELEQZ.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) { /* SELEQZ.df */
case 0x11: { /* D */
DIP("seleqz.d f%u, f%u, f%u", fd, fs, ft);
t1 = newTemp(Ity_I1);
if (mode64) {
assign(t1, binop(Iop_CmpNE64,
binop(Iop_And64,
unop(Iop_ReinterpF64asI64,
getDReg(ft)),
mkU64(1)),
mkU64(0)));
} else {
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_64to32,
unop(Iop_ReinterpF64asI64,
getDReg(ft))),
mkU32(1)),
mkU32(0)));
}
putDReg(fd, IRExpr_ITE( mkexpr(t1),
binop(Iop_I64StoF64,
get_IR_roundingmode(), mkU64(0)),
getDReg(fs)));
break;
}
case 0x10: { /* S */
DIP("seleqz.s f%u, f%u, f%u", fd, fs, ft);
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(ft))),
mkU32(1)),
mkU32(0)));
putFReg(fd, IRExpr_ITE(mkexpr(t1),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0))),
getFReg(fs)));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x17: /* SELNEZ.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
switch (fmt) {
case 0x11: { /* D */
DIP("selnez.d f%u, f%u, f%u", fd, fs, ft);
t1 = newTemp(Ity_I1);
if (mode64) {
assign(t1, binop(Iop_CmpNE64,
binop(Iop_And64,
unop(Iop_ReinterpF64asI64,
getDReg(ft)),
mkU64(1)),
mkU64(0)));
} else {
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_64to32,
unop(Iop_ReinterpF64asI64,
getDReg(ft))),
mkU32(1)),
mkU32(0)));
}
putDReg(fd, IRExpr_ITE( mkexpr(t1),
getDReg(fs),
binop(Iop_I64StoF64,
get_IR_roundingmode(),
mkU64(0))));
break;
}
case 0x10: { /* S */
DIP("selnez.s f%u, f%u, f%u", fd, fs, ft);
t1 = newTemp(Ity_I1);
assign(t1, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(ft))),
mkU32(1)),
mkU32(0)));
putFReg(fd, IRExpr_ITE(mkexpr(t1),
getFReg(fs),
mkWidenFromF32(tyF,
binop(Iop_I32StoF32,
get_IR_roundingmode(),
mkU32(0)))));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
case 0x1B: /* CLASS.fmt */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
t0 = newTemp(Ity_I1); // exp zero
t1 = newTemp(Ity_I1); // exp max
t2 = newTemp(Ity_I1); // sign
t3 = newTemp(Ity_I1); // first
t4 = newTemp(Ity_I1); // val not zero
t5 = newTemp(Ity_I32);
switch (fmt) {
case 0x11: { /* D */
DIP("class.d f%u, f%u", fd, fs);
assign(t0, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64,
getDReg(fs))),
mkU32(0x7ff00000)),
mkU32(0)));
assign(t1, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64,
getDReg(fs))),
mkU32(0x7ff00000)),
mkU32(0x7ff00000)));
assign(t2, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64,
getDReg(fs))),
mkU32(0x80000000)),
mkU32(0x80000000)));
assign(t3, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64,
getDReg(fs))),
mkU32(0x00080000)),
mkU32(0x00080000)));
if (mode64) assign(t4, binop(Iop_CmpNE64,
binop(Iop_And64,
unop(Iop_ReinterpF64asI64,
getDReg(fs)),
mkU64(0x000fffffffffffffULL)),
mkU64(0)));
else assign(t4, binop(Iop_CmpNE32,
binop(Iop_Or32,
binop(Iop_And32,
unop(Iop_64HIto32,
unop(Iop_ReinterpF64asI64,
getDReg(fs))),
mkU32(0x000fffff)),
unop(Iop_64to32,
unop(Iop_ReinterpF64asI64,
getDReg(fs)))),
mkU32(0)));
assign(t5, binop(Iop_Shl32,
IRExpr_ITE(mkexpr(t1),
IRExpr_ITE(mkexpr(t4),
mkU32(0), mkU32(1)),
IRExpr_ITE(mkexpr(t0),
IRExpr_ITE(mkexpr(t4),
mkU32(0x4),
mkU32(0x8)),
mkU32(2))),
IRExpr_ITE(mkexpr(t2), mkU8(2), mkU8(6))));
putDReg(fd, unop(Iop_ReinterpI64asF64,
unop(Iop_32Uto64,
IRExpr_ITE(binop(Iop_CmpNE32,
mkexpr(t5), mkU32(0)),
mkexpr(t5),
IRExpr_ITE(mkexpr(t3),
mkU32(2),
mkU32(1))))));
break;
}
case 0x10: { /* S */
DIP("class.s f%u, f%u", fd, fs);
assign(t0, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(fs))),
mkU32(0x7f800000)),
mkU32(0)));
assign(t1, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(fs))),
mkU32(0x7f800000)),
mkU32(0x7f800000)));
assign(t2, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(fs))),
mkU32(0x80000000)),
mkU32(0x80000000)));
assign(t3, binop(Iop_CmpEQ32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(fs))),
mkU32(0x00400000)),
mkU32(0x00400000)));
assign(t4, binop(Iop_CmpNE32,
binop(Iop_And32,
unop(Iop_ReinterpF32asI32,
getLoFromF64(tyF, getFReg(fs))),
mkU32(0x007fffff)),
mkU32(0)));
assign(t5, binop(Iop_Shl32,
IRExpr_ITE(mkexpr(t1),
IRExpr_ITE(mkexpr(t4),
mkU32(0), mkU32(1)),
IRExpr_ITE(mkexpr(t0),
IRExpr_ITE(mkexpr(t4),
mkU32(0x4),
mkU32(0x8)), //zero or subnorm
mkU32(2))),
IRExpr_ITE(mkexpr(t2), mkU8(2), mkU8(6))));
putDReg(fd, unop(Iop_ReinterpI64asF64,
unop(Iop_32Uto64,
IRExpr_ITE(binop(Iop_CmpNE32,
mkexpr(t5), mkU32(0)),
mkexpr(t5),
IRExpr_ITE(mkexpr(t3),
mkU32(2),
mkU32(1))))));
break;
}
default:
return -1;
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
default:
if (dis_instr_CCondFmt(cins))
break;
return -1;
}
}
}
break; /* COP1 */
case 0x03: /* COP1X */
switch (function) {
case 0x0: { /* LWXC1 */
/* Load Word Indexed to Floating Point - LWXC1 (MIPS32r2) */
DIP("lwxc1 f%u, r%u(r%u)", fd, rt, rs);
t2 = newTemp(ty);
assign(t2, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
getIReg(rt)));
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I32);
t3 = newTemp(Ity_F32);
t4 = newTemp(Ity_I64);
assign(t3, load(Ity_F32, mkexpr(t2)));
assign(t4, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32,
mkexpr(t3)), True));
putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t4)));
} else {
putFReg(fd, load(Ity_F32, mkexpr(t2)));
}
break;
}
case 0x1: { /* LDXC1 */
/* Load Doubleword Indexed to Floating Point
LDXC1 (MIPS32r2 and MIPS64) */
DIP("ldxc1 f%u, r%u(r%u)", fd, rt, rs);
t0 = newTemp(ty);
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
getIReg(rt)));
putDReg(fd, load(Ity_F64, mkexpr(t0)));
break;
}
case 0x5: /* Load Doubleword Indexed Unaligned to Floating Point - LUXC1;
MIPS32r2 and MIPS64 */
DIP("luxc1 f%u, r%u(r%u)", fd, rt, rs);
if ((mode64 || VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps))
&& fp_mode64) {
t0 = newTemp(ty);
t1 = newTemp(ty);
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32,
getIReg(rs), getIReg(rt)));
assign(t1, binop(mode64 ? Iop_And64 : Iop_And32,
mkexpr(t0),
mode64 ? mkU64(0xfffffffffffffff8ULL)
: mkU32(0xfffffff8ULL)));
putFReg(fd, load(Ity_F64, mkexpr(t1)));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x8: { /* Store Word Indexed from Floating Point - SWXC1 */
DIP("swxc1 f%u, r%u(r%u)", ft, rt, rs);
t0 = newTemp(ty);
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
getIReg(rt)));
if (fp_mode64) {
store(mkexpr(t0), getLoFromF64(tyF, getFReg(fs)));
} else {
store(mkexpr(t0), getFReg(fs));
}
break;
}
case 0x9: { /* Store Doubleword Indexed from Floating Point - SDXC1 */
DIP("sdxc1 f%u, r%u(r%u)", fs, rt, rs);
t0 = newTemp(ty);
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32, getIReg(rs),
getIReg(rt)));
store(mkexpr(t0), getDReg(fs));
break;
}
case 0xD: /* Store Doubleword Indexed Unaligned from Floating Point -
SUXC1; MIPS64 MIPS32r2 */
DIP("suxc1 f%u, r%u(r%u)", fd, rt, rs);
if ((mode64 || VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps))
&& fp_mode64) {
t0 = newTemp(ty);
t1 = newTemp(ty);
assign(t0, binop(mode64 ? Iop_Add64 : Iop_Add32,
getIReg(rs), getIReg(rt)));
assign(t1, binop(mode64 ? Iop_And64 : Iop_And32,
mkexpr(t0),
mode64 ? mkU64(0xfffffffffffffff8ULL)
: mkU32(0xfffffff8ULL)));
store(mkexpr(t1), getFReg(fs));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x0F: {
DIP("prefx");
break;
}
case 0x20: { /* MADD.S */
DIP("madd.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
assign(t1, triop(Iop_AddF32, rm, getLoFromF64(tyF, getFReg(fmt)),
triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)))));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break; /* MADD.S */
}
case 0x21: { /* MADD.D */
DIP("madd.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_AddF64, rm, getDReg(fmt),
triop(Iop_MulF64, rm, getDReg(fs),
getDReg(ft))));
break; /* MADD.D */
}
case 0x28: { /* MSUB.S */
DIP("msub.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
assign(t1, triop(Iop_SubF32, rm,
triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft))),
getLoFromF64(tyF, getFReg(fmt))));
putFReg(fd, mkWidenFromF32(tyF, mkexpr(t1)));
break; /* MSUB.S */
}
case 0x29: { /* MSUB.D */
DIP("msub.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
putDReg(fd, triop(Iop_SubF64, rm, triop(Iop_MulF64, rm, getDReg(fs),
getDReg(ft)), getDReg(fmt)));
break; /* MSUB.D */
}
case 0x30: { /* NMADD.S */
DIP("nmadd.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
assign(t1, triop(Iop_AddF32, rm, getLoFromF64(tyF, getFReg(fmt)),
triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft)))));
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t1))));
break; /* NMADD.S */
}
case 0x31: { /* NMADD.D */
DIP("nmadd.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F64);
assign(t1, triop(Iop_AddF64, rm, getDReg(fmt),
triop(Iop_MulF64, rm, getDReg(fs),
getDReg(ft))));
putDReg(fd, unop(Iop_NegF64, mkexpr(t1)));
break; /* NMADD.D */
}
case 0x38: { /* NMSUBB.S */
DIP("nmsub.s f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F32);
assign(t1, triop(Iop_SubF32, rm,
triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
getLoFromF64(tyF, getFReg(ft))),
getLoFromF64(tyF, getFReg(fmt))));
putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t1))));
break; /* NMSUBB.S */
}
case 0x39: { /* NMSUBB.D */
DIP("nmsub.d f%u, f%u, f%u, f%u", fd, fmt, fs, ft);
IRExpr *rm = get_IR_roundingmode();
t1 = newTemp(Ity_F64);
assign(t1, triop(Iop_SubF64, rm, triop(Iop_MulF64, rm, getDReg(fs),
getDReg(ft)), getDReg(fmt)));
putDReg(fd, unop(Iop_NegF64, mkexpr(t1)));
break; /* NMSUBB.D */
}
default:
return -1;
}
break;
case 0x04: /* BEQL */
DIP("beql r%u, r%u, %u", rs, rt, imm);
*lastn = dis_branch_likely(binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
getIReg(rs), getIReg(rt)), imm);
break;
case 0x05: /* BNEL */
DIP("bnel r%u, r%u, %u", rs, rt, imm);
*lastn = dis_branch_likely(binop(mode64 ? Iop_CmpEQ64 : Iop_CmpEQ32,
getIReg(rs), getIReg(rt)), imm);
break;
case 0x06: /* 0x16 ??? BLEZL, BLEZC, BGEZC, BGEC */
if (rt == 0) { /* BLEZL */
DIP("blezl r%u, %u", rs, imm);
*lastn = dis_branch_likely(unop(Iop_Not1, (binop(mode64 ? Iop_CmpLE64S :
Iop_CmpLE32S, getIReg(rs), mode64 ?
mkU64(0x0) : mkU32(0x0)))), imm);
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (rs == 0) { /* BLEZC */
DIP("blezc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(False,
binop(Iop_CmpLE64S, getIReg(rt), mkU64(0x0)),
imm, dres);
} else {
dis_branch_compact(False,
binop(Iop_CmpLE32S, getIReg(rt), mkU32(0x0)),
imm, dres);
}
} else if (rt == rs) { /* BGEZC */
DIP("bgezc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(False,
binop(Iop_CmpLE64S, mkU64(0x0), getIReg(rt)),
imm, dres);
} else {
dis_branch_compact(False,
binop(Iop_CmpLE32S, mkU32(0x0), getIReg(rt)),
imm, dres);
}
} else { /* BGEC */
DIP("bgec r%u, r%u, %u", rs, rt, imm);
if (mode64) {
dis_branch_compact(False,
binop(Iop_CmpLE64S, getIReg(rt), getIReg(rs)),
imm, dres);
} else {
dis_branch_compact(False,
binop(Iop_CmpLE32S, getIReg(rt), getIReg(rs)),
imm, dres);
}
}
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x07: /* BGTZL, BGTZC, BLTZC, BLTC */
if (rt == 0) { /* BGTZL */
DIP("bgtzl r%u, %u", rs, imm);
if (mode64)
*lastn = dis_branch_likely(binop(Iop_CmpLE64S, getIReg(rs),
mkU64(0x00)), imm);
else
*lastn = dis_branch_likely(binop(Iop_CmpLE32S, getIReg(rs),
mkU32(0x00)), imm);
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (rs == 0) { /* BGTZC */
DIP("bgtzc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLE64S,
getIReg(rt), mkU64(0x0))),
imm, dres);
} else {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLE32S,
getIReg(rt), mkU32(0x0))),
imm, dres);
}
} else if (rs == rt) { /* BLTZC */
DIP("bltzc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLE64S,
mkU64(0x0), getIReg(rt))),
imm, dres);
} else {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLE32S,
mkU32(0x0), getIReg(rt))),
imm, dres);
}
} else { /* BLTC */
DIP("bltc r%u, r%u, %u", rs, rt, imm);
if (mode64) {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLE64S,
getIReg(rt), getIReg(rs))),
imm, dres);
} else {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpLE32S,
getIReg(rt), getIReg(rs))),
imm, dres);
}
}
} else {
ILLEGAL_INSTRUCTON
}
break;
#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev < 6))
case 0x08: { /* Doubleword Add Immidiate - DADDI; MIPS64 */
DIP("daddi r%u, r%u, %u", rt, rs, imm);
IRTemp tmpRs64 = newTemp(Ity_I64);
assign(tmpRs64, getIReg(rs));
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I64);
t2 = newTemp(Ity_I64);
t3 = newTemp(Ity_I64);
t4 = newTemp(Ity_I64);
/* dst = src0 + sign(imm)
if(sign(src0 ) != sign(imm ))
goto no overflow;
if(sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t0, binop(Iop_Add64, mkexpr(tmpRs64),
mkU64(extend_s_16to64(imm))));
assign(t1, binop(Iop_Xor64, mkexpr(tmpRs64),
mkU64(extend_s_16to64(imm))));
assign(t2, unop(Iop_1Sto64, binop(Iop_CmpEQ64, binop(Iop_And64,
mkexpr(t1), mkU64(0x8000000000000000ULL)),
mkU64(0x8000000000000000ULL))));
assign(t3, binop(Iop_Xor64, mkexpr(t0), mkexpr(tmpRs64)));
assign(t4, unop(Iop_1Sto64, binop(Iop_CmpNE64, binop(Iop_And64,
mkexpr(t3), mkU64(0x8000000000000000ULL)),
mkU64(0x8000000000000000ULL))));
stmt(IRStmt_Exit(binop(Iop_CmpEQ64, binop(Iop_Or64, mkexpr(t2),
mkexpr(t4)), mkU64(0)), Ijk_SigFPE_IntOvf,
IRConst_U64(guest_PC_curr_instr + 4),
OFFB_PC));
putIReg(rt, mkexpr(t0));
break;
}
#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6))
case 0x08: { /* BNEZALC, BNEC, BNVC */
if (rs == 0) { /* BNEZALC */
DIP("bnezalc r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(True,
unop(Iop_Not1,
binop(Iop_CmpEQ64, getIReg(rt), mkU64(0x0))),
imm, dres);
} else {
dis_branch_compact(True,
unop(Iop_Not1,
binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x0))),
imm, dres);
}
} else if (rs < rt) { /* BNEC */
DIP("bnec r%u, %u", rt, imm);
if (mode64) {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpEQ64,
getIReg(rt), getIReg(rs))),
imm, dres);
} else {
dis_branch_compact(False,
unop(Iop_Not1,
binop(Iop_CmpEQ32,
getIReg(rt), getIReg(rs))),
imm, dres);
}
} else { /* BNVC */
DIP("bnvc r%u, r%u, %u", rs, rt, imm);
if (mode64) {
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
assign(t0, IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rt),
mkU64(0xffffffff80000000ULL)),
mkU32(1),
IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rt),
mkU64(0x7FFFFFFFULL)),
mkU32(0), mkU32(1))));
assign(t1, IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rs),
mkU64(0xffffffff80000000ULL)),
mkU32(1),
IRExpr_ITE(binop(Iop_CmpLT64S,
getIReg(rs),
mkU64(0x7FFFFFFFULL)),
mkU32(0), mkU32(1))));
assign(t2, IRExpr_ITE(binop(Iop_CmpLT64S,
binop(Iop_Add64,
getIReg(rt), getIReg(rs)),
mkU64(0xffffffff80000000ULL)),
mkU32(1),
IRExpr_ITE(binop(Iop_CmpLT64S,
binop(Iop_Add64,
getIReg(rt),
getIReg(rs)),
mkU64(0x7FFFFFFFULL)),
mkU32(0), mkU32(1))));
assign(t3, binop(Iop_Add32,
mkexpr(t0),
binop(Iop_Add32, mkexpr(t1), mkexpr(t2))));
dis_branch_compact(False,
binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0)),
imm, dres);
} else {
IRTemp tmpRs32 = newTemp(Ity_I32);
IRTemp tmpRt32 = newTemp(Ity_I32);
assign(tmpRs32, getIReg(rs));
assign(tmpRt32, getIReg(rt));
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
t2 = newTemp(Ity_I32);
t3 = newTemp(Ity_I32);
t4 = newTemp(Ity_I32);
/* dst = src0 + src1
if (sign(src0 ) != sign(src1 ))
goto no overflow;
if (sign(dst) == sign(src0 ))
goto no overflow;
we have overflow! */
assign(t0, binop(Iop_Add32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
assign(t1, binop(Iop_Xor32, mkexpr(tmpRs32), mkexpr(tmpRt32)));
assign(t2, unop(Iop_1Uto32,
binop(Iop_CmpEQ32,
binop(Iop_And32, mkexpr(t1), mkU32(0x80000000)),
mkU32(0x80000000))));
assign(t3, binop(Iop_Xor32, mkexpr(t0), mkexpr(tmpRs32)));
assign(t4, unop(Iop_1Uto32,
binop(Iop_CmpNE32,
binop(Iop_And32, mkexpr(t3), mkU32(0x80000000)),
mkU32(0x80000000))));
dis_branch_compact(False, binop(Iop_CmpNE32 ,
binop(Iop_Or32, mkexpr(t2), mkexpr(t4)),
mkU32(0)), imm, dres);
}
}
break;
}
#endif
case 0x09: /* Doubleword Add Immidiate Unsigned - DADDIU; MIPS64 */
DIP("daddiu r%u, r%u, %u", rt, rs, imm);
putIReg(rt, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
break;
case 0x0A: { /* LDL */
/* Load Doubleword Left - LDL; MIPS64 */
vassert(mode64);
DIP("ldl r%u, %u(r%u)", rt, imm, rs);
/* t1 = addr */
#if defined (_MIPSEL)
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
#elif defined (_MIPSEB)
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Xor64, mkU64(0x7), binop(Iop_Add64, getIReg(rs),
mkU64(extend_s_16to64(imm)))));
#endif
/* t2 = word addr */
/* t4 = addr mod 8 */
LWX_SWX_PATTERN64_1;
/* t3 = word content - shifted */
t3 = newTemp(Ity_I64);
assign(t3, binop(Iop_Shl64, load(Ity_I64, mkexpr(t2)),
narrowTo(Ity_I8, binop(Iop_Shl64, binop(Iop_Sub64, mkU64(0x07),
mkexpr(t4)), mkU8(3)))));
/* rt content - adjusted */
t5 = newTemp(Ity_I64);
t6 = newTemp(Ity_I64);
t7 = newTemp(Ity_I64);
assign(t5, binop(Iop_Mul64, mkexpr(t4), mkU64(0x8)));
assign(t6, binop(Iop_Shr64, mkU64(0x00FFFFFFFFFFFFFFULL),
narrowTo(Ity_I8, mkexpr(t5))));
assign(t7, binop(Iop_And64, getIReg(rt), mkexpr(t6)));
putIReg(rt, binop(Iop_Or64, mkexpr(t7), mkexpr(t3)));
break;
}
case 0x0B: { /* LDR */
/* Load Doubleword Right - LDR; MIPS64 */
vassert(mode64);
DIP("ldr r%u,%u(r%u)", rt, imm, rs);
/* t1 = addr */
#if defined (_MIPSEL)
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
#elif defined (_MIPSEB)
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Xor64, mkU64(0x7), binop(Iop_Add64, getIReg(rs),
mkU64(extend_s_16to64(imm)))));
#endif
/* t2 = word addr */
/* t4 = addr mod 8 */
LWX_SWX_PATTERN64_1;
/* t3 = word content - shifted */
t3 = newTemp(Ity_I64);
assign(t3, binop(Iop_Shr64, load(Ity_I64, mkexpr(t2)),
narrowTo(Ity_I8, binop(Iop_Shl64, mkexpr(t4), mkU8(3)))));
/* rt content - adjusted */
t5 = newTemp(Ity_I64);
assign(t5, binop(Iop_And64, getIReg(rt), unop(Iop_Not64,
binop(Iop_Shr64, mkU64(0xFFFFFFFFFFFFFFFFULL),
narrowTo(Ity_I8, binop(Iop_Shl64, mkexpr(t4), mkU8(0x3)))))));
putIReg(rt, binop(Iop_Or64, mkexpr(t5), mkexpr(t3)));
break;
}
case 0x0C: /* Special2 */
return disInstr_MIPS_WRK_Special2(cins, archinfo, abiinfo,
dres, bstmt, lastn);
case 0x0D: /* DAUI */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("daui r%u, r%u, %x", rt, rs, imm);
putIReg(rt, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_32to64(imm << 16))));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x0E: /* MIPS MSA (SIMD) */
if (has_msa) {
Int retVal = disMSAInstr_MIPS_WRK(cins);
if (retVal == 0) {
break;
} else if (retVal == -2) {
ILLEGAL_INSTRUCTON
break;
}
}
vex_printf("Error occured while trying to decode MIPS MSA "
"instruction.\nYour platform probably doesn't support "
"MIPS MSA (SIMD) ASE.\n");
return -1;
case 0x0F: /* Special3 */
return disInstr_MIPS_WRK_Special3(cins, archinfo, abiinfo,
dres, bstmt, lastn);
default:
return -1;
}
return 0;
}
static UInt disInstr_MIPS_WRK_20(UInt cins)
{
IRTemp t1 = 0, t2, t3, t4, t5;
UInt opcode, rs, rt, imm;
opcode = get_opcode(cins);
imm = get_imm(cins);
rs = get_rs(cins);
rt = get_rt(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
switch (opcode & 0x0F) {
case 0x00: /* LB */
DIP("lb r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
if (mode64)
putIReg(rt, unop(Iop_8Sto64, load(Ity_I8, mkexpr(t1))));
else
putIReg(rt, unop(Iop_8Sto32, load(Ity_I8, mkexpr(t1))));
break;
case 0x01: /* LH */
DIP("lh r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
if (mode64)
putIReg(rt, unop(Iop_16Sto64, load(Ity_I16, mkexpr(t1))));
else
putIReg(rt, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t1))));
break;
case 0x02: /* LWL */
DIP("lwl r%u, %u(r%u)", rt, imm, rs);
if (mode64) {
/* t1 = addr */
t1 = newTemp(Ity_I64);
#if defined (_MIPSEL)
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
#elif defined (_MIPSEB)
assign(t1, binop(Iop_Xor64,
mkU64(0x03),
binop(Iop_Add64,
getIReg(rs),
mkU64(extend_s_16to64(imm)))));
#endif
/* t2 = word addr */
/* t4 = addr mod 4 */
LWX_SWX_PATTERN64;
/* t3 = word content - shifted */
t3 = newTemp(Ity_I32);
assign(t3, binop(Iop_Shl32,
load(Ity_I32, mkexpr(t2)),
narrowTo(Ity_I8,
binop(Iop_Shl32,
binop(Iop_Sub32,
mkU32(0x03),
mkexpr(t4)),
mkU8(3)))));
/* rt content - adjusted */
t5 = newTemp(Ity_I32);
assign(t5, binop(Iop_And32,
mkNarrowTo32(ty, getIReg(rt)),
binop(Iop_Shr32,
mkU32(0x00FFFFFF),
narrowTo(Ity_I8, binop(Iop_Mul32,
mkU32(0x08),
mkexpr(t4))))));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t5),
mkexpr(t3)), True));
} else {
/* t1 = addr */
t1 = newTemp(Ity_I32);
#if defined (_MIPSEL)
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
#elif defined (_MIPSEB)
assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
mkU32(extend_s_16to32(imm)))));
#endif
/* t2 = word addr */
/* t4 = addr mod 4 */
LWX_SWX_PATTERN;
/* t3 = word content - shifted */
t3 = newTemp(Ity_I32);
assign(t3, binop(Iop_Shl32, load(Ity_I32, mkexpr(t2)), narrowTo(Ity_I8,
binop(Iop_Shl32, binop(Iop_Sub32, mkU32(0x03), mkexpr(t4)),
mkU8(3)))));
/* rt content - adjusted */
t5 = newTemp(Ity_I32);
assign(t5, binop(Iop_And32,
getIReg(rt),
binop(Iop_Shr32,
mkU32(0x00FFFFFF),
narrowTo(Ity_I8, binop(Iop_Mul32,
mkU32(0x08),
mkexpr(t4))))));
putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3)));
}
break;
case 0x03: /* LW */
DIP("lw r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True));
break;
case 0x04: /* LBU */
DIP("lbu r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
if (mode64)
putIReg(rt, unop(Iop_8Uto64, load(Ity_I8, mkexpr(t1))));
else
putIReg(rt, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t1))));
break;
case 0x05: /* LHU */
DIP("lhu r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
if (mode64)
putIReg(rt, unop(Iop_16Uto64, load(Ity_I16, mkexpr(t1))));
else
putIReg(rt, unop(Iop_16Uto32, load(Ity_I16, mkexpr(t1))));
break;
case 0x06: /* LWR */
DIP("lwr r%u, %u(r%u)", rt, imm, rs);
if (mode64) {
/* t1 = addr */
t1 = newTemp(Ity_I64);
#if defined (_MIPSEL)
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
#elif defined (_MIPSEB)
assign(t1, binop(Iop_Xor64,
mkU64(0x3),
binop(Iop_Add64,
getIReg(rs),
mkU64(extend_s_16to64(imm)))));
#endif
/* t2 = word addr */
/* t4 = addr mod 4 */
LWX_SWX_PATTERN64;
/* t3 = word content - shifted */
t3 = newTemp(Ity_I32);
assign(t3, binop(Iop_Shr32,
load(Ity_I32, mkexpr(t2)),
narrowTo(Ity_I8,
binop(Iop_Shl32, mkexpr(t4), mkU8(0x03)))));
/* rt content - adjusted */
t5 = newTemp(Ity_I32);
assign(t5, binop(Iop_And32, mkNarrowTo32(ty, getIReg(rt)),
unop(Iop_Not32, binop(Iop_Shr32, mkU32(0xFFFFFFFF),
narrowTo(Ity_I8, binop(Iop_Shl32, mkexpr(t4), mkU8(0x3)))))));
putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t5),
mkexpr(t3)), True));
} else {
/* t1 = addr */
t1 = newTemp(Ity_I32);
#if defined (_MIPSEL)
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
#elif defined (_MIPSEB)
assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
mkU32(extend_s_16to32(imm)))));
#endif
/* t2 = word addr */
/* t4 = addr mod 4 */
LWX_SWX_PATTERN;
/* t3 = word content - shifted */
t3 = newTemp(Ity_I32);
assign(t3, binop(Iop_Shr32, load(Ity_I32, mkexpr(t2)),
narrowTo(Ity_I8, binop(Iop_Shl32, mkexpr(t4),
mkU8(3)))));
/* rt content - adjusted */
t5 = newTemp(Ity_I32);
assign(t5, binop(Iop_And32, getIReg(rt), unop(Iop_Not32,
binop(Iop_Shr32, mkU32(0xFFFFFFFF), narrowTo(Ity_I8,
binop(Iop_Shl32, mkexpr(t4), mkU8(0x3)))))));
putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3)));
}
break;
case 0x07: /* Load Word unsigned - LWU; MIPS64 */
DIP("lwu r%u,%u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), False));
break;
case 0x08: /* SB */
DIP("sb r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
store(mkexpr(t1), narrowTo(Ity_I8, getIReg(rt)));
break;
case 0x09: /* SH */
DIP("sh r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
store(mkexpr(t1), narrowTo(Ity_I16, getIReg(rt)));
break;
case 0x0A: /* SWL */
DIP("swl r%u, %u(r%u)", rt, imm, rs);
if (mode64) {
IRTemp E_byte = newTemp(Ity_I8);
IRTemp F_byte = newTemp(Ity_I8);
IRTemp G_byte = newTemp(Ity_I8);
IRTemp H_byte = newTemp(Ity_I8);
IRTemp F_pos = newTemp(Ity_I64);
IRTemp G_pos = newTemp(Ity_I64);
/* H byte */
assign(H_byte, getByteFromReg(rt, 0));
/* G byte */
assign(G_byte, getByteFromReg(rt, 1));
/* F byte */
assign(F_byte, getByteFromReg(rt, 2));
/* E byte */
assign(E_byte, getByteFromReg(rt, 3));
/* t1 = addr */
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
/* t2 = word addr */
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL)));
/* t3 = addr mod 4 */
t3 = newTemp(Ity_I64);
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x3)));
#if defined (_MIPSEL)
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
mkU64(0x0),
mkU64(0x1)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
mkU64(0x1),
mkU64(0x0)));
/* Store X_byte on the right place. */
store(mkexpr(t2), mkexpr(H_byte));
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(mkexpr(t1), mkexpr(E_byte));
#else /* _MIPSEB */
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
mkU64(0x0),
mkU64(0x1)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
mkU64(0x2),
mkU64(0x3)));
store(binop(Iop_Add64, mkexpr(t2), mkU64(3)), mkexpr(H_byte));
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(mkexpr(t1), mkexpr(E_byte));
#endif
} else {
IRTemp E_byte = newTemp(Ity_I8);
IRTemp F_byte = newTemp(Ity_I8);
IRTemp G_byte = newTemp(Ity_I8);
IRTemp H_byte = newTemp(Ity_I8);
IRTemp F_pos = newTemp(Ity_I32);
IRTemp G_pos = newTemp(Ity_I32);
/* H byte */
assign(H_byte, getByteFromReg(rt, 0));
/* G byte */
assign(G_byte, getByteFromReg(rt, 1));
/* F byte */
assign(F_byte, getByteFromReg(rt, 2));
/* E byte */
assign(E_byte, getByteFromReg(rt, 3));
/* t1 = addr */
t1 = newTemp(Ity_I32);
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
/* t2 = word addr */
t2 = newTemp(Ity_I32);
assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFCULL)));
/* t3 = addr mod 4 */
t3 = newTemp(Ity_I32);
assign(t3, binop(Iop_And32, mkexpr(t1), mkU32(0x3)));
#if defined (_MIPSEL)
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
mkU32(0x0),
mkU32(0x1)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
mkU32(0x1),
mkU32(0x0)));
/* Store X_byte on the right place. */
store(mkexpr(t2), mkexpr(H_byte));
store(binop(Iop_Add32, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
store(binop(Iop_Sub32, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(mkexpr(t1), mkexpr(E_byte));
#else /* _MIPSEB */
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
mkU32(0x0),
mkU32(0x1)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
mkU32(0x2),
mkU32(0x3)));
store(binop(Iop_Add32, mkexpr(t2), mkU32(3)), mkexpr(H_byte));
store(binop(Iop_Add32, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
store(binop(Iop_Add32, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(mkexpr(t1), mkexpr(E_byte));
#endif
}
break;
case 0x0B: /* SW */
DIP("sw r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
store(mkexpr(t1), mkNarrowTo32(ty, getIReg(rt)));
break;
case 0x0C: { /* SDL rt, offset(base) MIPS64 */
DIP("sdl r%u, %u(r%u)", rt, imm, rs);
vassert(mode64);
IRTemp A_byte = newTemp(Ity_I8);
IRTemp B_byte = newTemp(Ity_I8);
IRTemp C_byte = newTemp(Ity_I8);
IRTemp D_byte = newTemp(Ity_I8);
IRTemp E_byte = newTemp(Ity_I8);
IRTemp F_byte = newTemp(Ity_I8);
IRTemp G_byte = newTemp(Ity_I8);
IRTemp H_byte = newTemp(Ity_I8);
IRTemp B_pos = newTemp(Ity_I64);
IRTemp C_pos = newTemp(Ity_I64);
IRTemp D_pos = newTemp(Ity_I64);
IRTemp E_pos = newTemp(Ity_I64);
IRTemp F_pos = newTemp(Ity_I64);
IRTemp G_pos = newTemp(Ity_I64);
/* H byte */
assign(H_byte, getByteFromReg(rt, 0));
/* G byte */
assign(G_byte, getByteFromReg(rt, 1));
/* F byte */
assign(F_byte, getByteFromReg(rt, 2));
/* E byte */
assign(E_byte, getByteFromReg(rt, 3));
/* D byte */
assign(D_byte, getByteFromReg(rt, 4));
/* C byte */
assign(C_byte, getByteFromReg(rt, 5));
/* B byte */
assign(B_byte, getByteFromReg(rt, 6));
/* A byte */
assign(A_byte, getByteFromReg(rt, 7));
/* t1 = addr */
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
/* t2 = word addr */
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL)));
/* t3 = addr mod 7 */
t3 = newTemp(Ity_I64);
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x7)));
#if defined (_MIPSEL)
/* Calculate X_byte position. */
assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x1)),
mkU64(0x0),
mkU64(0x1)));
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x2)),
mkU64(0x0),
mkU64(0x2)));
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x3)),
mkU64(0x0),
mkU64(0x3)));
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x4)),
mkU64(0x0),
mkU64(0x4)));
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x5)),
mkU64(0x0),
mkU64(0x5)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)),
mkU64(0x1),
mkU64(0x0)));
/* Store X_byte on the right place. */
store(mkexpr(t2), mkexpr(H_byte));
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
store(mkexpr(t1), mkexpr(A_byte));
#else /* _MIPSEB */
/* Calculate X_byte position. */
assign(B_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)),
mkU64(0x0),
mkU64(0x1)));
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x6)),
mkU64(0x2),
mkU64(0x0)));
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x5)),
mkU64(0x3),
mkU64(0x0)));
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x4)),
mkU64(0x4),
mkU64(0x0)));
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x3)),
mkU64(0x5),
mkU64(0x0)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
mkU64(0x6),
mkU64(0x7)));
/* Store X_byte on the right place. */
store(binop(Iop_Add64, mkexpr(t2), mkU64(0x7)), mkexpr(H_byte));
store(binop(Iop_Add64, mkexpr(t2), mkexpr(G_pos)), mkexpr(G_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
store(mkexpr(t1), mkexpr(A_byte));
#endif
break;
}
case 0x0D: {
/* SDR rt, offset(base) - MIPS64 */
vassert(mode64);
DIP("sdr r%u, %u(r%u)", rt, imm, rs);
IRTemp A_byte = newTemp(Ity_I8);
IRTemp B_byte = newTemp(Ity_I8);
IRTemp C_byte = newTemp(Ity_I8);
IRTemp D_byte = newTemp(Ity_I8);
IRTemp E_byte = newTemp(Ity_I8);
IRTemp F_byte = newTemp(Ity_I8);
IRTemp G_byte = newTemp(Ity_I8);
IRTemp H_byte = newTemp(Ity_I8);
IRTemp B_pos = newTemp(Ity_I64);
IRTemp C_pos = newTemp(Ity_I64);
IRTemp D_pos = newTemp(Ity_I64);
IRTemp E_pos = newTemp(Ity_I64);
IRTemp F_pos = newTemp(Ity_I64);
IRTemp G_pos = newTemp(Ity_I64);
/* H byte */
assign(H_byte, getByteFromReg(rt, 0));
/* G byte */
assign(G_byte, getByteFromReg(rt, 1));
/* F byte */
assign(F_byte, getByteFromReg(rt, 2));
/* E byte */
assign(E_byte, getByteFromReg(rt, 3));
/* D byte */
assign(D_byte, getByteFromReg(rt, 4));
/* C byte */
assign(C_byte, getByteFromReg(rt, 5));
/* B byte */
assign(B_byte, getByteFromReg(rt, 6));
/* A byte */
assign(A_byte, getByteFromReg(rt, 7));
/* t1 = addr */
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
/* t2 = word addr */
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL)));
/* t3 = addr mod 7 */
t3 = newTemp(Ity_I64);
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x7)));
#if defined (_MIPSEL)
/* Calculate X_byte position. */
assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x1), mkexpr(t3)),
mkU64(0x0),
mkU64(0x6)));
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x2), mkexpr(t3)),
mkU64(0x0),
mkU64(0x5)));
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x3), mkexpr(t3)),
mkU64(0x0),
mkU64(0x4)));
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x4), mkexpr(t3)),
mkU64(0x0),
mkU64(0x3)));
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x5), mkexpr(t3)),
mkU64(0x0),
mkU64(0x2)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)),
mkU64(0x0),
mkU64(0x1)));
/* Store X_byte on the right place. */
store(binop(Iop_Add64, mkexpr(t2), mkU64(0x7)), mkexpr(A_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
store(mkexpr(t1), mkexpr(H_byte));
#else /* _MIPSEB */
/* Calculate X_byte position. */
assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x5), mkexpr(t3)),
mkU64(0x6),
mkU64(0x0)));
assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x4), mkexpr(t3)),
mkU64(0x5),
mkU64(0x0)));
assign(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x3), mkexpr(t3)),
mkU64(0x4),
mkU64(0x0)));
assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x2), mkexpr(t3)),
mkU64(0x3),
mkU64(0x0)));
assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x1), mkexpr(t3)),
mkU64(0x2),
mkU64(0x0)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
mkU64(0x0),
mkU64(0x1)));
/* Store X_byte on the right place. */
store(mkexpr(t2), mkexpr(A_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(B_pos)), mkexpr(B_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(C_pos)), mkexpr(C_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(D_pos)), mkexpr(D_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(E_pos)), mkexpr(E_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
store(mkexpr(t1), mkexpr(H_byte));
#endif
break;
}
case 0x0E: /* SWR */
DIP("swr r%u, %u(r%u)", rt, imm, rs);
if (mode64) {
IRTemp E_byte = newTemp(Ity_I8);
IRTemp F_byte = newTemp(Ity_I8);
IRTemp G_byte = newTemp(Ity_I8);
IRTemp H_byte = newTemp(Ity_I8);
IRTemp F_pos = newTemp(Ity_I64);
IRTemp G_pos = newTemp(Ity_I64);
/* H byte */
assign(H_byte, getByteFromReg(rt, 0));
/* G byte */
assign(G_byte, getByteFromReg(rt, 1));
/* F byte */
assign(F_byte, getByteFromReg(rt, 2));
/* E byte */
assign(E_byte, getByteFromReg(rt, 3));
/* t1 = addr */
t1 = newTemp(Ity_I64);
assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm))));
/* t2 = word addr */
t2 = newTemp(Ity_I64);
assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL)));
/* t3 = addr mod 4 */
t3 = newTemp(Ity_I64);
assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x3)));
#if defined (_MIPSEL)
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
mkU64(0x2),
mkU64(0x3)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
mkU64(0x0),
mkU64(0x1)));
/* Store X_byte on the right place. */
store(binop(Iop_Add64, mkexpr(t2), mkU64(0x3)), mkexpr(E_byte));
store(binop(Iop_Add64, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Add64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
store(mkexpr(t1), mkexpr(H_byte));
#else /* _MIPSEB */
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)),
mkU64(0x1),
mkU64(0x0)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)),
mkU64(0x0),
mkU64(0x1)));
/* Store X_byte on the right place. */
store(mkexpr(t2), mkexpr(E_byte));
store(binop(Iop_Add64, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Sub64, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
store(mkexpr(t1), mkexpr(H_byte));
#endif
} else {
IRTemp E_byte = newTemp(Ity_I8);
IRTemp F_byte = newTemp(Ity_I8);
IRTemp G_byte = newTemp(Ity_I8);
IRTemp H_byte = newTemp(Ity_I8);
IRTemp F_pos = newTemp(Ity_I32);
IRTemp G_pos = newTemp(Ity_I32);
/* H byte */
assign(H_byte, getByteFromReg(rt, 0));
/* G byte */
assign(G_byte, getByteFromReg(rt, 1));
/* F byte */
assign(F_byte, getByteFromReg(rt, 2));
/* E byte */
assign(E_byte, getByteFromReg(rt, 3));
/* t1 = addr */
t1 = newTemp(Ity_I32);
assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
/* t2 = word addr */
t2 = newTemp(Ity_I32);
assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFCULL)));
/* t3 = addr mod 4 */
t3 = newTemp(Ity_I32);
assign(t3, binop(Iop_And32, mkexpr(t1), mkU32(0x3)));
#if defined (_MIPSEL)
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
mkU32(0x2),
mkU32(0x3)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
mkU32(0x0),
mkU32(0x1)));
/* Store X_byte on the right place. */
store(binop(Iop_Add32, mkexpr(t2), mkU32(0x3)), mkexpr(E_byte));
store(binop(Iop_Add32, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Add32, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
store(mkexpr(t1), mkexpr(H_byte));
#else /* _MIPSEB */
/* Calculate X_byte position. */
assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)),
mkU32(0x1),
mkU32(0x0)));
assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)),
mkU32(0x0),
mkU32(0x1)));
/* Store X_byte on the right place. */
store(mkexpr(t2), mkexpr(E_byte));
store(binop(Iop_Add32, mkexpr(t2), mkexpr(F_pos)), mkexpr(F_byte));
store(binop(Iop_Sub32, mkexpr(t1), mkexpr(G_pos)), mkexpr(G_byte));
store(mkexpr(t1), mkexpr(H_byte));
#endif
}
break;
}
return 0;
}
static UInt disInstr_MIPS_WRK_30(UInt cins, const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo, DisResult* dres,
IRStmt** bstmt)
{
IRTemp t0, t1 = 0, t2, t3, t4, t5;
UInt opcode, rs, rt, rd, ft, function, imm, instr_index;
opcode = get_opcode(cins);
imm = get_imm(cins);
rs = get_rs(cins);
rt = get_rt(cins);
rd = get_rd(cins);
ft = get_ft(cins);
instr_index = get_instr_index(cins);
function = get_function(cins);
IRType ty = mode64 ? Ity_I64 : Ity_I32;
switch (opcode & 0x0F) {
case 0x00: /* LL */
DIP("ll r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
if (abiinfo->guest__use_fallback_LLSC) {
t2 = newTemp(ty);
assign(t2, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True));
putLLaddr(mkexpr(t1));
putLLdata(mkexpr(t2));
putIReg(rt, mkexpr(t2));
} else {
t2 = newTemp(Ity_I32);
stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), NULL));
putIReg(rt, mkWidenFrom32(ty, mkexpr(t2), True));
}
break;
case 0x01: /* LWC1 */
/* Load Word to Floating Point - LWC1 (MIPS32) */
DIP("lwc1 f%u, %u(r%u)", ft, imm, rs);
LOAD_STORE_PATTERN;
if (fp_mode64) {
t0 = newTemp(Ity_F32);
t2 = newTemp(Ity_I64);
assign(t0, load(Ity_F32, mkexpr(t1)));
assign(t2, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32,
mkexpr(t0)), True));
putDReg(ft, unop(Iop_ReinterpI64asF64, mkexpr(t2)));
} else {
putFReg(ft, load(Ity_F32, mkexpr(t1)));
}
break;
case 0x02: /* Branch on Bit Clear - BBIT0; Cavium OCTEON */
/* Cavium Specific instructions. */
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
DIP("bbit0 r%u, 0x%x, %x", rs, rt, imm);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
assign(t0, mkU32(0x1));
assign(t1, binop(Iop_Shl32, mkexpr(t0), mkU8(rt)));
dis_branch(False, binop(Iop_CmpEQ32,
binop(Iop_And32,
mkexpr(t1),
mkNarrowTo32(ty, getIReg(rs))),
mkU32(0x0)),
imm, bstmt);
} else if (archinfo->hwcaps & VEX_MIPS_CPU_ISA_M32R6) { /* BC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("bc %x", instr_index & 0x3FFFFFF);
if (mode64) {
t0 = newTemp(Ity_I64);
assign(t0, mkU64(guest_PC_curr_instr +
((extend_s_26to64(instr_index & 0x3FFFFFF) + 1 ) << 2)));
} else {
t0 = newTemp(Ity_I32);
assign(t0, mkU32(guest_PC_curr_instr +
((extend_s_26to32(instr_index & 0x3FFFFFF) + 1) << 2)));
}
putPC(mkexpr(t0));
dres->whatNext = Dis_StopHere;
dres->jk_StopHere = Ijk_Boring;
} else {
ILLEGAL_INSTRUCTON;
break;
}
} else {
return -1;
}
break;
case 0x03: /* PREF */
DIP("pref");
break;
case 0x04: /* Load Linked Doubleword - LLD; MIPS64 */
DIP("lld r%u, %u(r%u)", rt, imm, rs);
if (mode64) {
LOAD_STORE_PATTERN;
t2 = newTemp(Ity_I64);
if (abiinfo->guest__use_fallback_LLSC) {
assign(t2, load(Ity_I64, mkexpr(t1)));
putLLaddr(mkexpr(t1));
putLLdata(mkexpr(t2));
} else {
stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), NULL));
}
putIReg(rt, mkexpr(t2));
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x05: /* Load Doubleword to Floating Point - LDC1 (MIPS32) */
DIP("ldc1 f%u, %u(%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
putDReg(ft, load(Ity_F64, mkexpr(t1)));
break;
case 0x06: /* Branch on Bit Clear Plus 32 - BBIT032; Cavium OCTEON */
/* Cavium Specific instructions. */
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
DIP("bbit032 r%u, 0x%x, %x", rs, rt, imm);
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I8); /* Shift. */
t2 = newTemp(Ity_I64);
assign(t0, mkU64(0x1));
assign(t1, binop(Iop_Add8, mkU8(rt), mkU8(32)));
assign(t2, binop(Iop_Shl64, mkexpr(t0), mkexpr(t1)));
dis_branch(False, binop(Iop_CmpEQ64,
binop(Iop_And64,
mkexpr(t2),
getIReg(rs)),
mkU64(0x0)),
imm, bstmt);
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (rs == 0) { /* JIC */
DIP("jic r%u, %u", rt, instr_index & 0xFFFF);
if (mode64) {
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_Add64, getIReg(rt),
mkU64(extend_s_16to64((instr_index & 0xFFFF)))));
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_Add32, getIReg(rt),
mkU32(extend_s_16to32((instr_index & 0xFFFF)))));
}
putPC(mkexpr(t0));
dres->whatNext = Dis_StopHere;
dres->jk_StopHere = Ijk_Boring;
} else { /* BEQZC */
DIP("beqzc r%u, %u", rs, imm);
dres->jk_StopHere = Ijk_Boring;
dres->whatNext = Dis_StopHere;
ULong branch_offset;
t0 = newTemp(Ity_I1);
if (mode64) {
branch_offset = extend_s_23to64((instr_index & 0x1fffff) << 2);
assign(t0, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0x0)));
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U64(guest_PC_curr_instr + 4 + branch_offset),
OFFB_PC));
putPC(mkU64(guest_PC_curr_instr + 4));
} else {
branch_offset = extend_s_23to32((instr_index & 0x1fffff) << 2);
assign(t0, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x0)));
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U32(guest_PC_curr_instr + 4 +
(UInt) branch_offset), OFFB_PC));
putPC(mkU32(guest_PC_curr_instr + 4));
}
}
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x07: /* Load Doubleword - LD; MIPS64 */
DIP("ld r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
putIReg(rt, load(Ity_I64, mkexpr(t1)));
break;
case 0x08: /* SC */
DIP("sc r%u, %u(r%u)", rt, imm, rs);
t2 = newTemp(Ity_I1);
LOAD_STORE_PATTERN;
if (abiinfo->guest__use_fallback_LLSC) {
t3 = newTemp(Ity_I32);
assign(t2, binop(mode64 ? Iop_CmpNE64 : Iop_CmpNE32,
mkexpr(t1), getLLaddr()));
assign(t3, mkNarrowTo32(ty, getIReg(rt)));
putLLaddr(LLADDR_INVALID);
putIReg(rt, getIReg(0));
mips_next_insn_if(mkexpr(t2));
t4 = newTemp(Ity_I32);
t5 = newTemp(Ity_I32);
assign(t5, mkNarrowTo32(ty, getLLdata()));
stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */
MIPS_IEND, mkexpr(t1), /* addr */
NULL, mkexpr(t5), /* expected value */
NULL, mkexpr(t3) /* new value */)));
putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32,
binop(Iop_CmpEQ32, mkexpr(t4), mkexpr(t5))));
} else {
stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1),
mkNarrowTo32(ty, getIReg(rt))));
putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, mkexpr(t2)));
}
break;
case 0x09: /* SWC1 */
DIP("swc1 f%u, %u(r%u)", ft, imm, rs);
if (fp_mode64) {
t0 = newTemp(Ity_I64);
t2 = newTemp(Ity_I32);
LOAD_STORE_PATTERN;
assign(t0, unop(Iop_ReinterpF64asI64, getFReg(ft)));
assign(t2, unop(Iop_64to32, mkexpr(t0)));
store(mkexpr(t1), unop(Iop_ReinterpI32asF32, mkexpr(t2)));
} else {
LOAD_STORE_PATTERN;
store(mkexpr(t1), getFReg(ft));
}
break;
case 0x0A: /* Branch on Bit Set - BBIT1; Cavium OCTEON */
/* Cavium Specific instructions. */
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
DIP("bbit1 r%u, 0x%x, %x", rs, rt, imm);
t0 = newTemp(Ity_I32);
t1 = newTemp(Ity_I32);
assign(t0, mkU32(0x1));
assign(t1, binop(Iop_Shl32, mkexpr(t0), mkU8(rt)));
dis_branch(False, binop(Iop_CmpNE32,
binop(Iop_And32,
mkexpr(t1),
mkNarrowTo32(ty, getIReg(rs))),
mkU32(0x0)),
imm, bstmt);
} else if (archinfo->hwcaps & VEX_MIPS_CPU_ISA_M32R6) {/* BALC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("balc %x", instr_index & 0x3FFFFFF);
if (mode64) {
t0 = newTemp(Ity_I64);
assign(t0, mkU64(guest_PC_curr_instr + ((extend_s_26to64(
instr_index & 0x3FFFFFF) + 1) << 2)));
putIReg(31, mkU64(guest_PC_curr_instr + 4));
} else {
t0 = newTemp(Ity_I32);
assign(t0, mkU32(guest_PC_curr_instr + ((extend_s_26to32(
instr_index & 0x3FFFFFF) + 1) << 2)));
putIReg(31, mkU32(guest_PC_curr_instr + 4));
}
putPC(mkexpr(t0));
dres->whatNext = Dis_StopHere;
dres->jk_StopHere = Ijk_Call;
} else {
ILLEGAL_INSTRUCTON;
break;
}
} else {
return -1;
}
break;
case 0x0B: /* PCREL */
if (rt == 0x1E) { /* AUIPC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("auipc r%u, %u", rs, imm);
if (mode64) {
putIReg(rs, mkU64(guest_PC_curr_instr + (imm << 16)));
} else {
putIReg(rs, mkU32(guest_PC_curr_instr + (imm << 16)));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if (rt == 0x1F) { /* ALUIPC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("aluipc r%u, %u", rs, imm);
if (mode64) {
putIReg(rs, mkU64((~0x0FFFFULL) &
(guest_PC_curr_instr + extend_s_32to64(imm << 16))));
} else {
putIReg(rs, mkU32((~0x0FFFFULL) &
(guest_PC_curr_instr + (imm << 16))));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if ((rt & 0x18) == 0) { /* ADDIUPC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("addiupc r%u, %u", rs, instr_index & 0x7FFFF);
if (mode64) {
putIReg(rs, mkU64(guest_PC_curr_instr +
(extend_s_19to64(instr_index & 0x7FFFF) << 2)));
} else {
putIReg(rs, mkU32(guest_PC_curr_instr +
(extend_s_19to32(instr_index & 0x7FFFF) << 2)));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if ((rt & 0x18) == 8) { /* LWPC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("lwpc r%u, %x", rs, instr_index & 0x7FFFF);
if (mode64) {
t1 = newTemp(Ity_I64);
assign(t1, mkU64(guest_PC_curr_instr +
(extend_s_19to64(instr_index & 0x7FFFF) << 2)));
putIReg(rs, unop(Iop_32Sto64, load(Ity_I32, mkexpr(t1))));
} else {
t1 = newTemp(Ity_I32);
assign(t1, mkU32(guest_PC_curr_instr +
(extend_s_19to32(instr_index & 0x7FFFF) << 2)));
putIReg(rs, load(Ity_I32, mkexpr(t1)));
}
} else {
ILLEGAL_INSTRUCTON;
}
break;
} else if ((rt & 0x18) == 16) { /* LWUPC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("lwupc r%u, %x", rs, instr_index & 0x7FFFF);
if (mode64) {
t1 = newTemp(Ity_I64);
assign(t1, mkU64(guest_PC_curr_instr +
(extend_s_19to64(instr_index & 0x7FFFF) << 2)));
putIReg(rs, unop(Iop_32Uto64, load(Ity_I32, mkexpr(t1))));
} else {
t1 = newTemp(Ity_I32);
assign(t1, mkU32(guest_PC_curr_instr +
(extend_s_19to32(instr_index & 0x7FFFF) << 2)));
putIReg(rs, load(Ity_I32, mkexpr(t1)));
}
} else {
ILLEGAL_INSTRUCTON
}
break;
} else if ((rt & 0x1C) == 0x18) { /* LDPC */
if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
DIP("ldpc r%u, %x", rs, instr_index & 0x3FFFF);
t1 = newTemp(Ity_I64);
assign(t1, mkU64(guest_PC_curr_instr +
(extend_s_18to64(instr_index & 0x3FFFF) << 3)));
putIReg(rs, load(Ity_I64, mkexpr(t1)));
} else {
ILLEGAL_INSTRUCTON
}
break;
} else {
return -1;
}
if (0x3B == function &&
(VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_BROADCOM)) {
/*RDHWR*/
DIP("rdhwr r%u, r%u", rt, rd);
if (rd == 29) {
putIReg(rt, getULR());
} else
return -1;
break;
} else {
return -1;
}
case 0x0C: /* Store Conditional Doubleword - SCD; MIPS64 */
DIP("scd r%u, %u(r%u)", rt, imm, rs);
if (mode64) {
t2 = newTemp(Ity_I1);
LOAD_STORE_PATTERN;
if (abiinfo->guest__use_fallback_LLSC) {
t3 = newTemp(Ity_I64);
assign(t2, binop(Iop_CmpNE64, mkexpr(t1), getLLaddr()));
assign(t3, getIReg(rt));
putLLaddr(LLADDR_INVALID);
putIReg(rt, getIReg(0));
mips_next_insn_if(mkexpr(t2));
t4 = newTemp(Ity_I64);
t5 = newTemp(Ity_I64);
assign(t5, getLLdata());
stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */
MIPS_IEND, mkexpr(t1), /* addr */
NULL, mkexpr(t5), /* expected value */
NULL, mkexpr(t3) /* new value */)));
putIReg(rt, unop(Iop_1Uto64,
binop(Iop_CmpEQ64, mkexpr(t4), mkexpr(t5))));
} else {
stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), getIReg(rt)));
putIReg(rt, unop(Iop_1Uto64, mkexpr(t2)));
}
} else {
ILLEGAL_INSTRUCTON
}
break;
case 0x0D: /* Store Doubleword from Floating Point - SDC1 */
DIP("sdc1 f%u, %u(%u)", ft, imm, rs);
LOAD_STORE_PATTERN;
store(mkexpr(t1), getDReg(ft));
break;
case 0x0E: /* Branch on Bit Set Plus 32 - BBIT132; Cavium OCTEON */
/* Cavium Specific instructions. */
if (VEX_MIPS_COMP_ID(archinfo->hwcaps) == VEX_PRID_COMP_CAVIUM) {
DIP("bbit132 r%u, 0x%x, %x", rs, rt, imm);
t0 = newTemp(Ity_I64);
t1 = newTemp(Ity_I8); /* Shift. */
t2 = newTemp(Ity_I64);
assign(t0, mkU64(0x1));
assign(t1, binop(Iop_Add8, mkU8(rt), mkU8(32)));
assign(t2, binop(Iop_Shl64, mkexpr(t0), mkexpr(t1)));
dis_branch(False, binop(Iop_CmpNE64,
binop(Iop_And64,
mkexpr(t2),
getIReg(rs)),
mkU64(0x0)),
imm, bstmt);
} else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) {
if (rs == 0) {/* JIALC */
DIP("jialc r%u, %u", rt, instr_index & 0xFFFF);
if (rs) return -1;
if (mode64) {
t0 = newTemp(Ity_I64);
assign(t0, binop(Iop_Add64, getIReg(rt),
mkU64(extend_s_16to64((instr_index & 0xFFFF)))));
putIReg(31, mkU64(guest_PC_curr_instr + 4));
} else {
t0 = newTemp(Ity_I32);
assign(t0, binop(Iop_Add32, getIReg(rt),
mkU32(extend_s_16to32((instr_index & 0xFFFF)))));
putIReg(31, mkU32(guest_PC_curr_instr + 4));
}
putPC(mkexpr(t0));
dres->whatNext = Dis_StopHere;
dres->jk_StopHere = Ijk_Call;
} else { /* BNEZC */
DIP("bnezc r%u, %u", rs, imm);
dres->jk_StopHere = Ijk_Boring;
dres->whatNext = Dis_StopHere;
ULong branch_offset;
t0 = newTemp(Ity_I1);
if (mode64) {
branch_offset = extend_s_23to64((instr_index & 0x1fffff) << 2);
assign(t0, unop(Iop_Not1, binop(Iop_CmpEQ64, getIReg(rs), mkU64(0x0))));
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U64(guest_PC_curr_instr + 4 + branch_offset),
OFFB_PC));
putPC(mkU64(guest_PC_curr_instr + 4));
} else {
branch_offset = extend_s_23to32((instr_index & 0x1fffff) << 2);
assign(t0, unop(Iop_Not1, binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x0))));
stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
IRConst_U32(guest_PC_curr_instr + 4 +
(UInt) branch_offset), OFFB_PC));
putPC(mkU32(guest_PC_curr_instr + 4));
}
}
} else {
return -1;
}
break;
case 0x0F: /* Store Doubleword - SD; MIPS64 */
DIP("sd r%u, %u(r%u)", rt, imm, rs);
LOAD_STORE_PATTERN;
store(mkexpr(t1), getIReg(rt));
break;
default:
return -1;
}
return 0;
}
static DisResult disInstr_MIPS_WRK ( Long delta64,
const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo,
Bool sigill_diag )
{
UInt opcode, cins, result;
DisResult dres;
static IRExpr *lastn = NULL; /* last jump addr */
static IRStmt *bstmt = NULL; /* branch (Exit) stmt */
/* The running delta */
Int delta = (Int) delta64;
/* Holds eip at the start of the insn, so that we can print
consistent error messages for unimplemented insns. */
Int delta_start = delta;
/* Are we in a delay slot ? */
Bool delay_slot_branch, likely_delay_slot, delay_slot_jump;
/* Set result defaults. */
dres.whatNext = Dis_Continue;
dres.len = 0;
dres.jk_StopHere = Ijk_INVALID;
dres.hint = Dis_HintNone;
delay_slot_branch = likely_delay_slot = delay_slot_jump = False;
const UChar *code = guest_code + delta;
cins = getUInt(code);
opcode = get_opcode(cins);
DIP("\t0x%llx:\t0x%08x\t", (Addr64)guest_PC_curr_instr, cins);
if (delta != 0) {
if (branch_or_jump(guest_code + delta - 4)
&& (lastn != NULL || bstmt != NULL)) {
dres.whatNext = Dis_StopHere;
delay_slot_jump = (lastn != NULL);
delay_slot_branch = (bstmt != NULL);
}
likely_delay_slot = (lastn != NULL)
&& branch_or_link_likely(guest_code + delta - 4);
}
// Emit an Illegal instruction in case a branch/jump
// instruction is encountered in the delay slot
// of an another branch/jump
if ((delay_slot_branch || likely_delay_slot || delay_slot_jump) &&
(branch_or_jump(guest_code + delta) ||
branch_or_link_likely(guest_code + delta))) {
if (mode64)
putPC(mkU64(guest_PC_curr_instr + 4));
else
putPC(mkU32(guest_PC_curr_instr + 4));
dres.jk_StopHere = Ijk_SigILL;
dres.whatNext = Dis_StopHere;
lastn = NULL;
bstmt = NULL;
return dres;
}
/* Spot "Special" instructions (see comment at top of file). */
{
/* Spot the 16-byte preamble:
****mips32****
"srl $0, $0, 13
"srl $0, $0, 29
"srl $0, $0, 3
"srl $0, $0, 19
****mips64****
dsll $0, $0, 3
dsll $0, $0, 13
dsll $0, $0, 29
dsll $0, $0, 19 */
UInt word1 = mode64 ? 0xF8 : 0x342;
UInt word2 = mode64 ? 0x378 : 0x742;
UInt word3 = mode64 ? 0x778 : 0xC2;
UInt word4 = mode64 ? 0x4F8 : 0x4C2;
if (getUInt(code + 0) == word1 && getUInt(code + 4) == word2 &&
getUInt(code + 8) == word3 && getUInt(code + 12) == word4) {
/* Got a "Special" instruction preamble. Which one is it? */
if (getUInt(code + 16) == 0x01ad6825 /* or $13, $13, $13 */ ) {
/* $11 = client_request ( $12 ) */
DIP("$11 = client_request ( $12 )");
if (mode64)
putPC(mkU64(guest_PC_curr_instr + 20));
else
putPC(mkU32(guest_PC_curr_instr + 20));
dres.jk_StopHere = Ijk_ClientReq;
dres.whatNext = Dis_StopHere;
goto decode_success;
} else if (getUInt(code + 16) == 0x01ce7025 /* or $14, $14, $14 */ ) {
/* $11 = guest_NRADDR */
DIP("$11 = guest_NRADDR");
dres.len = 20;
delta += 20;
if (mode64)
putIReg(11, IRExpr_Get(offsetof(VexGuestMIPS64State,
guest_NRADDR), Ity_I64));
else
putIReg(11, IRExpr_Get(offsetof(VexGuestMIPS32State,
guest_NRADDR), Ity_I32));
goto decode_success;
} else if (getUInt(code + 16) == 0x01ef7825 /* or $15, $15, $15 */ ) {
/* branch-and-link-to-noredir $25 */
DIP("branch-and-link-to-noredir $25");
if (mode64)
putIReg(31, mkU64(guest_PC_curr_instr + 20));
else
putIReg(31, mkU32(guest_PC_curr_instr + 20));
putPC(getIReg(25));
dres.jk_StopHere = Ijk_NoRedir;
dres.whatNext = Dis_StopHere;
goto decode_success;
} else if (getUInt(code + 16) == 0x016b5825 /* or $11,$11,$11 */ ) {
/* IR injection */
DIP("IR injection");
#if defined (_MIPSEL)
vex_inject_ir(irsb, Iend_LE);
#elif defined (_MIPSEB)
vex_inject_ir(irsb, Iend_BE);
#endif
if (mode64) {
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_CMSTART),
mkU64(guest_PC_curr_instr)));
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_CMLEN),
mkU64(20)));
putPC(mkU64(guest_PC_curr_instr + 20));
} else {
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_CMSTART),
mkU32(guest_PC_curr_instr)));
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_CMLEN),
mkU32(20)));
putPC(mkU32(guest_PC_curr_instr + 20));
}
dres.whatNext = Dis_StopHere;
dres.jk_StopHere = Ijk_InvalICache;
dres.len = 20;
delta += 20;
goto decode_success;
}
/* We don't know what it is. Set opc1/opc2 so decode_failure
can print the insn following the Special-insn preamble. */
delta += 16;
goto decode_failure;
/*NOTREACHED*/
}
}
switch (opcode & 0x30) {
case 0x00:
result = disInstr_MIPS_WRK_00(cins, archinfo, abiinfo,
&dres, &bstmt, &lastn);
if (result == -1) goto decode_failure;
if (result == -2) goto decode_failure_dsp;
break;
case 0x10:
result = disInstr_MIPS_WRK_10(cins, archinfo, abiinfo,
&dres, &bstmt, &lastn);
if (result == -1) goto decode_failure;
if (result == -2) goto decode_failure_dsp;
break;
case 0x20:
result = disInstr_MIPS_WRK_20(cins);
if (result == -1) goto decode_failure;
if (result == -2) goto decode_failure_dsp;
break;
case 0x30:
result = disInstr_MIPS_WRK_30(cins, archinfo, abiinfo, &dres, &bstmt);
if (result == -1) goto decode_failure;
if (result == -2) goto decode_failure_dsp;
break;
decode_failure_dsp:
vex_printf("Error occured while trying to decode MIPS32 DSP "
"instruction.\nYour platform probably doesn't support "
"MIPS32 DSP ASE.\n");
decode_failure:
/* All decode failures end up here. */
if (sigill_diag)
vex_printf("vex mips->IR: unhandled instruction bytes: "
"0x%x 0x%x 0x%x 0x%x\n",
(UInt) getIByte(delta_start + 0),
(UInt) getIByte(delta_start + 1),
(UInt) getIByte(delta_start + 2),
(UInt) getIByte(delta_start + 3));
/* Tell the dispatcher that this insn cannot be decoded, and so has
not been executed, and (is currently) the next to be executed.
EIP should be up-to-date since it made so at the start bnezof each
insn, but nevertheless be paranoid and update it again right
now. */
if (mode64) {
stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_PC),
mkU64(guest_PC_curr_instr)));
jmp_lit64(&dres, Ijk_NoDecode, guest_PC_curr_instr);
} else {
stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_PC),
mkU32(guest_PC_curr_instr)));
jmp_lit32(&dres, Ijk_NoDecode, guest_PC_curr_instr);
}
dres.whatNext = Dis_StopHere;
dres.len = 0;
return dres;
} /* switch (opc) for the main (primary) opcode switch. */
/* All MIPS insn have 4 bytes */
if (delay_slot_branch) {
delay_slot_branch = False;
stmt(bstmt);
bstmt = NULL;
if (mode64)
putPC(mkU64(guest_PC_curr_instr + 4));
else
putPC(mkU32(guest_PC_curr_instr + 4));
dres.jk_StopHere = is_Branch_or_Jump_and_Link(guest_code + delta - 4) ?
Ijk_Call : Ijk_Boring;
}
if (likely_delay_slot) {
dres.jk_StopHere = Ijk_Boring;
dres.whatNext = Dis_StopHere;
putPC(lastn);
lastn = NULL;
}
if (delay_slot_jump) {
putPC(lastn);
lastn = NULL;
dres.jk_StopHere = is_Branch_or_Jump_and_Link(guest_code + delta - 4) ?
Ijk_Call : Ijk_Boring;
}
decode_success:
dres.len = 4;
DIP("\n");
/* All decode successes end up here. */
switch (dres.whatNext) {
case Dis_Continue:
if (branch_or_jump(guest_code + delta) ||
branch_or_link_likely(guest_code + delta)) {
guest_PC_curr_instr += 4;
dres = disInstr_MIPS_WRK(delta64 + 4, archinfo, abiinfo, sigill_diag);
dres.len = 8;
} else {
if (mode64)
putPC(mkU64(guest_PC_curr_instr + 4));
else
putPC(mkU32(guest_PC_curr_instr + 4));
}
break;
case Dis_StopHere:
break;
default:
vassert(0);
break;
}
/* On MIPS we need to check if the last instruction in block is branch or
jump. */
if (((vex_control.guest_max_insns - 1) == (delta + 4) / 4)
&& (dres.whatNext != Dis_StopHere))
if (branch_or_jump(guest_code + delta + 4)) {
dres.whatNext = Dis_StopHere;
dres.jk_StopHere = Ijk_Boring;
if (mode64)
putPC(mkU64(guest_PC_curr_instr + 4));
else
putPC(mkU32(guest_PC_curr_instr + 4));
}
return dres;
}
/*------------------------------------------------------------*/
/*--- Top-level fn ---*/
/*------------------------------------------------------------*/
/* Disassemble a single instruction into IR. The instruction
is located in host memory at &guest_code[delta]. */
DisResult disInstr_MIPS( IRSB* irsb_IN,
const UChar* guest_code_IN,
Long delta,
Addr guest_IP,
VexArch guest_arch,
const VexArchInfo* archinfo,
const VexAbiInfo* abiinfo,
VexEndness host_endness_IN,
Bool sigill_diag_IN )
{
DisResult dres;
/* Set globals (see top of this file) */
vassert(guest_arch == VexArchMIPS32 || guest_arch == VexArchMIPS64);
mode64 = guest_arch != VexArchMIPS32;
fp_mode64 = abiinfo->guest_mips_fp_mode & 1;
fp_mode64_fre = abiinfo->guest_mips_fp_mode & 2;
has_msa = VEX_MIPS_PROC_MSA(archinfo->hwcaps);
vassert(VEX_MIPS_HOST_FP_MODE(archinfo->hwcaps) >= fp_mode64);
guest_code = guest_code_IN;
irsb = irsb_IN;
host_endness = host_endness_IN;
#if defined(VGP_mips32_linux)
guest_PC_curr_instr = (Addr32)guest_IP;
#elif defined(VGP_mips64_linux)
guest_PC_curr_instr = (Addr64)guest_IP;
#endif
dres = disInstr_MIPS_WRK(delta, archinfo, abiinfo, sigill_diag_IN);
return dres;
}
/*--------------------------------------------------------------------*/
/*--- end guest_mips_toIR.c ---*/
/*--------------------------------------------------------------------*/