From: Petar Jovanovic Date: Wed, 27 Mar 2019 18:42:05 +0000 (+0000) Subject: mips: code refactoring (NFC) X-Git-Tag: VALGRIND_3_15_0~33 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=92ecddd13ea52003c0c8fd0a3300411005c8d6b3;p=thirdparty%2Fvalgrind.git mips: code refactoring (NFC) Code in VEX/priv/guest_mips_toIR.c is notably refactored. DSP ASE dissasembly has been put in a separate file: guest_mipsdsp_toIR.c. Patch by Aleksandar Rikalo. --- diff --git a/Makefile.vex.am b/Makefile.vex.am index 2b54b8a55b..10e1890f63 100644 --- a/Makefile.vex.am +++ b/Makefile.vex.am @@ -47,6 +47,7 @@ noinst_HEADERS = \ priv/guest_arm64_defs.h \ priv/guest_s390_defs.h \ priv/guest_mips_defs.h \ + priv/mips_defs.h \ priv/host_generic_regs.h \ priv/host_generic_simd64.h \ priv/host_generic_simd128.h \ @@ -143,6 +144,7 @@ LIBVEX_SOURCES_COMMON = \ priv/guest_s390_helpers.c \ priv/guest_s390_toIR.c \ priv/guest_mips_helpers.c \ + priv/guest_mipsdsp_toIR.c \ priv/guest_mips_toIR.c \ priv/host_generic_regs.c \ priv/host_generic_simd64.c \ diff --git a/VEX/Makefile-gcc b/VEX/Makefile-gcc index 0822712deb..0b94e13c5f 100644 --- a/VEX/Makefile-gcc +++ b/VEX/Makefile-gcc @@ -34,6 +34,7 @@ PRIV_HEADERS = priv/host_x86_defs.h \ priv/guest_arm_defs.h \ priv/guest_ppc_defs.h \ priv/guest_mips_defs.h \ + priv/mips_defs.h \ priv/s390_disasm.h \ priv/s390_defs.h \ priv/ir_match.h \ @@ -82,6 +83,7 @@ LIB_OBJS = priv/ir_defs.o \ priv/guest_arm64_toIR.o \ priv/guest_ppc_toIR.o \ priv/guest_s390_toIR.o \ + priv/guest_mipsdsp_toIR.o \ priv/guest_mips_toIR.o PUB_INCLUDES = -Ipub @@ -409,6 +411,10 @@ priv/guest_mips_helpers.o: $(ALL_HEADERS) priv/guest_mips_helpers.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest_mips_helpers.o \ -c priv/guest_mips_helpers.c +priv/guest_mipsdsp_toIR.o: $(ALL_HEADERS) priv/guest_mipsdsp_toIR.c + $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest_mipsdsp_toIR.o \ + -c priv/guest_mipsdsp_toIR.c + priv/guest_mips_toIR.o: $(ALL_HEADERS) priv/guest_mips_toIR.c $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest_mips_toIR.o \ -c priv/guest_mips_toIR.c diff --git a/VEX/priv/guest_mips_toIR.c b/VEX/priv/guest_mips_toIR.c old mode 100644 new mode 100755 index 4748ba4f30..eb437ec084 --- a/VEX/priv/guest_mips_toIR.c +++ b/VEX/priv/guest_mips_toIR.c @@ -40,6 +40,7 @@ #include "main_globals.h" #include "guest_generic_bb_to_IR.h" #include "guest_mips_defs.h" +#include "mips_defs.h" /*------------------------------------------------------------*/ /*--- Globals ---*/ @@ -55,7 +56,7 @@ static VexEndness host_endness; /* Pointer to the guest code area. */ -static const UChar *guest_code; +const UChar *guest_code; /* CONST: The guest address for the instruction currently being translated. */ @@ -66,14 +67,14 @@ static Addr64 guest_PC_curr_instr; #endif /* MOD: The IRSB* into which we're generating code. */ -static IRSB *irsb; +IRSB *irsb; /* Is our guest binary 32 or 64bit? Set at each call to disInstr_MIPS below. */ -static Bool mode64 = False; +Bool mode64 = False; /* CPU has FPU and 32 dbl. prec. FP registers. */ -static Bool fp_mode64 = False; + static Bool fp_mode64 = False; /* FPU works in FRE mode */ static Bool fp_mode64_fre = False; @@ -85,14 +86,6 @@ static Bool has_msa = False; #define ONE_SINGLE 0x3F800000 #define ONE_DOUBLE 0x3FF0000000000000ULL -/*------------------------------------------------------------*/ -/*--- Debugging output ---*/ -/*------------------------------------------------------------*/ - -#define DIP(format, args...) \ - if (vex_traceflags & VEX_TRACE_FE) \ - vex_printf(format, ## args) - /*------------------------------------------------------------*/ /*--- Helper bits and pieces for deconstructing the ---*/ /*--- mips insn stream. ---*/ @@ -106,12812 +99,6014 @@ static UInt integerGuestRegOffset(UInt iregNo) 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 ---------------- */ - -static 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) { + switch (iregNo) { case 0: - ret = offsetof(VexGuestMIPS64State, guest_w0); + ret = offsetof(VexGuestMIPS32State, guest_r0); break; case 1: - ret = offsetof(VexGuestMIPS64State, guest_w1); + ret = offsetof(VexGuestMIPS32State, guest_r1); break; case 2: - ret = offsetof(VexGuestMIPS64State, guest_w2); + ret = offsetof(VexGuestMIPS32State, guest_r2); break; case 3: - ret = offsetof(VexGuestMIPS64State, guest_w3); + ret = offsetof(VexGuestMIPS32State, guest_r3); break; case 4: - ret = offsetof(VexGuestMIPS64State, guest_w4); + ret = offsetof(VexGuestMIPS32State, guest_r4); break; case 5: - ret = offsetof(VexGuestMIPS64State, guest_w5); + ret = offsetof(VexGuestMIPS32State, guest_r5); break; case 6: - ret = offsetof(VexGuestMIPS64State, guest_w6); + ret = offsetof(VexGuestMIPS32State, guest_r6); break; case 7: - ret = offsetof(VexGuestMIPS64State, guest_w7); + ret = offsetof(VexGuestMIPS32State, guest_r7); break; case 8: - ret = offsetof(VexGuestMIPS64State, guest_w8); + ret = offsetof(VexGuestMIPS32State, guest_r8); break; case 9: - ret = offsetof(VexGuestMIPS64State, guest_w9); + ret = offsetof(VexGuestMIPS32State, guest_r9); break; case 10: - ret = offsetof(VexGuestMIPS64State, guest_w10); + ret = offsetof(VexGuestMIPS32State, guest_r10); break; case 11: - ret = offsetof(VexGuestMIPS64State, guest_w11); + ret = offsetof(VexGuestMIPS32State, guest_r11); break; case 12: - ret = offsetof(VexGuestMIPS64State, guest_w12); + ret = offsetof(VexGuestMIPS32State, guest_r12); break; case 13: - ret = offsetof(VexGuestMIPS64State, guest_w13); + ret = offsetof(VexGuestMIPS32State, guest_r13); break; case 14: - ret = offsetof(VexGuestMIPS64State, guest_w14); + ret = offsetof(VexGuestMIPS32State, guest_r14); break; case 15: - ret = offsetof(VexGuestMIPS64State, guest_w15); + ret = offsetof(VexGuestMIPS32State, guest_r15); break; case 16: - ret = offsetof(VexGuestMIPS64State, guest_w16); + ret = offsetof(VexGuestMIPS32State, guest_r16); break; case 17: - ret = offsetof(VexGuestMIPS64State, guest_w17); + ret = offsetof(VexGuestMIPS32State, guest_r17); break; case 18: - ret = offsetof(VexGuestMIPS64State, guest_w18); + ret = offsetof(VexGuestMIPS32State, guest_r18); break; case 19: - ret = offsetof(VexGuestMIPS64State, guest_w19); + ret = offsetof(VexGuestMIPS32State, guest_r19); break; case 20: - ret = offsetof(VexGuestMIPS64State, guest_w20); + ret = offsetof(VexGuestMIPS32State, guest_r20); break; case 21: - ret = offsetof(VexGuestMIPS64State, guest_w21); + ret = offsetof(VexGuestMIPS32State, guest_r21); break; case 22: - ret = offsetof(VexGuestMIPS64State, guest_w22); + ret = offsetof(VexGuestMIPS32State, guest_r22); break; case 23: - ret = offsetof(VexGuestMIPS64State, guest_w23); + ret = offsetof(VexGuestMIPS32State, guest_r23); break; case 24: - ret = offsetof(VexGuestMIPS64State, guest_w24); + ret = offsetof(VexGuestMIPS32State, guest_r24); break; case 25: - ret = offsetof(VexGuestMIPS64State, guest_w25); + ret = offsetof(VexGuestMIPS32State, guest_r25); break; case 26: - ret = offsetof(VexGuestMIPS64State, guest_w26); + ret = offsetof(VexGuestMIPS32State, guest_r26); break; case 27: - ret = offsetof(VexGuestMIPS64State, guest_w27); + ret = offsetof(VexGuestMIPS32State, guest_r27); break; case 28: - ret = offsetof(VexGuestMIPS64State, guest_w28); + ret = offsetof(VexGuestMIPS32State, guest_r28); break; case 29: - ret = offsetof(VexGuestMIPS64State, guest_w29); + ret = offsetof(VexGuestMIPS32State, guest_r29); break; case 30: - ret = offsetof(VexGuestMIPS64State, guest_w30); + ret = offsetof(VexGuestMIPS32State, guest_r30); break; case 31: - ret = offsetof(VexGuestMIPS64State, guest_w31); + ret = offsetof(VexGuestMIPS32State, guest_r31); break; default: vassert(0); break; } - } else { - switch (msaRegNo) { + else + switch (iregNo) { case 0: - ret = offsetof(VexGuestMIPS32State, guest_w0); + ret = offsetof(VexGuestMIPS64State, guest_r0); break; case 1: - ret = offsetof(VexGuestMIPS32State, guest_w1); + ret = offsetof(VexGuestMIPS64State, guest_r1); break; case 2: - ret = offsetof(VexGuestMIPS32State, guest_w2); + ret = offsetof(VexGuestMIPS64State, guest_r2); break; case 3: - ret = offsetof(VexGuestMIPS32State, guest_w3); + ret = offsetof(VexGuestMIPS64State, guest_r3); break; case 4: - ret = offsetof(VexGuestMIPS32State, guest_w4); + ret = offsetof(VexGuestMIPS64State, guest_r4); break; case 5: - ret = offsetof(VexGuestMIPS32State, guest_w5); + ret = offsetof(VexGuestMIPS64State, guest_r5); break; case 6: - ret = offsetof(VexGuestMIPS32State, guest_w6); + ret = offsetof(VexGuestMIPS64State, guest_r6); break; case 7: - ret = offsetof(VexGuestMIPS32State, guest_w7); + ret = offsetof(VexGuestMIPS64State, guest_r7); break; case 8: - ret = offsetof(VexGuestMIPS32State, guest_w8); + ret = offsetof(VexGuestMIPS64State, guest_r8); break; case 9: - ret = offsetof(VexGuestMIPS32State, guest_w9); + ret = offsetof(VexGuestMIPS64State, guest_r9); break; case 10: - ret = offsetof(VexGuestMIPS32State, guest_w10); + ret = offsetof(VexGuestMIPS64State, guest_r10); break; case 11: - ret = offsetof(VexGuestMIPS32State, guest_w11); + ret = offsetof(VexGuestMIPS64State, guest_r11); break; case 12: - ret = offsetof(VexGuestMIPS32State, guest_w12); + ret = offsetof(VexGuestMIPS64State, guest_r12); break; case 13: - ret = offsetof(VexGuestMIPS32State, guest_w13); + ret = offsetof(VexGuestMIPS64State, guest_r13); break; case 14: - ret = offsetof(VexGuestMIPS32State, guest_w14); + ret = offsetof(VexGuestMIPS64State, guest_r14); break; case 15: - ret = offsetof(VexGuestMIPS32State, guest_w15); + ret = offsetof(VexGuestMIPS64State, guest_r15); break; case 16: - ret = offsetof(VexGuestMIPS32State, guest_w16); + ret = offsetof(VexGuestMIPS64State, guest_r16); break; case 17: - ret = offsetof(VexGuestMIPS32State, guest_w17); + ret = offsetof(VexGuestMIPS64State, guest_r17); break; case 18: - ret = offsetof(VexGuestMIPS32State, guest_w18); + ret = offsetof(VexGuestMIPS64State, guest_r18); break; case 19: - ret = offsetof(VexGuestMIPS32State, guest_w19); + ret = offsetof(VexGuestMIPS64State, guest_r19); break; case 20: - ret = offsetof(VexGuestMIPS32State, guest_w20); + ret = offsetof(VexGuestMIPS64State, guest_r20); break; case 21: - ret = offsetof(VexGuestMIPS32State, guest_w21); + ret = offsetof(VexGuestMIPS64State, guest_r21); break; case 22: - ret = offsetof(VexGuestMIPS32State, guest_w22); + ret = offsetof(VexGuestMIPS64State, guest_r22); break; case 23: - ret = offsetof(VexGuestMIPS32State, guest_w23); + ret = offsetof(VexGuestMIPS64State, guest_r23); break; case 24: - ret = offsetof(VexGuestMIPS32State, guest_w24); + ret = offsetof(VexGuestMIPS64State, guest_r24); break; case 25: - ret = offsetof(VexGuestMIPS32State, guest_w25); + ret = offsetof(VexGuestMIPS64State, guest_r25); break; case 26: - ret = offsetof(VexGuestMIPS32State, guest_w26); + ret = offsetof(VexGuestMIPS64State, guest_r26); break; case 27: - ret = offsetof(VexGuestMIPS32State, guest_w27); + ret = offsetof(VexGuestMIPS64State, guest_r27); break; case 28: - ret = offsetof(VexGuestMIPS32State, guest_w28); + ret = offsetof(VexGuestMIPS64State, guest_r28); break; case 29: - ret = offsetof(VexGuestMIPS32State, guest_w29); + ret = offsetof(VexGuestMIPS64State, guest_r29); break; case 30: - ret = offsetof(VexGuestMIPS32State, guest_w30); + ret = offsetof(VexGuestMIPS64State, guest_r30); break; case 31: - ret = offsetof(VexGuestMIPS32State, guest_w31); + ret = offsetof(VexGuestMIPS64State, guest_r31); 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]; +#if defined(VGP_mips32_linux) +#define OFFB_PC offsetof(VexGuestMIPS32State, guest_PC) +#else +#define OFFB_PC offsetof(VexGuestMIPS64State, guest_PC) #endif - return w; -} -#define BITS2(_b1,_b0) \ - (((_b1) << 1) | (_b0)) +/* ---------------- Floating point registers ---------------- */ -#define BITS3(_b2,_b1,_b0) \ - (((_b2) << 2) | ((_b1) << 1) | (_b0)) +static UInt floatGuestRegOffset(UInt fregNo) +{ + vassert(fregNo < 32); + UInt ret; -#define BITS4(_b3,_b2,_b1,_b0) \ - (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0)) + if (!mode64) + switch (fregNo) { + case 0: + ret = offsetof(VexGuestMIPS32State, guest_f0); + break; -#define BITS5(_b4,_b3,_b2,_b1,_b0) \ - (((_b4) << 4) | BITS4((_b3),(_b2),(_b1),(_b0))) + case 1: + ret = offsetof(VexGuestMIPS32State, guest_f1); + break; -#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \ - ((BITS2((_b5),(_b4)) << 4) \ - | BITS4((_b3),(_b2),(_b1),(_b0))) + case 2: + ret = offsetof(VexGuestMIPS32State, guest_f2); + break; -#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \ - ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \ - | BITS4((_b3),(_b2),(_b1),(_b0))) + case 3: + ret = offsetof(VexGuestMIPS32State, guest_f3); + break; -#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)))); \ + case 4: + ret = offsetof(VexGuestMIPS32State, guest_f4); + break; -#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)))); \ + case 5: + ret = offsetof(VexGuestMIPS32State, guest_f5); + break; -#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))); + case 6: + ret = offsetof(VexGuestMIPS32State, guest_f6); + break; -#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)))); + case 7: + ret = offsetof(VexGuestMIPS32State, guest_f7); + break; -#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))); + case 8: + ret = offsetof(VexGuestMIPS32State, guest_f8); + break; -#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))) + case 9: + ret = offsetof(VexGuestMIPS32State, guest_f9); + break; -#define SXXV_PATTERN(op) \ - putIReg(rd, binop(op, \ - getIReg(rt), \ - unop(Iop_32to8, \ - binop(Iop_And32, \ - getIReg(rs), \ - mkU32(0x0000001F) \ - ) \ - ) \ - ) \ - ) + case 10: + ret = offsetof(VexGuestMIPS32State, guest_f10); + break; -#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 \ - )) + case 11: + ret = offsetof(VexGuestMIPS32State, guest_f11); + break; -#define SXX_PATTERN(op) \ - putIReg(rd, binop(op, getIReg(rt), mkU8(sa))); + case 12: + ret = offsetof(VexGuestMIPS32State, guest_f12); + break; -#define ALU_PATTERN(op) \ - putIReg(rd, binop(op, getIReg(rs), getIReg(rt))); + case 13: + ret = offsetof(VexGuestMIPS32State, guest_f13); + break; -#define ALUI_PATTERN(op) \ - putIReg(rt, binop(op, getIReg(rs), mkU32(imm))); + case 14: + ret = offsetof(VexGuestMIPS32State, guest_f14); + break; -#define ALUI_PATTERN64(op) \ - putIReg(rt, binop(op, getIReg(rs), mkU64(imm))); + case 15: + ret = offsetof(VexGuestMIPS32State, guest_f15); + break; -#define ALU_PATTERN64(op) \ - putIReg(rd, mkWidenFrom32(ty, binop(op, \ - mkNarrowTo32(ty, getIReg(rs)), \ - mkNarrowTo32(ty, getIReg(rt))), True)); + case 16: + ret = offsetof(VexGuestMIPS32State, guest_f16); + break; -#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))); + case 17: + ret = offsetof(VexGuestMIPS32State, guest_f17); + break; -#define ILLEGAL_INSTRUCTON \ - putPC(mkU32(guest_PC_curr_instr + 4)); \ - dres.jk_StopHere = Ijk_SigILL; \ - dres.whatNext = Dis_StopHere; + case 18: + ret = offsetof(VexGuestMIPS32State, guest_f18); + break; -#define LLADDR_INVALID \ - (mode64 ? mkU64(0xFFFFFFFFFFFFFFFFULL) : mkU32(0xFFFFFFFF)) + case 19: + ret = offsetof(VexGuestMIPS32State, guest_f19); + break; -/*------------------------------------------------------------*/ -/*--- Field helpers ---*/ -/*------------------------------------------------------------*/ + case 20: + ret = offsetof(VexGuestMIPS32State, guest_f20); + break; -static UInt get_opcode(UInt mipsins) -{ - return (0xFC000000 & mipsins) >> 26; -} + case 21: + ret = offsetof(VexGuestMIPS32State, guest_f21); + break; -static UInt get_rs(UInt mipsins) -{ - return (0x03E00000 & mipsins) >> 21; -} + case 22: + ret = offsetof(VexGuestMIPS32State, guest_f22); + break; -static UInt get_rt(UInt mipsins) -{ - return (0x001F0000 & mipsins) >> 16; -} + case 23: + ret = offsetof(VexGuestMIPS32State, guest_f23); + break; -static UInt get_imm(UInt mipsins) -{ - return (0x0000FFFF & mipsins); -} + case 24: + ret = offsetof(VexGuestMIPS32State, guest_f24); + break; -static UInt get_instr_index(UInt mipsins) -{ - return (0x03FFFFFF & mipsins); -} + case 25: + ret = offsetof(VexGuestMIPS32State, guest_f25); + break; -static UInt get_rd(UInt mipsins) -{ - return (0x0000F800 & mipsins) >> 11; -} + case 26: + ret = offsetof(VexGuestMIPS32State, guest_f26); + break; -static UInt get_sa(UInt mipsins) -{ - return (0x000007C0 & mipsins) >> 6; -} + case 27: + ret = offsetof(VexGuestMIPS32State, guest_f27); + break; -static UInt get_function(UInt mipsins) -{ - return (0x0000003F & mipsins); -} + case 28: + ret = offsetof(VexGuestMIPS32State, guest_f28); + break; -static UInt get_ft(UInt mipsins) -{ - return (0x001F0000 & mipsins) >> 16; -} + case 29: + ret = offsetof(VexGuestMIPS32State, guest_f29); + break; -static UInt get_fs(UInt mipsins) -{ - return (0x0000F800 & mipsins) >> 11; -} + case 30: + ret = offsetof(VexGuestMIPS32State, guest_f30); + break; -static UInt get_fd(UInt mipsins) -{ - return (0x000007C0 & mipsins) >> 6; -} + case 31: + ret = offsetof(VexGuestMIPS32State, guest_f31); + break; -static UInt get_mov_cc(UInt mipsins) -{ - return (0x001C0000 & mipsins) >> 18; -} + default: + vassert(0); + break; + } + else + switch (fregNo) { + case 0: + ret = offsetof(VexGuestMIPS64State, guest_f0); + break; -static UInt get_bc1_cc(UInt mipsins) -{ - return (0x001C0000 & mipsins) >> 18; -} + case 1: + ret = offsetof(VexGuestMIPS64State, guest_f1); + break; -static UInt get_fpc_cc(UInt mipsins) -{ - return (0x00000700 & mipsins) >> 8; -} + case 2: + ret = offsetof(VexGuestMIPS64State, guest_f2); + break; -static UInt get_tf(UInt mipsins) -{ - return (0x00010000 & mipsins) >> 16; -} + case 3: + ret = offsetof(VexGuestMIPS64State, guest_f3); + break; -static UInt get_nd(UInt mipsins) -{ - return (0x00020000 & mipsins) >> 17; -} + case 4: + ret = offsetof(VexGuestMIPS64State, guest_f4); + break; -static UInt get_fmt(UInt mipsins) -{ - return (0x03E00000 & mipsins) >> 21; -} + case 5: + ret = offsetof(VexGuestMIPS64State, guest_f5); + break; -static UInt get_FC(UInt mipsins) -{ - return (0x000000F0 & mipsins) >> 4; -} + case 6: + ret = offsetof(VexGuestMIPS64State, guest_f6); + break; -static UInt get_cond(UInt mipsins) -{ - return (0x0000000F & mipsins); -} + case 7: + ret = offsetof(VexGuestMIPS64State, guest_f7); + break; -/* for break & syscall */ -static UInt get_code(UInt mipsins) -{ - return (0xFFC0 & mipsins) >> 6; -} + case 8: + ret = offsetof(VexGuestMIPS64State, guest_f8); + break; -static UInt get_lsb(UInt mipsins) -{ - return (0x7C0 & mipsins) >> 6; -} + case 9: + ret = offsetof(VexGuestMIPS64State, guest_f9); + break; -static UInt get_msb(UInt mipsins) -{ - return (0x0000F800 & mipsins) >> 11; -} + case 10: + ret = offsetof(VexGuestMIPS64State, guest_f10); + break; -static UInt get_rot(UInt mipsins) -{ - return (0x00200000 & mipsins) >> 21; -} + case 11: + ret = offsetof(VexGuestMIPS64State, guest_f11); + break; -static UInt get_rotv(UInt mipsins) -{ - return (0x00000040 & mipsins) >> 6; -} + case 12: + ret = offsetof(VexGuestMIPS64State, guest_f12); + break; -static UInt get_sel(UInt mipsins) -{ - return (0x00000007 & mipsins); -} + case 13: + ret = offsetof(VexGuestMIPS64State, guest_f13); + break; -/* Get acc number for all MIPS32 DSP ASE(r2) instructions that use them, - except for MFHI and MFLO. */ -static UInt get_acNo(UInt mipsins) -{ - return (0x00001800 & mipsins) >> 11; -} + case 14: + ret = offsetof(VexGuestMIPS64State, guest_f14); + break; -/* Get accumulator number for MIPS32 DSP ASEr2 MFHI and MFLO instructions. */ -static UInt get_acNo_mfhilo(UInt mipsins) -{ - return (0x00600000 & mipsins) >> 21; -} + case 15: + ret = offsetof(VexGuestMIPS64State, guest_f15); + break; -/* Get mask field (helper function for wrdsp instruction). */ -static UInt get_wrdspMask(UInt mipsins) -{ - return (0x001ff800 & mipsins) >> 11; -} + case 16: + ret = offsetof(VexGuestMIPS64State, guest_f16); + break; -/* Get mask field (helper function for rddsp instruction). */ -static UInt get_rddspMask(UInt mipsins) -{ - return (0x03ff0000 & mipsins) >> 16; -} + case 17: + ret = offsetof(VexGuestMIPS64State, guest_f17); + break; -/* Get shift field (helper function for DSP ASE instructions). */ -static UInt get_shift(UInt mipsins) -{ - return (0x03f00000 & mipsins) >> 20; -} + case 18: + ret = offsetof(VexGuestMIPS64State, guest_f18); + break; -/* Get immediate field for DSP ASE instructions. */ -static UInt get_dspImm(UInt mipsins) -{ - return (0x03ff0000 & mipsins) >> 16; -} + case 19: + ret = offsetof(VexGuestMIPS64State, guest_f19); + break; -static Bool branch_or_jump(const UChar * addr) -{ - UInt fmt; - UInt cins = getUInt(addr); + case 20: + ret = offsetof(VexGuestMIPS64State, guest_f20); + break; - UInt opcode = get_opcode(cins); - UInt rt = get_rt(cins); - UInt function = get_function(cins); + case 21: + ret = offsetof(VexGuestMIPS64State, guest_f21); + break; - /* bgtz, blez, bne, beq, jal */ - if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04 - || opcode == 0x03 || opcode == 0x02) { - return True; - } + case 22: + ret = offsetof(VexGuestMIPS64State, guest_f22); + break; - /* bgez */ - if (opcode == 0x01 && rt == 0x01) { - return True; - } + case 23: + ret = offsetof(VexGuestMIPS64State, guest_f23); + break; - /* bgezal */ - if (opcode == 0x01 && rt == 0x11) { - return True; - } + case 24: + ret = offsetof(VexGuestMIPS64State, guest_f24); + break; - /* bltzal */ - if (opcode == 0x01 && rt == 0x10) { - return True; - } + case 25: + ret = offsetof(VexGuestMIPS64State, guest_f25); + break; - /* bltz */ - if (opcode == 0x01 && rt == 0x00) { - return True; - } + case 26: + ret = offsetof(VexGuestMIPS64State, guest_f26); + break; - /* jalr */ - if (opcode == 0x00 && function == 0x09) { - return True; - } + case 27: + ret = offsetof(VexGuestMIPS64State, guest_f27); + break; - /* jr */ - if (opcode == 0x00 && function == 0x08) { - return True; - } + case 28: + ret = offsetof(VexGuestMIPS64State, guest_f28); + break; - if (opcode == 0x11) { - /* bc1f & bc1t */ - fmt = get_fmt(cins); - if (fmt == 0x08) { - return True; - } + case 29: + ret = offsetof(VexGuestMIPS64State, guest_f29); + break; - /* 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; - } + case 30: + ret = offsetof(VexGuestMIPS64State, guest_f30); + break; - /* R6 branches */ - /* bc1eqz */ - if (fmt == 0x09) { - return True; - } + case 31: + ret = offsetof(VexGuestMIPS64State, guest_f31); + break; - /* bc1nez */ - if (fmt == 0x0D) { - return True; + default: + vassert(0); + break; } - } - - /* 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; + return ret; } -static Bool is_Branch_or_Jump_and_Link(const UChar * addr) +/* ---------------- MIPS32 DSP ASE(r2) accumulators ---------------- */ + +UInt accumulatorGuestRegOffset(UInt acNo) { - UInt cins = getUInt(addr); + vassert(!mode64); + vassert(acNo <= 3); + UInt ret; - UInt opcode = get_opcode(cins); - UInt rt = get_rt(cins); - UInt function = get_function(cins); + switch (acNo) { + case 0: + ret = offsetof(VexGuestMIPS32State, guest_ac0); + break; - /* jal */ - if (opcode == 0x02) { - return True; - } + case 1: + ret = offsetof(VexGuestMIPS32State, guest_ac1); + break; - /* bgezal or bal(r6) */ - if (opcode == 0x01 && rt == 0x11) { - return True; - } + case 2: + ret = offsetof(VexGuestMIPS32State, guest_ac2); + break; - /* bltzal */ - if (opcode == 0x01 && rt == 0x10) { - return True; - } + case 3: + ret = offsetof(VexGuestMIPS32State, guest_ac3); + break; - /* jalr */ - if (opcode == 0x00 && function == 0x09) { - return True; + default: + vassert(0); + break; } - return False; + return ret; } -static Bool branch_or_link_likely(const UChar * addr) -{ - UInt cins = getUInt(addr); - UInt opcode = get_opcode(cins); - UInt rt = get_rt(cins); +/* ---------------- MIPS32 MSA registers ---------------- */ - /* bgtzl, blezl, bnel, beql */ - if (opcode == 0x17 || opcode == 0x16 || opcode == 0x15 || opcode == 0x14) - return True; +static UInt msaGuestRegOffset(UInt msaRegNo) +{ + vassert(msaRegNo <= 31); + UInt ret; - /* bgezl */ - if (opcode == 0x01 && rt == 0x03) - return True; + if (mode64) { + switch (msaRegNo) { + case 0: + ret = offsetof(VexGuestMIPS64State, guest_w0); + break; - /* bgezall */ - if (opcode == 0x01 && rt == 0x13) - return True; + case 1: + ret = offsetof(VexGuestMIPS64State, guest_w1); + break; - /* bltzall */ - if (opcode == 0x01 && rt == 0x12) - return True; + case 2: + ret = offsetof(VexGuestMIPS64State, guest_w2); + break; - /* bltzl */ - if (opcode == 0x01 && rt == 0x02) - return True; + case 3: + ret = offsetof(VexGuestMIPS64State, guest_w3); + break; - return False; -} + case 4: + ret = offsetof(VexGuestMIPS64State, guest_w4); + break; -/*------------------------------------------------------------*/ -/*--- Helper bits and pieces for creating IR fragments. ---*/ -/*------------------------------------------------------------*/ + case 5: + ret = offsetof(VexGuestMIPS64State, guest_w5); + break; -static IRExpr *mkU8(UInt i) -{ - vassert(i < 256); - return IRExpr_Const(IRConst_U8((UChar) i)); -} + case 6: + ret = offsetof(VexGuestMIPS64State, guest_w6); + break; -/* Create an expression node for a 16-bit integer constant. */ -static IRExpr *mkU16(UInt i) -{ - return IRExpr_Const(IRConst_U16(i)); -} + case 7: + ret = offsetof(VexGuestMIPS64State, guest_w7); + break; -/* Create an expression node for a 32-bit integer constant. */ -static IRExpr *mkU32(UInt i) -{ - return IRExpr_Const(IRConst_U32(i)); -} + case 8: + ret = offsetof(VexGuestMIPS64State, guest_w8); + break; -/* Create an expression node for a 64-bit integer constant. */ -static IRExpr *mkU64(ULong i) -{ - return IRExpr_Const(IRConst_U64(i)); -} + case 9: + ret = offsetof(VexGuestMIPS64State, guest_w9); + break; -static IRExpr *mkexpr(IRTemp tmp) -{ - return IRExpr_RdTmp(tmp); -} + case 10: + ret = offsetof(VexGuestMIPS64State, guest_w10); + break; -static IRExpr *unop(IROp op, IRExpr * a) -{ - return IRExpr_Unop(op, a); -} + case 11: + ret = offsetof(VexGuestMIPS64State, guest_w11); + break; -static IRExpr *binop(IROp op, IRExpr * a1, IRExpr * a2) -{ - return IRExpr_Binop(op, a1, a2); -} + case 12: + ret = offsetof(VexGuestMIPS64State, guest_w12); + break; -static IRExpr *triop(IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3) -{ - return IRExpr_Triop(op, a1, a2, a3); -} + case 13: + ret = offsetof(VexGuestMIPS64State, guest_w13); + break; -static IRExpr *qop ( IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3, - IRExpr * a4 ) -{ - return IRExpr_Qop(op, a1, a2, a3, a4); -} + case 14: + ret = offsetof(VexGuestMIPS64State, guest_w14); + break; -static IRExpr *load(IRType ty, IRExpr * addr) -{ - IRExpr *load1 = NULL; -#if defined (_MIPSEL) - load1 = IRExpr_Load(Iend_LE, ty, addr); -#elif defined (_MIPSEB) - load1 = IRExpr_Load(Iend_BE, ty, addr); -#endif - return load1; -} + case 15: + ret = offsetof(VexGuestMIPS64State, guest_w15); + break; -/* Add a statement to the list held by "irsb". */ -static void stmt(IRStmt * st) -{ - addStmtToIRSB(irsb, st); -} + case 16: + ret = offsetof(VexGuestMIPS64State, guest_w16); + break; -static void assign(IRTemp dst, IRExpr * e) -{ - stmt(IRStmt_WrTmp(dst, e)); -} + case 17: + ret = offsetof(VexGuestMIPS64State, guest_w17); + break; -static void store(IRExpr * addr, IRExpr * data) -{ -#if defined (_MIPSEL) - stmt(IRStmt_Store(Iend_LE, addr, data)); -#elif defined (_MIPSEB) - stmt(IRStmt_Store(Iend_BE, addr, data)); -#endif -} + case 18: + ret = offsetof(VexGuestMIPS64State, guest_w18); + break; -/* Generate a new temporary of the given type. */ -static IRTemp newTemp(IRType ty) -{ - vassert(isPlausibleIRType(ty)); - return newIRTemp(irsb->tyenv, ty); -} + case 19: + ret = offsetof(VexGuestMIPS64State, guest_w19); + break; -/* 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))); -} + case 20: + ret = offsetof(VexGuestMIPS64State, guest_w20); + break; -static IRExpr *genRORV32(IRExpr * src, IRExpr * rs) -{ - IRTemp t0 = newTemp(Ity_I8); - IRTemp t1 = newTemp(Ity_I8); + case 21: + ret = offsetof(VexGuestMIPS64State, guest_w21); + break; - 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))); -} + case 22: + ret = offsetof(VexGuestMIPS64State, guest_w22); + break; + case 23: + ret = offsetof(VexGuestMIPS64State, guest_w23); + break; -static UShort extend_s_9to16(UInt x) -{ - return (UShort) ((((Int) x) << 23) >> 23); -} + case 24: + ret = offsetof(VexGuestMIPS64State, guest_w24); + break; -static UShort extend_s_10to16(UInt x) -{ - return (UShort) ((((Int) x) << 22) >> 22); -} + case 25: + ret = offsetof(VexGuestMIPS64State, guest_w25); + break; -static UInt extend_s_10to32(UInt x) -{ - return (UInt)((((Int) x) << 22) >> 22); -} + case 26: + ret = offsetof(VexGuestMIPS64State, guest_w26); + break; -static ULong extend_s_10to64(UInt x) -{ - return (ULong)((((Long) x) << 54) >> 54); -} + case 27: + ret = offsetof(VexGuestMIPS64State, guest_w27); + break; -static UInt extend_s_16to32(UInt x) -{ - return (UInt) ((((Int) x) << 16) >> 16); -} + case 28: + ret = offsetof(VexGuestMIPS64State, guest_w28); + break; -static UInt extend_s_18to32(UInt x) -{ - return (UInt) ((((Int) x) << 14) >> 14); -} + case 29: + ret = offsetof(VexGuestMIPS64State, guest_w29); + break; -static UInt extend_s_19to32(UInt x) -{ - return (UInt) ((((Int) x) << 13) >> 13); -} + case 30: + ret = offsetof(VexGuestMIPS64State, guest_w30); + break; -static UInt extend_s_23to32(UInt x) -{ - return (UInt) ((((Int) x) << 9) >> 9); -} + case 31: + ret = offsetof(VexGuestMIPS64State, guest_w31); + break; -static UInt extend_s_26to32(UInt x) -{ - return (UInt) ((((Int) x) << 6) >> 6); -} + default: + vassert(0); + break; + } + } else { + switch (msaRegNo) { + case 0: + ret = offsetof(VexGuestMIPS32State, guest_w0); + break; -static ULong extend_s_16to64 ( UInt x ) -{ - return (ULong) ((((Long) x) << 48) >> 48); -} + case 1: + ret = offsetof(VexGuestMIPS32State, guest_w1); + break; -static ULong extend_s_18to64 ( UInt x ) -{ - return (ULong) ((((Long) x) << 46) >> 46); -} + case 2: + ret = offsetof(VexGuestMIPS32State, guest_w2); + break; -static ULong extend_s_19to64(UInt x) -{ - return (ULong) ((((Long) x) << 45) >> 45); -} + case 3: + ret = offsetof(VexGuestMIPS32State, guest_w3); + break; -static ULong extend_s_23to64(UInt x) -{ - return (ULong) ((((Long) x) << 41) >> 41); -} + case 4: + ret = offsetof(VexGuestMIPS32State, guest_w4); + break; -static ULong extend_s_26to64(UInt x) -{ - return (ULong) ((((Long) x) << 38) >> 38); -} + case 5: + ret = offsetof(VexGuestMIPS32State, guest_w5); + break; -static ULong extend_s_32to64 ( UInt x ) -{ - return (ULong) ((((Long) x) << 32) >> 32); -} + case 6: + ret = offsetof(VexGuestMIPS32State, guest_w6); + break; -static void jmp_lit32 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr32 d32 ) -{ - vassert(dres->whatNext == Dis_Continue); - vassert(dres->len == 0); - vassert(dres->continueAt == 0); - vassert(dres->jk_StopHere == Ijk_INVALID); - dres->whatNext = Dis_StopHere; - dres->jk_StopHere = kind; - stmt( IRStmt_Put( OFFB_PC, mkU32(d32) ) ); -} + case 7: + ret = offsetof(VexGuestMIPS32State, guest_w7); + break; -static void jmp_lit64 ( /*MOD*/ DisResult* dres, IRJumpKind kind, Addr64 d64 ) -{ - vassert(dres->whatNext == Dis_Continue); - vassert(dres->len == 0); - vassert(dres->continueAt == 0); - vassert(dres->jk_StopHere == Ijk_INVALID); - dres->whatNext = Dis_StopHere; - dres->jk_StopHere = kind; - stmt(IRStmt_Put(OFFB_PC, mkU64(d64))); -} + case 8: + ret = offsetof(VexGuestMIPS32State, guest_w8); + break; -/* 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. */ -static IRExpr *getAcc(UInt acNo) -{ - vassert(!mode64); - vassert(acNo <= 3); - return IRExpr_Get(accumulatorGuestRegOffset(acNo), Ity_I64); -} + case 9: + ret = offsetof(VexGuestMIPS32State, guest_w9); + break; -/* Get value from DSPControl register (helper function for MIPS32 DSP ASE - instructions). */ -static IRExpr *getDSPControl(void) -{ - vassert(!mode64); - return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_DSPControl), Ity_I32); -} + case 10: + ret = offsetof(VexGuestMIPS32State, guest_w10); + break; -/* Put value to DSPControl register. Expression e is written to DSPControl as - is. If only certain bits of DSPControl need to be changed, it should be done - before calling putDSPControl(). It could be done by reading DSPControl and - ORing it with appropriate mask. */ -static void putDSPControl(IRExpr * e) -{ - vassert(!mode64); - stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_DSPControl), e)); -} + case 11: + ret = offsetof(VexGuestMIPS32State, guest_w11); + break; -/* Fetch a byte from the guest insn stream. */ -static UChar getIByte(Int delta) -{ - return guest_code[delta]; -} + case 12: + ret = offsetof(VexGuestMIPS32State, guest_w12); + break; -static 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); - } -} + case 13: + ret = offsetof(VexGuestMIPS32State, guest_w13); + break; + case 14: + ret = offsetof(VexGuestMIPS32State, guest_w14); + break; -static IRExpr *getWReg(UInt wregNo) { - vassert(wregNo <= 31); - return IRExpr_Get(msaGuestRegOffset(wregNo), Ity_V128); -} + case 15: + ret = offsetof(VexGuestMIPS32State, guest_w15); + break; -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); -} + case 16: + ret = offsetof(VexGuestMIPS32State, guest_w16); + break; -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); -} + case 17: + ret = offsetof(VexGuestMIPS32State, guest_w17); + break; -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); -} + case 18: + ret = offsetof(VexGuestMIPS32State, guest_w18); + break; -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); -} + case 19: + ret = offsetof(VexGuestMIPS32State, guest_w19); + break; -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); -} + case 20: + ret = offsetof(VexGuestMIPS32State, guest_w20); + break; -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); -} + case 21: + ret = offsetof(VexGuestMIPS32State, guest_w21); + break; -/* 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))); -} + case 22: + ret = offsetof(VexGuestMIPS32State, guest_w22); + break; -static void putFCSR(IRExpr * e) -{ - if (mode64) - stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_FCSR), e)); - else - stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_FCSR), e)); -} + case 23: + ret = offsetof(VexGuestMIPS32State, guest_w23); + break; -static void putLLaddr(IRExpr * e) -{ - if (mode64) - stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLaddr), e)); - else - stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLaddr), e)); -} + case 24: + ret = offsetof(VexGuestMIPS32State, guest_w24); + break; -static void putLLdata(IRExpr * e) -{ - if (mode64) - stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLdata), e)); - else - stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata), e)); -} + case 25: + ret = offsetof(VexGuestMIPS32State, guest_w25); + break; -static void putMSACSR(IRExpr * e) { - if (mode64) - stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_MSACSR), e)); - else - stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_MSACSR), e)); -} + case 26: + ret = offsetof(VexGuestMIPS32State, guest_w26); + break; -/* 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))); + case 27: + ret = offsetof(VexGuestMIPS32State, guest_w27); + break; - 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)); + case 28: + ret = offsetof(VexGuestMIPS32State, guest_w28); + break; - 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); + case 29: + ret = offsetof(VexGuestMIPS32State, guest_w29); + break; - 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)); + case 30: + ret = offsetof(VexGuestMIPS32State, guest_w30); + break; - 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); + case 31: + ret = offsetof(VexGuestMIPS32State, guest_w31); + break; - 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); + default: + vassert(0); + break; } } - stmt(IRStmt_Dirty(d)); + return ret; +} - putFCSR(mkexpr(fcsr)); + +/* 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; } -/* 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))); +#define BITS2(_b1,_b0) \ + (((_b1) << 1) | (_b0)) - 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 */ +#define BITS3(_b2,_b1,_b0) \ + (((_b2) << 2) | ((_b1) << 1) | (_b0)) - if (mode64) - d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_MSACSR); - else - d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_MSACSR); +#define BITS4(_b3,_b2,_b1,_b0) \ + (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0)) - 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 */ +#define BITS5(_b4,_b3,_b2,_b1,_b0) \ + (((_b4) << 4) | BITS4((_b3),(_b2),(_b1),(_b0))) - if (mode64) - d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_MSACSR); - else - d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_MSACSR); +#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \ + ((BITS2((_b5),(_b4)) << 4) \ + | BITS4((_b3),(_b2),(_b1),(_b0))) - 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); - } +#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \ + ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \ + | BITS4((_b3),(_b2),(_b1),(_b0))) - stmt(IRStmt_Dirty(d)); - putMSACSR(mkexpr(msacsr)); -} +#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)))); \ -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); -} +#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)))); \ -static 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)); -} +#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))); -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)))); -} +#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)))); -static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src) -{ - vassert(ty == Ity_I32 || ty == Ity_I64); - return ty == Ity_I64 ? unop(Iop_64to32, src) : src; -} +#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))); -static 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)))); - } -} +#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))) -static 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)))); - } -} +#define SXXV_PATTERN(op) \ + putIReg(rd, binop(op, \ + getIReg(rt), \ + unop(Iop_32to8, \ + binop(Iop_And32, \ + getIReg(rs), \ + mkU32(0x0000001F) \ + ) \ + ) \ + ) \ + ) -/* Put value to accumulator(helper function for MIPS32 DSP ASE instructions). */ -static void putAcc(UInt acNo, IRExpr * e) -{ - vassert(!mode64); - vassert(acNo <= 3); - vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64); - stmt(IRStmt_Put(accumulatorGuestRegOffset(acNo), e)); -/* If acNo = 0, split value to HI and LO regs in order to maintain compatibility - between MIPS32 and MIPS DSP ASE insn sets. */ - if (0 == acNo) { - putLO(unop(Iop_64to32, e)); - putHI(unop(Iop_64HIto32, e)); - } -} +#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 \ + )) -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); -} +#define SXX_PATTERN(op) \ + putIReg(rd, binop(op, getIReg(rt), mkU8(sa))); -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); -} +#define ALU_PATTERN(op) \ + putIReg(rd, binop(op, getIReg(rs), getIReg(rt))); -static void putPC(IRExpr * e) -{ - stmt(IRStmt_Put(OFFB_PC, e)); -} +#define ALUI_PATTERN(op) \ + putIReg(rt, binop(op, getIReg(rs), mkU32(imm))); -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); -} +#define ALUI_PATTERN64(op) \ + putIReg(rt, binop(op, getIReg(rs), mkU64(imm))); -/* 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; -} +#define ALU_PATTERN64(op) \ + putIReg(rd, mkWidenFrom32(ty, binop(op, \ + mkNarrowTo32(ty, getIReg(rs)), \ + mkNarrowTo32(ty, getIReg(rt))), True)); -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; -} +#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))); -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); +#define ILLEGAL_INSTRUCTON \ + putPC(mkU32(guest_PC_curr_instr + 4)); \ + dres->jk_StopHere = Ijk_SigILL; \ + dres->whatNext = Dis_StopHere; - stmt(IRStmt_Exit(condition, Ijk_Boring, - mode64 ? IRConst_U64(guest_PC_curr_instr + 4) : - IRConst_U32(guest_PC_curr_instr + 4), - OFFB_PC)); -} +#define LLADDR_INVALID \ + (mode64 ? mkU64(0xFFFFFFFFFFFFFFFFULL) : mkU32(0xFFFFFFFF)) -static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm) +/*------------------------------------------------------------*/ +/*--- Field helpers ---*/ +/*------------------------------------------------------------*/ + +static Bool branch_or_jump(const UChar * addr) { - ULong branch_offset; - IRTemp t0; + UInt fmt; + UInt cins = getUInt(addr); - /* 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); + UInt opcode = get_opcode(cins); + UInt rt = get_rt(cins); + UInt function = get_function(cins); - t0 = newTemp(Ity_I1); - assign(t0, guard); + /* bgtz, blez, bne, beq, jal */ + if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04 + || opcode == 0x03 || opcode == 0x02) { + return True; + } - 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)); + /* bgez */ + if (opcode == 0x01 && rt == 0x01) { + return True; + } - irsb->jumpkind = Ijk_Boring; + /* bgezal */ + if (opcode == 0x01 && rt == 0x11) { + return True; + } - if (mode64) - return mkU64(guest_PC_curr_instr + 4 + branch_offset); - else - return mkU32(guest_PC_curr_instr + 4 + branch_offset); -} + /* bltzal */ + if (opcode == 0x01 && rt == 0x10) { + return True; + } -static void dis_branch(Bool link, IRExpr * guard, UInt imm, IRStmt ** set) -{ - ULong branch_offset; - IRTemp t0; + /* bltz */ + if (opcode == 0x01 && rt == 0x00) { + return True; + } - 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)); + /* jalr */ + if (opcode == 0x00 && function == 0x09) { + return True; } - /* 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. */ + /* jr */ + if (opcode == 0x00 && function == 0x08) { + return True; + } - if (mode64) - branch_offset = extend_s_18to64(imm << 2); - else - branch_offset = extend_s_18to32(imm << 2); + if (opcode == 0x11) { + /* bc1f & bc1t */ + fmt = get_fmt(cins); - 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); -} + if (fmt == 0x08) { + return True; + } -static void dis_branch_compact(Bool link, IRExpr * guard, UInt imm, - DisResult *dres) -{ - ULong branch_offset; - IRTemp t0; + /* MSA branches */ + /* bnz.df, bz.df */ + if (fmt >= 0x18) { + return True; + } - 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; - } + /* bnz.v */ + if (fmt == 0x0f) { + return True; + } - dres->whatNext = Dis_StopHere; + /* bz.v */ + if (fmt == 0x0b) { + return True; + } - /* 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. */ + /* R6 branches */ + /* bc1eqz */ + if (fmt == 0x09) { + return True; + } - if (mode64) - branch_offset = extend_s_18to64(imm << 2); - else - branch_offset = extend_s_18to32(imm << 2); + /* bc1nez */ + if (fmt == 0x0D) { + return True; + } + } - t0 = newTemp(Ity_I1); - assign(t0, guard); + /* bposge32 */ + if (opcode == 0x01 && rt == 0x1c) { + return True; + } - 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)); + /* Cavium Specific instructions. */ + if (opcode == 0x32 || opcode == 0x3A || opcode == 0x36 || opcode == 0x3E) { + /* BBIT0, BBIT1, BBIT032, BBIT132 */ + return True; } -} -static IRExpr *getFReg(UInt fregNo) -{ - vassert(fregNo < 32); - IRType ty = fp_mode64 ? Ity_F64 : Ity_F32; - return IRExpr_Get(floatGuestRegOffset(fregNo), ty); + return False; } -static IRExpr *getDReg(UInt dregNo) +static Bool is_Branch_or_Jump_and_Link(const UChar * addr) { - 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); + UInt cins = getUInt(addr); - assign(t0, getFReg(dregNo & (~1))); - assign(t1, getFReg(dregNo | 1)); + UInt opcode = get_opcode(cins); + UInt rt = get_rt(cins); + UInt function = get_function(cins); - 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))); + /* jal */ + if (opcode == 0x02) { + return True; + } - return mkexpr(t2); + /* 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 void putFReg(UInt dregNo, IRExpr * e) +static Bool branch_or_link_likely(const UChar * addr) { - vassert(dregNo < 32); - IRType ty = fp_mode64 ? Ity_F64 : Ity_F32; - vassert(typeOfIRExpr(irsb->tyenv, e) == ty); + UInt cins = getUInt(addr); + UInt opcode = get_opcode(cins); + UInt rt = get_rt(cins); - 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)); - } + /* bgtzl, blezl, bnel, beql */ + if (opcode == 0x17 || opcode == 0x16 || opcode == 0x15 || opcode == 0x14) + return True; - if (has_msa && fp_mode64) { - stmt(IRStmt_Put(msaGuestRegOffset(dregNo), - binop(Iop_64HLtoV128, - unop(Iop_ReinterpF64asI64, e), - unop(Iop_ReinterpF64asI64, e)))); - } + /* 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; } -static void putDReg(UInt dregNo, IRExpr * e) +/*------------------------------------------------------------*/ +/*--- Helper bits and pieces for creating IR fragments. ---*/ +/*------------------------------------------------------------*/ + +/* Generate an expression for SRC rotated right by ROT. */ +static IRExpr *genROR32(IRExpr * src, Int rot) { - 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))); - } + 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 void setFPUCondCode(IRExpr * e, UInt cc) +static IRExpr *genRORV32(IRExpr * src, IRExpr * rs) { - if (cc == 0) { - putFCSR(binop(Iop_And32, getFCSR(), mkU32(0xFF7FFFFF))); - putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(23)))); + 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->continueAt == 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->continueAt == 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 { - 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)))); + IRType ty = mode64 ? Ity_I64 : Ity_I32; + vassert(iregNo < 32); + return IRExpr_Get(integerGuestRegOffset(iregNo), ty); } } -static IRExpr* get_IR_roundingmode ( void ) +static IRExpr *getWReg(UInt wregNo) { -/* - 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. */ + vassert(wregNo <= 31); + return IRExpr_Get(msaGuestRegOffset(wregNo), Ity_V128); +} +static IRExpr *getHI(void) +{ if (mode64) - assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS64State, - guest_FCSR), Ity_I32), mkU32(3))); + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_HI), Ity_I64); 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 IRExpr_Get(offsetof(VexGuestMIPS32State, guest_HI), Ity_I32); +} - return binop(Iop_Xor32, mkexpr(rm_MIPS), binop(Iop_And32, - binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2))); +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* 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. */ +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) - assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS64State, - guest_MSACSR), Ity_I32), mkU32(3))); + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LLaddr), Ity_I64); else - assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS32State, - guest_MSACSR), Ity_I32), mkU32(3))); + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLaddr), Ity_I32); +} - /* 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 *getLLdata(void) +{ + if (mode64) + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_LLdata), Ity_I64); + else + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LLdata), Ity_I32); } -/* sz, ULong -> IRExpr */ -static IRExpr *mkSzImm ( IRType ty, ULong imm64 ) +static IRExpr *getMSACSR(void) { - vassert(ty == Ity_I32 || ty == Ity_I64); - return ty == Ity_I64 ? mkU64(imm64) : mkU32((UInt) imm64); + if (mode64) + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_MSACSR), Ity_I32); + else + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_MSACSR), Ity_I32); } -static IRConst *mkSzConst ( IRType ty, ULong imm64 ) +/* Get byte from register reg, byte pos from 0 to 3 (or 7 for MIPS64) . */ +static IRExpr *getByteFromReg(UInt reg, UInt byte_pos) { - vassert(ty == Ity_I32 || ty == Ity_I64); - return (ty == Ity_I64 ? IRConst_U64(imm64) : IRConst_U32((UInt) imm64)); + 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))); } -/* Make sure we get valid 32 and 64bit addresses */ -static Addr64 mkSzAddr ( IRType ty, Addr64 addr ) +static void putFCSR(IRExpr * e) { - vassert(ty == Ity_I32 || ty == Ity_I64); - return (ty == Ity_I64 ? (Addr64) addr : - (Addr64) extend_s_32to64(toUInt(addr))); + if (mode64) + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_FCSR), e)); + else + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_FCSR), e)); } -/* Shift and Rotate instructions for MIPS64 */ -static Bool dis_instr_shrt ( UInt theInstr ) +static void putLLaddr(IRExpr * e) { - 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); + if (mode64) + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLaddr), e)); + else + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLaddr), e)); +} - assign(tmpRs, getIReg(regRs)); - assign(tmpRt, getIReg(regRt)); +static void putLLdata(IRExpr * e) +{ + if (mode64) + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_LLdata), e)); + else + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LLdata), e)); +} - 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; +static void putMSACSR(IRExpr * e) +{ + if (mode64) + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_MSACSR), e)); + else + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_MSACSR), e)); +} - 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; +/* 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); - 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) */ + /* 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))); - assign(tmp64, binop(Iop_And64, mkexpr(tmpRs), mkSzImm(ty, 63))); - assign(tmp, binop(Iop_Sub64, mkU64(63), mkexpr(tmp64))); + if (opN == 1) { /* Unary operation. */ + /* Declare we're reading guest state. */ + if (sz32 || fp_mode64) + d->nFxState = 2; + else + d->nFxState = 3; - assign(tmpLs8, mkNarrowTo8(ty, mkexpr(tmp))); - assign(tmpRs8, mkNarrowTo8(ty, mkexpr(tmp64))); + vex_bzero(&d->fxState, sizeof(d->fxState)); - 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))); + d->fxState[0].fx = Ifx_Read; /* read */ - putIReg(regRd, mkexpr(tmpOr)); - } else - return False; - break; + if (mode64) + d->fxState[0].offset = offsetof(VexGuestMIPS64State, guest_FCSR); + else + d->fxState[0].offset = offsetof(VexGuestMIPS32State, guest_FCSR); - 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; + 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); - 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; + 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; - 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); + vex_bzero(&d->fxState, sizeof(d->fxState)); - 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; + 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); } + } - 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; + stmt(IRStmt_Dirty(d)); - 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; + putFCSR(mkexpr(fcsr)); +} - 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; +/* 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 */ - default: - return False; + 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); } - return True; + + stmt(IRStmt_Dirty(d)); + putMSACSR(mkexpr(msacsr)); } -static IROp mkSzOp ( IRType ty, IROp op8 ) +static IRExpr *getULR(void) { - 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; + if (mode64) + return IRExpr_Get(offsetof(VexGuestMIPS64State, guest_ULR), Ity_I64); + else + return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR), Ity_I32); } -/*********************************************************/ -/*--- 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; +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 Bool dis_instr_CCondFmt ( UInt cins ) +static void putWReg(UInt wregNo, IRExpr * e) { - IRTemp t0, t1, t2, t3, tmp5, tmp6; - IRTemp ccIR = newTemp(Ity_I32); - IRTemp ccMIPS = newTemp(Ity_I32); + 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); + 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, + Bool(*resteerOkFn) (void *, Addr), + void *callback_opaque, 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))); - tmp5 = newTemp(Ity_F64); - tmp6 = newTemp(Ity_F64); + if (putIntoRd) + putIReg(rd, mkexpr(old_mem)); +} - assign(tmp5, unop(Iop_F32toF64, getLoFromF64(Ity_F64, - getFReg(fs)))); - assign(tmp6, unop(Iop_F32toF64, getLoFromF64(Ity_F64, - getFReg(ft)))); +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)); - 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 - */ + 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; + } - /* 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)); + 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; + } - /* 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); + /* 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; - case 0x5: - setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)), - fpc_cc); + } + + /* 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; - case 0x6: - setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)), - fpc_cc); + } + + /* 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; - case 0x7: - setFPUCondCode(mkexpr(t2), fpc_cc); + } + + /* 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; - case 0x8: - setFPUCondCode(mkU32(0), fpc_cc); + } + + /* 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; - case 0x9: - setFPUCondCode(mkexpr(t0), fpc_cc); + } + + /* 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; - case 0xA: - setFPUCondCode(mkexpr(t1), fpc_cc); + } + + /* 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; - case 0xB: - setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)), - fpc_cc); + } + + /* 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; - case 0xC: - setFPUCondCode(mkexpr(t3), fpc_cc); + } + + /* 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; - case 0xD: - setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)), - fpc_cc); + } + + /* 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; - case 0xE: - setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)), - fpc_cc); + } + + /* 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; - case 0xF: - setFPUCondCode(mkexpr(t2), fpc_cc); + } + + /* 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; } - } else { - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); + 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; + } - 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 - */ + case 0x04: // LHX rd, index(base) + DIP("lhx r%u, r%u(r%u)", regRd, regRt, regRs); + LOADX_STORE_PATTERN; - /* 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))); + if (mode64) + putIReg(regRd, unop(Iop_16Sto64, load(Ity_I16, + mkexpr(t1)))); + else + putIReg(regRd, unop(Iop_16Sto32, load(Ity_I16, + mkexpr(t1)))); - 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); + + 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 0xC: - setFPUCondCode(mkexpr(t3), fpc_cc); + } + + 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 0xD: - setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)), - fpc_cc); + } + + 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 0xE: - setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)), - fpc_cc); + } + + 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 0xF: - setFPUCondCode(mkexpr(t2), fpc_cc); + } + + 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; - - 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; } - } + } /* opc1 = 0x1F & opc2 = 0xA (LX) ends here*/ + break; + } /* opc1 = 0x1F ends here*/ - default: - return False; - } - } else { - return False; - } + default: + return False; + } /* main opc1 switch ends here */ return True; } -/*********************************************************/ -/*--- Branch Instructions for mips64 ---*/ -/*********************************************************/ -static Bool dis_instr_branch ( UInt theInstr, DisResult * dres, - Bool(*resteerOkFn) (void *, Addr), - void *callback_opaque, IRStmt ** set ) +static Int msa_I8_logical(UInt cins, UChar wd, UChar ws) { - 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 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; + } - IRTemp tmp = newTemp(ty); - IRTemp tmpRs = newTemp(ty); - IRTemp tmpRt = newTemp(ty); - IRTemp tmpLt = newTemp(ty); - IRTemp tmpReg0 = newTemp(ty); + 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; + } - UChar regLnk = 31; /* reg 31 is link reg in MIPS */ - Addr64 addrTgt = 0; - Addr64 cia = guest_PC_curr_instr; + 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; + } - IRExpr *eConst0 = mkSzImm(ty, (UInt) 0); - IRExpr *eNia = mkSzImm(ty, cia + 8); - IRExpr *eCond = NULL; + default: + return -1; + } - assign(tmpRs, getIReg(regRs)); - assign(tmpRt, getIReg(regRt)); - assign(tmpReg0, getIReg(0)); + return 0; +} - eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpReg0), mkexpr(tmpReg0)); +static Int msa_I8_branch(UInt cins, UChar wd, UChar ws) +{ + IRTemp t1, t2, t3, t4; + UShort operation; + UChar i8; - switch (opc1) { - case 0x01: - switch (regRt) { - case 0x00: { /* BLTZ rs, offset */ - addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2)); - IRTemp tmpLtRes = newTemp(Ity_I1); + operation = (cins >> 24) & 3; + i8 = (cins & 0x00FF0000) >> 16; - assign(tmp, eConst0); - assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), mkexpr(tmp))); - assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) : - unop(Iop_1Uto32, mkexpr(tmpLtRes))); + 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; + } - eCond = binop(mkSzOp(ty, Iop_CmpNE8), mkexpr(tmpLt), - mkexpr(tmpReg0)); + 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; + } - jmpKind = Ijk_Boring; - 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; + } - case 0x01: { /* BGEZ rs, offset */ - IRTemp tmpLtRes = newTemp(Ity_I1); - addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2)); + default: + return -1; + } - 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)); + return 0; +} - jmpKind = Ijk_Boring; - break; - } +static Int msa_I8_shift(UInt cins, UChar wd, UChar ws) +{ + IRTemp t1, t2; + UShort operation; + UChar i8; - case 0x11: { /* BGEZAL rs, offset */ - addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2)); - putIReg(regLnk, eNia); - IRTemp tmpLtRes = newTemp(Ity_I1); + operation = (cins >> 24) & 3; + i8 = (cins & 0x00FF0000) >> 16; - assign(tmpLtRes, binop(opSlt, mkexpr(tmpRs), eConst0)); - assign(tmpLt, mode64 ? unop(Iop_1Uto64, mkexpr(tmpLtRes)) : - unop(Iop_1Uto32, mkexpr(tmpLtRes))); + 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]; - eCond = binop(mkSzOp(ty, Iop_CmpEQ8), mkexpr(tmpLt), - mkexpr(tmpReg0)); + 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)))); + } - jmpKind = Ijk_Call; - break; - } + 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 0x10: { /* BLTZAL rs, offset */ - IRTemp tmpLtRes = newTemp(Ity_I1); - IRTemp tmpRes = newTemp(ty); + 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]; - addrTgt = mkSzAddr(ty, cia + 4 + (sOffset << 2)); - putIReg(regLnk, eNia); + 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)))); + } - 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)); + 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; + } - jmpKind = Ijk_Call; - 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 False; } - *set = IRStmt_Exit(eCond, jmpKind, mkSzConst(ty, addrTgt), OFFB_PC); - return True; -} -/*********************************************************/ -/*--- Cavium Specific Instructions ---*/ -/*********************************************************/ + default: + return -1; + } -/* 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) ); + return 0; } -/* Based on s390_irgen_load_and_add32. */ -static void mips_load_store32(IRTemp op1addr, IRTemp new_val, - IRTemp expd, UChar rd, Bool putIntoRd) +static Int msa_I5_06(UInt cins, UChar wd, UChar ws) /* I5 (0x06) */ { - IRCAS *cas; - IRTemp old_mem = newTemp(Ity_I32); - IRType ty = mode64 ? Ity_I64 : Ity_I32; + IRTemp t1, t2, t3; + UShort operation; + UChar df, wt; - 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)); + operation = (cins & 0x03800000) >> 23; + df = (cins & 0x00600000) >> 21; + wt = (cins & 0x001F0000) >> 16; - /* 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)); -} + switch (operation) { + case 0x00: { /* ADDVI */ + ULong tmp = wt; -/* 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)); + 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; + } - /* 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)); -} + 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; + } -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)); + 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; + } - 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))); + 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 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); + 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; } - /* 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); + 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; } - /* 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; - } + 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; } + } - /* 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 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 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)); + + 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; } - - /* 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 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 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)); + 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 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)); + 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 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))); + 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; + } + } - 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 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 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)))); + 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 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)))); + 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 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))))); + 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; + } + } - 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; + } + + 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; + } - default: - return False; + 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; - } /* 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; - } + } + + 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; } - } /* opc1 = 0x1F & opc2 = 0xA (LX) ends here*/ + + 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; - } /* opc1 = 0x1F ends here*/ - default: - return False; - } /* main opc1 switch ends here */ - return True; -} + } -/*------------------------------------------------------------*/ -/*--- Disassemble a single DSP ASE instruction ---*/ -/*------------------------------------------------------------*/ + case 0x02: { /* CLTI_S.df */ + ULong tmp = i5; -static UInt disDSPInstr_MIPS_WRK ( UInt cins ) -{ - IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, - t15, t16, t17; - UInt opcode, rs, rt, rd, sa, function, ac, ac_mfhilo, rddsp_mask, - wrdsp_mask, dsp_imm, shift; + 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; + } - opcode = get_opcode(cins); - rs = get_rs(cins); - rt = get_rt(cins); - rd = get_rd(cins); - sa = get_sa(cins); - function = get_function(cins); - ac = get_acNo(cins); - ac_mfhilo = get_acNo_mfhilo(cins); - rddsp_mask = get_rddspMask(cins); - wrdsp_mask = get_wrdspMask(cins); - dsp_imm = get_dspImm(cins); - shift = get_shift(cins); - - switch (opcode) { - case 0x00: { /* Special */ - switch (function) { - case 0x10: { /* MFHI */ - DIP("mfhi ac%u r%u", ac_mfhilo, rd); - putIReg(rd, unop(Iop_64HIto32, getAcc(ac_mfhilo))); + 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 0x11: { /* MTHI */ - DIP("mthi ac%u r%u", ac, rs); - t1 = newTemp(Ity_I32); - assign(t1, unop(Iop_64to32, getAcc(ac))); - putAcc(ac, binop(Iop_32HLto64, getIReg(rs), mkexpr(t1))); + 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; } - case 0x12: { /* MFLO */ - DIP("mflo ac%u r%u", ac_mfhilo, rd); - putIReg(rd, unop(Iop_64to32, getAcc(ac_mfhilo))); + 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 0x13: { /* MTLO */ - DIP("mtlo ac%u r%u", ac, rs); - t1 = newTemp(Ity_I32); - assign(t1, unop(Iop_64HIto32, getAcc(ac))); - putAcc(ac, binop(Iop_32HLto64, mkexpr(t1), getIReg(rs))); + 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 0x18: { /* MULT */ - DIP("mult ac%u r%u, r%u", ac, rs, rt); - t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_MullS32, mkNarrowTo32(Ity_I32, getIReg(rs)), - mkNarrowTo32(Ity_I32, getIReg(rt)))); - putAcc(ac, mkexpr(t1)); + 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 0x19: { /* MULTU */ - DIP("multu ac%u r%u, r%u", ac, rs, rt); - t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_MullU32, mkNarrowTo32(Ity_I32, getIReg(rs)), - mkNarrowTo32(Ity_I32, - getIReg(rt)))); - putAcc(ac, mkexpr(t1)); - 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 0x1C: { /* Special2 */ - switch (function) { - case 0x00: { /* MADD */ - DIP("madd ac%u, r%u, r%u", ac, rs, rt); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - assign(t1, getAcc(ac)); - assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); - assign(t3, binop(Iop_Add64, mkexpr(t1), mkexpr(t2))); + case 0x04: { /* CLEI_S.df */ + ULong tmp = i5; - putAcc(ac, mkexpr(t3)); + 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: { /* MADDU */ - DIP("maddu ac%u r%u, r%u", ac, rs, rt); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - assign(t1, getAcc(ac)); - assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); - assign(t3, binop(Iop_Add64, mkexpr(t2), mkexpr(t1))); - - putAcc(ac, mkexpr(t3)); + 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 0x04: { /* MSUB */ - DIP("msub ac%u r%u, r%u", ac, rs, rt); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - assign(t1, getAcc(ac)); - assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); - assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2))); - - putAcc(ac, mkexpr(t3)); + 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 0x05: { /* MSUBU */ - DIP("msubu ac%u r%u, r%u", ac, rs, rt); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - assign(t1, getAcc(ac)); - assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); - assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2))); - - putAcc(ac, mkexpr(t3)); + 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 0x1F: { /* Special3 */ - switch (function) { - case 0x12: { /* ABSQ_S.PH */ - switch (sa) { - case 0x1: { /* ABSQ_S.QB */ - DIP("absq_s.qb r%u, r%u", rd, rt); - vassert(!mode64); - t0 = newTemp(Ity_I8); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I8); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I8); - t8 = newTemp(Ity_I8); - t9 = newTemp(Ity_I1); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I8); - t12 = newTemp(Ity_I8); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I1); - t15 = newTemp(Ity_I8); - t16 = newTemp(Ity_I32); - t17 = newTemp(Ity_I32); - - /* Absolute value of the rightmost byte (bits 7-0). */ - /* t0 - rightmost byte. */ - assign(t0, unop(Iop_16to8, unop(Iop_32to16, getIReg(rt)))); - /* t1 holds 1 if t0 is equal to 0x80, or 0 otherwise. */ - assign(t1, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, mkexpr(t0)), - mkU32(0x00000080))); - /* t2 holds 1 if value in t0 is negative, 0 otherwise. */ - assign(t2, unop(Iop_32to1, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00000080)), - mkU8(0x7)))); - /* t3 holds abs(t0). */ - assign(t3, IRExpr_ITE(mkexpr(t1), - mkU8(0x7F), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Add8, - unop(Iop_Not8, - mkexpr(t0)), - mkU8(0x1)), - mkexpr(t0)))); - - /* Absolute value of bits 15-8. */ - /* t4 - input byte. */ - assign(t4, - unop(Iop_16HIto8, unop(Iop_32to16, getIReg(rt)))); - /* t5 holds 1 if t4 is equal to 0x80, or 0 otherwise. */ - assign(t5, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, mkexpr(t4)), - mkU32(0x00000080))); - /* t6 holds 1 if value in t4 is negative, 0 otherwise. */ - assign(t6, unop(Iop_32to1, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - mkU8(15)))); - /* t3 holds abs(t4). */ - assign(t7, IRExpr_ITE(mkexpr(t5), - mkU8(0x7F), - IRExpr_ITE(mkexpr(t6), - binop(Iop_Add8, - unop(Iop_Not8, - mkexpr(t4)), - mkU8(0x1)), - mkexpr(t4)))); - - /* Absolute value of bits 23-15. */ - /* t8 - input byte. */ - assign(t8, - unop(Iop_16to8, unop(Iop_32HIto16, getIReg(rt)))); - /* t9 holds 1 if t8 is equal to 0x80, or 0 otherwise. */ - assign(t9, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, mkexpr(t8)), - mkU32(0x00000080))); - /* t6 holds 1 if value in t8 is negative, 0 otherwise. */ - assign(t10, unop(Iop_32to1, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00800000)), - mkU8(23)))); - /* t3 holds abs(t8). */ - assign(t11, IRExpr_ITE(mkexpr(t9), - mkU8(0x7F), - IRExpr_ITE(mkexpr(t10), - binop(Iop_Add8, - unop(Iop_Not8, - mkexpr(t8)), - mkU8(0x1)), - mkexpr(t8)))); - - /* Absolute value of bits 31-24. */ - /* t12 - input byte. */ - assign(t12, - unop(Iop_16HIto8, unop(Iop_32HIto16, getIReg(rt)))); - /* t13 holds 1 if t12 is equal to 0x80, or 0 otherwise. */ - assign(t13, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, mkexpr(t12)), - mkU32(0x00000080))); - /* t14 holds 1 if value in t12 is negative, 0 otherwise. */ - assign(t14, unop(Iop_32to1, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31)))); - /* t15 holds abs(t12). */ - assign(t15, IRExpr_ITE(mkexpr(t13), - mkU8(0x7F), - IRExpr_ITE(mkexpr(t14), - binop(Iop_Add8, - unop(Iop_Not8, - mkexpr(t12)), - mkU8(0x1)), - mkexpr(t12)))); - - /* t16 holds !0 if any of input bytes is 0x80 or 0 - otherwise. */ - assign(t16, - binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t13)), - unop(Iop_1Sto32, mkexpr(t9))), - unop(Iop_1Sto32, mkexpr(t5))), - unop(Iop_1Sto32, mkexpr(t1)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t16), - mkU32(0x0)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)))); - - /* t17 = t15|t11|t7|t3 */ - assign(t17, - binop(Iop_16HLto32, - binop(Iop_8HLto16, mkexpr(t15), mkexpr(t11)), - binop(Iop_8HLto16, mkexpr(t7), mkexpr(t3)))); - - putIReg(rd, mkexpr(t17)); - break; - } - case 0x2: { /* REPL.QB */ - DIP("repl.qb r%u, %u", rd, dsp_imm); - vassert(!mode64); - putIReg(rd, mkU32((dsp_imm << 24) | (dsp_imm << 16) | - (dsp_imm << 8) | (dsp_imm))); - break; - } - case 0x3: { /* REPLV.QB */ - DIP("replv.qb r%u, r%u", rd, rt); - vassert(!mode64); - t0 = newTemp(Ity_I8); - - assign(t0, unop(Iop_32to8, - binop(Iop_And32, getIReg(rt), mkU32(0xff)))); - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)), - binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)))); - break; - } - case 0x4: { /* PRECEQU.PH.QBL */ - DIP("precequ.ph.qbl r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xff000000)), - mkU8(1)), - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00ff0000)), - mkU8(9)))); - break; - } - case 0x5: { /* PRECEQU.PH.QBR */ - DIP("precequ.ph.qbr r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x0000ff00)), - mkU8(15)), - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x000000ff)), - mkU8(7)))); - break; - } - case 0x6: { /* PRECEQU.PH.QBLA */ - DIP("precequ.ph.qbla r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xff000000)), - mkU8(1)), - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x0000ff00)), - mkU8(1)))); - break; - } - case 0x7: { /* PRECEQU.PH.QBRA */ - DIP("precequ.ph.qbra r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00ff0000)), - mkU8(7)), - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x000000ff)), - mkU8(7)))); - break; - } - case 0x9: { /* ABSQ_S.PH */ - DIP("absq_s.ph r%u, r%u", rd, rt); - vassert(!mode64); - t0 = newTemp(Ity_I16); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I16); - t4 = newTemp(Ity_I16); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I16); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - - /* t0 holds lower 16 bits of value in rt. */ - assign(t0, unop(Iop_32to16, getIReg(rt))); - /* t1 holds 1 if t0 is equal to 0x8000. */ - assign(t1, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, mkexpr(t0)), - mkU32(0x00008000))); - /* t2 holds 1 if value in t0 is negative, 0 otherwise. */ - assign(t2, unop(Iop_32to1, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - mkU8(15)))); - /* t3 holds abs(t0). */ - assign(t3, IRExpr_ITE(mkexpr(t1), - mkU16(0x7FFF), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Add16, - unop(Iop_Not16, - mkexpr(t0)), - mkU16(0x1)), - mkexpr(t0)))); - - /* t4 holds lower 16 bits of value in rt. */ - assign(t4, unop(Iop_32HIto16, getIReg(rt))); - /* t5 holds 1 if t4 is equal to 0x8000. */ - assign(t5, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, mkexpr(t4)), - mkU32(0x00008000))); - /* t6 holds 1 if value in t4 is negative, 0 otherwise. */ - assign(t6, unop(Iop_32to1, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31)))); - /* t7 holds abs(t4). */ - assign(t7, IRExpr_ITE(mkexpr(t5), - mkU16(0x7FFF), - IRExpr_ITE(mkexpr(t6), - binop(Iop_Add16, - unop(Iop_Not16, - mkexpr(t4)), - mkU16(0x1)), - mkexpr(t4)))); - /* If any of the two input halfwords is equal 0x8000, - set bit 20 in DSPControl register. */ - assign(t8, binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t1)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t8), - mkU32(0x0)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)))); - - /* t9 = t7|t3 */ - assign(t9, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3))); - - putIReg(rd, mkexpr(t9)); - break; - } - case 0xA: { /* REPL.PH */ - DIP("repl.ph r%u, %u", rd, dsp_imm); - vassert(!mode64); - UShort immediate = extend_s_10to16(dsp_imm); + case 0x05: { /* CLEI_U.df */ + ULong tmp = i5; - putIReg(rd, mkU32(immediate << 16 | immediate)); - break; - } - case 0xB: { /* REPLV.PH */ - DIP("replv.ph r%u, r%u", rd, rt); - vassert(!mode64); + 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; + } - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, getIReg(rt)), - unop(Iop_32to16, getIReg(rt)))); - break; - } - case 0xC: { /* PRECEQ.W.PHL */ - DIP("preceq.w.phl r%u, r%u", rd, rt); - vassert(!mode64); - putIReg(rd, binop(Iop_And32, - getIReg(rt), - mkU32(0xffff0000))); - break; - } - case 0xD: { /* PRECEQ.W.PHR */ - DIP("preceq.w.phr r%u, r%u", rd, rt); - vassert(!mode64); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, getIReg(rt)), - mkU16(0x0))); - break; - } - case 0x11: { /* ABSQ_S.W */ - DIP("absq_s.w r%u, r%u", rd, rt); - vassert(!mode64); - t0 = newTemp(Ity_I1); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - - assign(t0, - binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000))); - - putDSPControl(IRExpr_ITE(mkexpr(t0), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - assign(t1, binop(Iop_CmpLT32S, getIReg(rt), mkU32(0x0))); - - assign(t2, IRExpr_ITE(mkexpr(t0), - mkU32(0x7FFFFFFF), - IRExpr_ITE(mkexpr(t1), - binop(Iop_Add32, - unop(Iop_Not32, - getIReg(rt)), - mkU32(0x1)), - getIReg(rt)))); - putIReg(rd, mkexpr(t2)); - break; - } - case 0x1B: { /* BITREV */ - DIP("bitrev r%u, r%u", rd, rt); - vassert(!mode64); - /* 32bit reversal as seen on Bit Twiddling Hacks site - http://graphics.stanford.edu/~seander/bithacks.html - section ReverseParallel */ - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); + 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; + } - assign(t1, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xaaaaaaaa)), - mkU8(0x1)), - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x55555555)), - mkU8(0x1)))); - assign(t2, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0xcccccccc)), - mkU8(0x2)), - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0x33333333)), - mkU8(0x2)))); - assign(t3, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0xf0f0f0f0)), - mkU8(0x4)), - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x0f0f0f0f)), - mkU8(0x4)))); - assign(t4, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0xff00ff00)), - mkU8(0x8)), - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x00ff00ff)), - mkU8(0x8)))); - assign(t5, binop(Iop_Or32, - binop(Iop_Shr32, - mkexpr(t4), - mkU8(0x10)), - binop(Iop_Shl32, - mkexpr(t4), - mkU8(0x10)))); - putIReg(rd, binop(Iop_Shr32, - mkexpr(t5), - mkU8(16))); - break; - } - case 0x1C: { /* PRECEU.PH.QBL */ - DIP("preceu.ph.qbl r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xff000000)), - mkU8(8)), - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00ff0000)), - mkU8(16)))); - break; - } - case 0x1E: { /* PRECEU.PH.QBLA */ - DIP("preceu.ph.qbla r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xff000000)), - mkU8(8)), - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x0000ff00)), - mkU8(8)))); - break; - } - case 0x1D: { /* PRECEU.PH.QBR */ - DIP("preceu.ph.qbr r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x0000ff00)), - mkU8(8)), - binop(Iop_And32, - getIReg(rt), - mkU32(0x000000ff)))); - break; - } - case 0x1F: { /* PRECEU.PH.QBRA */ - DIP("preceu.ph.qbra r%u, r%u", rd, rt); - vassert(!mode64); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00ff0000)), - binop(Iop_And32, - getIReg(rt), - mkU32(0x000000ff)))); - break; - } - default: - return -1; - } - break; /* end of ABSQ_S.PH */ - } - case 0x38: { /* EXTR.W */ - switch(sa) { - case 0x0: { /* EXTR.W */ - DIP("extr.w r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I32); - - assign(t0, getAcc(ac)); - if (0 == rs) { - assign(t1, mkexpr(t0)); - } else { - assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); - } - /* Check if bits 63..31 of the result in t1 aren't 0. */ - assign(t3, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0))); - /* Check if bits 63..31 of the result in t1 aren't - 0x1ffffffff. */ - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0x80000000))); - /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP - control register. */ - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t6))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t7), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - /* If the last discarded bit is 1, there would be carry - when rounding, otherwise there wouldn't. We use that - fact and just add the value of the last discarded bit - to the least sifgnificant bit of the shifted value - from acc. */ - if (0 == rs) { - assign(t8, mkU64(0x0ULL)); - } else { - assign(t8, binop(Iop_And64, - binop(Iop_Shr64, - mkexpr(t0), - mkU8(rs-1)), - mkU64(0x1ULL))); - } - assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + 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; + } - /* Repeat previous steps for the rounded value. */ - assign(t10, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0))); - assign(t11, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0))); + 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; + } + } - assign(t12, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0xffffffff))); - assign(t13, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x80000000))); - - assign(t14, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t11))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t12)), - unop(Iop_1Sto32, mkexpr(t13))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - if (0 == rs) { - putIReg(rt, unop(Iop_64to32, mkexpr(t0))); - } else { - putIReg(rt, unop(Iop_64to32, mkexpr(t1))); - } - break; - } - case 0x1: { /* EXTRV.W */ - DIP("extrv.w r%u, ac%u, r%u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I32); - t15 = newTemp(Ity_I8); - - assign(t15, unop(Iop_32to8, - binop(Iop_And32, - getIReg(rs), - mkU32(0x1f)))); - assign(t0, getAcc(ac)); - assign(t1, binop(Iop_Sar64, mkexpr(t0), mkexpr(t15))); - putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - mkexpr(t15)), - mkU32(0)), - unop(Iop_64to32, mkexpr(t0)), - unop(Iop_64to32, mkexpr(t1)))); - - /* Check if bits 63..31 of the result in t1 aren't 0. */ - assign(t3, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0))); - /* Check if bits 63..31 of the result in t1 aren't - 0x1ffffffff. */ - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0x80000000))); - /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP - control register. */ - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t6))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t7), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - /* If the last discarded bit is 1, there would be carry - when rounding, otherwise there wouldn't. We use that - fact and just add the value of the last discarded bit - to the least sifgnificant bit of the shifted value - from acc. */ - assign(t8, - IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - mkexpr(t15)), - mkU32(0)), - mkU64(0x0ULL), - binop(Iop_And64, - binop(Iop_Shr64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_Sub32, - unop(Iop_8Uto32, - mkexpr(t15)), - mkU32(1)))), - mkU64(0x1ULL)))); - - assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); - - /* Repeat previous steps for the rounded value. */ - assign(t10, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0))); - assign(t11, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0))); + break; + } - assign(t12, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0xffffffff))); - assign(t13, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x80000000))); - - assign(t14, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t11))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t12)), - unop(Iop_1Sto32, mkexpr(t13))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - break; - } - case 0x2: { /* EXTP */ - DIP("extp r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I8); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I32); - - assign(t0, getAcc(ac)); - /* Extract pos field of DSPControl register. */ - assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); - - /* Check if (pos - size) >= 0 [size <= pos] - if (pos < size) - put 1 to EFI field of DSPControl register - else - extract bits from acc and put 0 to EFI field of - DSPCtrl */ - assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfff)), - mkU32(0x4000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfff)))); - - /* If pos <= 31, shift right the value from the acc - (pos-size) times and take (size+1) bits from the least - significant positions. Otherwise, shift left the value - (63-pos) times, take (size+1) bits from the most - significant positions and shift right (31-size) times.*/ - assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); - - assign(t4, - IRExpr_ITE(mkexpr(t3), - unop(Iop_32to8, - binop(Iop_Sub32, - mkexpr(t1), mkU32(rs))), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(63), mkexpr(t1))))); - - assign(t5, IRExpr_ITE(mkexpr(t3), - binop(Iop_Shr64, - mkexpr(t0), mkexpr(t4)), - binop(Iop_Shl64, - mkexpr(t0), mkexpr(t4)))); - - /* t6 holds a mask for bit extraction */ - assign(t6, - IRExpr_ITE(mkexpr(t3), - unop(Iop_Not64, - binop(Iop_Shl64, - mkU64(0xffffffffffffffffULL), - mkU8(rs+1))), - unop(Iop_Not64, - binop(Iop_Shr64, - mkU64(0xffffffffffffffffULL), - mkU8(rs+1))))); - - assign(t7, IRExpr_ITE(mkexpr(t3), - unop(Iop_64to32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - binop(Iop_Shr32, - unop(Iop_64HIto32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - mkU8(31-rs)))); + case 0x06: { /* LDI.df */ + ULong tmp; + UShort s10; + s10 = (cins & 0x001FF800) >> 11; - putIReg(rt, mkexpr(t7)); - break; - } - case 0x3: { /* EXTPV */ - DIP("extpv r%u, ac%u, r%u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I8); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); - assign(t0, getAcc(ac)); - /* Extract pos field of DSPControl register. */ - assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); - - /* Check if (pos - size) >= 0 [size <= pos] - if (pos < size) - put 1 to EFI field of DSPControl register - else - extract bits from acc and put 0 to EFI field of - DSPCtrl */ - assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfff)), - mkU32(0x4000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfff)))); - - /* If pos <= 31, shift right the value from the acc - (pos-size) times and take (size+1) bits from the least - significant positions. Otherwise, shift left the value - (63-pos) times, take (size+1) bits from the most - significant positions and shift right (31-size) - times. */ - assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); - - assign(t4, - IRExpr_ITE(mkexpr(t3), - unop(Iop_32to8, - binop(Iop_Sub32, - mkexpr(t1), mkexpr(t8))), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(63), mkexpr(t1))))); - - assign(t5, IRExpr_ITE(mkexpr(t3), - binop(Iop_Shr64, - mkexpr(t0), mkexpr(t4)), - binop(Iop_Shl64, - mkexpr(t0), mkexpr(t4)))); - - /* t6 holds a mask for bit extraction. */ - assign(t6, - IRExpr_ITE(mkexpr(t3), - unop(Iop_Not64, - binop(Iop_Shl64, - mkU64(0xffffffffffffffffULL), - unop(Iop_32to8, - binop(Iop_Add32, - mkexpr(t8), - mkU32(1))))), - unop(Iop_Not64, - binop(Iop_Shr64, - mkU64(0xffffffffffffffffULL), - unop(Iop_32to8, - binop(Iop_Add32, - mkexpr(t8), - mkU32(1))))))); - - assign(t7, IRExpr_ITE(mkexpr(t3), - unop(Iop_64to32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - binop(Iop_Shr32, - unop(Iop_64HIto32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(31), - mkexpr(t8)))))); + 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; - putIReg(rt, mkexpr(t7)); - break; - } - case 0x4: { /* EXTR_R.W */ - DIP("extr_r.w r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I32); - t15 = newTemp(Ity_I64); - t16 = newTemp(Ity_I1); - - assign(t0, getAcc(ac)); - assign(t16, binop(Iop_CmpEQ32, - mkU32(rs), - mkU32(0))); - assign(t1, IRExpr_ITE(mkexpr(t16), - mkexpr(t0), - binop(Iop_Sar64, - mkexpr(t0), - mkU8(rs)))); - /* If the last discarded bit is 1, there would be carry - when rounding, otherwise there wouldn't. We use that - fact and just add the value of the last discarded bit - to the least significant bit of the shifted value - from acc. */ - assign(t15, binop(Iop_Shr64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_Sub32, - binop(Iop_And32, - mkU32(rs), - mkU32(0x1f)), - mkU32(1))))); - - assign(t8, - IRExpr_ITE(mkexpr(t16), - mkU64(0x0ULL), - binop(Iop_And64, - mkexpr(t15), - mkU64(0x0000000000000001ULL)))); - assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); - putIReg(rt, unop(Iop_64to32, mkexpr(t9))); - - /* Check if bits 63..31 of the result in t1 aren't 0. */ - assign(t3, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0))); + 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; - /* Check if bits 63..31 of the result in t1 aren't - 0x1ffffffff. */ - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0x80000000))); - /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP - control register. */ - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t6))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t7), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - /* Repeat previous steps for the rounded value. */ - assign(t10, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0))); - assign(t11, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0))); + case 0x02: /* LDI.W */ + DIP("LDI.W w%d, %d", wd, s10); + tmp = extend_s_10to32(s10); + tmp = tmp | (tmp << 32); + break; - assign(t12, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0xffffffff))); - assign(t13, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x80000000))); - - assign(t14, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t11))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t12)), - unop(Iop_1Sto32, mkexpr(t13))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - break; - } - case 0x5: { /* EXTRV_R.W */ - DIP("extrv_r.w r%u, ac%u, r%u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I32); - t15 = newTemp(Ity_I8); - - assign(t15, unop(Iop_32to8, - binop(Iop_And32, - getIReg(rs), - mkU32(0x1f)))); - assign(t0, getAcc(ac)); - assign(t1, binop(Iop_Sar64, mkexpr(t0), mkexpr(t15))); - - /* Check if bits 63..31 of the result in t1 aren't 0. */ - assign(t3, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0))); - /* Check if bits 63..31 of the result in t1 aren't - 0x1ffffffff. */ - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0x80000000))); - /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP - control register. */ - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t6))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t7), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - /* If the last discarded bit is 1, there would be carry - when rounding, otherwise there wouldn't. We use that - fact and just add the value of the last discarded bit - to the least sifgnificant bit of the shifted value - from acc. */ - assign(t8, - IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - mkexpr(t15)), - mkU32(0)), - mkU64(0x0ULL), - binop(Iop_And64, - binop(Iop_Shr64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_Sub32, - unop(Iop_8Uto32, - mkexpr(t15)), - mkU32(1)))), - mkU64(0x1ULL)))); - - assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); - /* Put rounded value in destination register. */ - putIReg(rt, unop(Iop_64to32, mkexpr(t9))); - - /* Repeat previous steps for the rounded value. */ - assign(t10, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0))); - assign(t11, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0))); + case 0x03: /* LDI.D */ + DIP("LDI.D w%d, %d", wd, s10); + tmp = extend_s_10to64(s10); + break; - assign(t12, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0xffffffff))); - assign(t13, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x80000000))); - - assign(t14, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t11))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t12)), - unop(Iop_1Sto32, mkexpr(t13))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - break; - } - case 0x6: { /* EXTR_RS.W */ - DIP("extr_rs.w r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I32); - t16 = newTemp(Ity_I32); - - assign(t0, getAcc(ac)); - if (0 == rs) { - assign(t1, mkexpr(t0)); - } else { - assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); - } + default: + return -1; + } - /* Check if bits 63..31 of the result in t1 aren't 0. */ - assign(t3, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0))); - /* Check if bits 63..31 of the result in t1 aren't - 0x1ffffffff. */ - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0x80000000))); - /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP - control register. */ - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t6))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t7), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - /* If the last discarded bit is 1, there would be carry - when rounding, otherwise there wouldn't. We use that - fact and just add the value of the last discarded bit - to the least sifgnificant bit of the shifted value - from acc. */ - if (0 == rs) { - assign(t8, mkU64(0x0ULL)); - } else { - assign(t8, binop(Iop_And64, - binop(Iop_Shr64, - mkexpr(t0), - mkU8(rs-1)), - mkU64(0x1ULL))); - } + putWReg(wd, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp))); + break; + } - assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + default: + return -1; + } - /* Repeat previous steps for the rounded value. */ - assign(t10, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0))); - assign(t11, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0))); + return 0; +} - assign(t12, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0xffffffff))); - assign(t13, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x80000000))); - - assign(t14, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t11))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t12)), - unop(Iop_1Sto32, mkexpr(t13))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - assign(t16, binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0x80000000))); - putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t16), - mkU32(0)), - mkU32(0x7fffffff), - mkU32(0x80000000)), - unop(Iop_64to32, mkexpr(t9)))); - break; - } - case 0x7: { /* EXTRV_RS.W */ - DIP("extrv_rs.w r%u, ac%u, r%u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I32); - t15 = newTemp(Ity_I32); - t16 = newTemp(Ity_I32); - t17 = newTemp(Ity_I1); - - assign(t15, binop(Iop_And32, - getIReg(rs), - mkU32(0x1f))); - assign(t17, binop(Iop_CmpEQ32, - mkexpr(t15), - mkU32(0))); - assign(t0, getAcc(ac)); - assign(t1, IRExpr_ITE(mkexpr(t17), - mkexpr(t0), - binop(Iop_Sar64, - mkexpr(t0), - unop(Iop_32to8, - mkexpr(t15))))); - - /* Check if bits 63..31 of the result in t1 aren't 0. */ - assign(t3, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0))); - /* Check if bits 63..31 of the result in t1 aren't - 0x1ffffffff. */ - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t1)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000)), - mkU32(0x80000000))); - /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP - control register. */ - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t5)), - unop(Iop_1Sto32, mkexpr(t6))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t7), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - /* If the last discarded bit is 1, there would be carry - when rounding, otherwise there wouldn't. We use that - fact and just add the value of the last discarded bit - to the least sifgnificant bit of the shifted value - from acc. */ - assign(t8, - IRExpr_ITE(mkexpr(t17), - mkU64(0x0ULL), - binop(Iop_And64, - binop(Iop_Shr64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_Sub32, - mkexpr(t15), - mkU32(1)))), - mkU64(0x1ULL)))); - - assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); - - /* Repeat previous steps for the rounded value. */ - assign(t10, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0))); - assign(t11, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0))); +static Int msa_BIT_09(UInt cins, UChar wd, UChar ws) /* BIT (0x09) */ +{ + IRTemp t1, t2, t3; + UShort operation; + UChar df, m; - assign(t12, binop(Iop_CmpNE32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0xffffffff))); - assign(t13, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x80000000))); - - assign(t14, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t11))), - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t12)), - unop(Iop_1Sto32, mkexpr(t13))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - - assign(t16, binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0x80000000))); - putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t14), - mkU32(0)), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t16), - mkU32(0)), - mkU32(0x7fffffff), - mkU32(0x80000000)), - unop(Iop_64to32, mkexpr(t9)))); - break; - } - case 0xA: { /* EXTPDP */ - DIP("extpdp r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I8); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t0, getAcc(ac)); - /* Extract pos field of DSPControl register. */ - assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); - - /* Check if (pos - size) >= 0 [size <= pos] - if (pos < size) - put 1 to EFI field of DSPControl register - else - extract bits from acc and put 0 to EFI field of - DSPCtrl */ - assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs))); - - assign(t8, binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfc0)), - binop(Iop_And32, - binop(Iop_Sub32, - binop(Iop_And32, - getDSPControl(), - mkU32(0x3f)), - mkU32(rs+1)), - mkU32(0x3f)))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfff)), - mkU32(0x4000)), - mkexpr(t8))); - - /* If pos <= 31, shift right the value from the acc - (pos-size) times and take (size+1) bits from the least - significant positions. Otherwise, shift left the value - (63-pos) times, take (size+1) bits from the most - significant positions and shift right (31-size) times. - */ - assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); - - assign(t4, - IRExpr_ITE(mkexpr(t3), - unop(Iop_32to8, - binop(Iop_Sub32, - mkexpr(t1), mkU32(rs))), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(63), mkexpr(t1))))); - - assign(t5, IRExpr_ITE(mkexpr(t3), - binop(Iop_Shr64, - mkexpr(t0), mkexpr(t4)), - binop(Iop_Shl64, - mkexpr(t0), mkexpr(t4)))); - - /* t6 holds a mask for bit extraction. */ - assign(t6, - IRExpr_ITE(mkexpr(t3), - unop(Iop_Not64, - binop(Iop_Shl64, - mkU64(0xffffffffffffffffULL), - mkU8(rs+1))), - unop(Iop_Not64, - binop(Iop_Shr64, - mkU64(0xffffffffffffffffULL), - mkU8(rs+1))))); - - assign(t7, IRExpr_ITE(mkexpr(t3), - unop(Iop_64to32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - binop(Iop_Shr32, - unop(Iop_64HIto32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - mkU8(31-rs)))); + operation = (cins & 0x03800000) >> 23; + df = (cins & 0x007F0000) >> 16; - putIReg(rt, mkexpr(t7)); - break; - } - case 0xB: { /* EXTPDPV */ - DIP("extpdpv r%u, ac%u, r%u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I8); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - - assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); - assign(t0, getAcc(ac)); - /* Extract pos field of DSPControl register. */ - assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); - - /* Check if (pos - size) >= 0 [size <= pos] - if (pos < size) - put 1 to EFI field of DSPControl register - else - extract bits from acc and put 0 to EFI field of - DSPCtrl */ - assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8))); - - assign(t9, binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfc0)), - binop(Iop_And32, - binop(Iop_Sub32, - binop(Iop_And32, - getDSPControl(), - mkU32(0x3f)), - binop(Iop_Add32, - mkexpr(t8), - mkU32(0x1))), - mkU32(0x3f)))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffbfff)), - mkU32(0x4000)), - mkexpr(t9))); - - /* If pos <= 31, shift right the value from the acc - (pos-size) times and take (size+1) bits from the least - significant positions. Otherwise, shift left the value - (63-pos) times, take (size+1) bits from the most - significant positions and shift right (31-size) times. - */ - assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); - - assign(t4, - IRExpr_ITE(mkexpr(t3), - unop(Iop_32to8, - binop(Iop_Sub32, - mkexpr(t1), mkexpr(t8))), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(63), mkexpr(t1))))); - - assign(t5, IRExpr_ITE(mkexpr(t3), - binop(Iop_Shr64, - mkexpr(t0), mkexpr(t4)), - binop(Iop_Shl64, - mkexpr(t0), mkexpr(t4)))); - - /* t6 holds a mask for bit extraction. */ - assign(t6, - IRExpr_ITE(mkexpr(t3), - unop(Iop_Not64, - binop(Iop_Shl64, - mkU64(0xffffffffffffffffULL), - unop(Iop_32to8, - binop(Iop_Add32, - mkexpr(t8), - mkU32(1))))), - unop(Iop_Not64, - binop(Iop_Shr64, - mkU64(0xffffffffffffffffULL), - unop(Iop_32to8, - binop(Iop_Add32, - mkexpr(t8), - mkU32(1))))))); - - assign(t7, IRExpr_ITE(mkexpr(t3), - unop(Iop_64to32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - binop(Iop_Shr32, - unop(Iop_64HIto32, - binop(Iop_And64, - mkexpr(t5), - mkexpr(t6))), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(31), - mkexpr(t8)))))); + 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; + } - putIReg(rt, mkexpr(t7)); - break; - } - case 0xE: { /* EXTR_S.H */ - DIP("extr_s.h r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); + 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; + } - assign(t0, getAcc(ac)); + 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; + } - assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + 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; + } - assign(t2, binop(Iop_Or32, - getDSPControl(), mkU32(0x00800000))); + 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; + } + } - assign(t9, binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t9), - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t0)), - mkU32(0x80000000))), - mkexpr(t2), - getDSPControl())); + break; + } - /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0) - 1. subtract 0x7fff from t1 - 2. if the resulting number is positive (sign bit = 0) - and any of the other bits is 1, the value is > 0. */ - assign(t3, binop(Iop_Sub64, - mkexpr(t1), - mkU64(0x0000000000007fffULL))); - assign(t4, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t3)), - mkU32(0x7fffffff)))), - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - unop(Iop_64to32, - mkexpr(t3))))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t3)), - mkU32(0x80000000)), - mkU32(0))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t4)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - /* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0 - 1. subtract t1 from 0xffffffffffff8000 - 2. if the resulting number is positive (sign bit = 0) - and any of the other bits is 1, the value is > 0 */ - assign(t6, binop(Iop_Sub64, - mkU64(0xffffffffffff8000ULL), - mkexpr(t1))); - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t6)), - mkU32(0x7fffffff)))), - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - unop(Iop_64to32, - mkexpr(t6))))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t6)), - mkU32(0x80000000)), - mkU32(0))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t7)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t4)), - mkU32(0x00007fff), - IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t7)), - mkU32(0xffff8000), - unop(Iop_64to32, - mkexpr(t1))))); - break; - } - case 0xF: { /* EXTRV_S.H */ - DIP("extrv_s.h r%u, ac%u, %u", rt, ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); + 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; + } - assign(t0, getAcc(ac)); + 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; + } - assign(t1, binop(Iop_Sar64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_And32, - getIReg(rs), - mkU32(0x1f))))); + 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; + } - assign(t2, binop(Iop_Or32, - getDSPControl(), mkU32(0x00800000))); + 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; + } + } - assign(t9, binop(Iop_And32, - unop(Iop_64to32, - mkexpr(t1)), - mkU32(0x80000000))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t9), - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t0)), - mkU32(0x80000000))), - mkexpr(t2), - getDSPControl())); + break; + } - /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0) - 1. subtract 0x7fff from t1 - 2. if the resulting number is positive (sign bit = 0) - and any of the other bits is 1, the value is > 0. */ - assign(t3, binop(Iop_Sub64, - mkexpr(t1), - mkU64(0x0000000000007fffULL))); - assign(t4, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t3)), - mkU32(0x7fffffff)))), - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - unop(Iop_64to32, - mkexpr(t3))))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t3)), - mkU32(0x80000000)), - mkU32(0))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t4)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - /* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0 - 1. subtract t1 from 0xffffffffffff8000 - 2. if the resulting number is positive (sign bit = 0) - and any of the other bits is 1, the value is > 0 */ - assign(t6, binop(Iop_Sub64, - mkU64(0xffffffffffff8000ULL), - mkexpr(t1))); - assign(t7, binop(Iop_And32, - binop(Iop_Or32, - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t6)), - mkU32(0x7fffffff)))), - unop(Iop_1Sto32, - binop(Iop_CmpNE32, - mkU32(0), - unop(Iop_64to32, - mkexpr(t6))))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t6)), - mkU32(0x80000000)), - mkU32(0))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t7)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00800000)), - getDSPControl())); - putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t4)), - mkU32(0x00007fff), - IRExpr_ITE(binop(Iop_CmpNE32, - mkU32(0), - mkexpr(t7)), - mkU32(0xffff8000), - unop(Iop_64to32, - mkexpr(t1))))); - break; - } - case 0x12: { /* RDDSP*/ - DIP("rddsp r%u, mask 0x%x", rd, rddsp_mask); - vassert(!mode64); + 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; + } - putIReg(rd, mkU32(0x0)); + 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; + } - if ((rddsp_mask & 0x1) == 0x1) { - /* Read pos field (bits 5-0) of DSPControl register. */ - putIReg(rd, binop(Iop_Or32, - getIReg(rd), - binop(Iop_And32, - getDSPControl(), - mkU32(0x0000003F)))); - } + 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; + } - if ((rddsp_mask & 0x2) == 0x2) { - /* Read scount field (bits 12-7) of DSPControl - register. */ - putIReg(rd, binop(Iop_Or32, - getIReg(rd), - binop(Iop_And32, - getDSPControl(), - mkU32(0x00001F80)))); - } + 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; + } + } - if ((rddsp_mask & 0x4) == 0x4) { - /* Read C field (bit 13) of DSPControl register. */ - putIReg(rd, binop(Iop_Or32, - getIReg(rd), - binop(Iop_And32, - getDSPControl(), - mkU32(0x00002000)))); - } + break; + } - if ((rddsp_mask & 0x8) == 0x8) { - /* Read outflag field (bit s 23-16) of DSPControl - register. */ - putIReg(rd, binop(Iop_Or32, - getIReg(rd), - binop(Iop_And32, - getDSPControl(), - mkU32(0x00FF0000)))); - } + case 0x03: { /* BCLRI.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + t3 = newTemp(Ity_V128); + ULong tmp = 1; + assign(t1, getWReg(ws)); - if ((rddsp_mask & 0x10) == 0x10) { - /* Read ccond field (bits 31-24) of DSPControl - register. */ - putIReg(rd, binop(Iop_Or32, - getIReg(rd), - binop(Iop_And32, - getDSPControl(), - mkU32(0xFF000000)))); - } + 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; + } - if ((rddsp_mask & 0x20) == 0x20) { - /* Read EFI field (bit 14) of DSPControl register. */ - putIReg(rd, binop(Iop_Or32, - getIReg(rd), - binop(Iop_And32, - getDSPControl(), - mkU32(0x00004000)))); - } + 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; + } - if ((rddsp_mask & 0x3f) == 0x3f) { - /* Read all fields of DSPControl register. */ - putIReg(rd, getDSPControl()); - } - break; - } - case 0x13: { /* WRDSP */ - DIP("wrdsp r%u, mask 0x%x", rs, wrdsp_mask); - vassert(!mode64); - - if ((wrdsp_mask & 0x3f) == 0x3f) { - /* If mips64 put all fields of rs, except bit 15 and bit - 6, to DSPControl register, otherwise put all except - bits 15, 6 and bits 31..28. */ - putDSPControl(mode64 ? - binop(Iop_And32, - getIReg(rs), - mkU32(0xffff7fbf)) : - binop(Iop_And32, - getIReg(rs), - mkU32(0x0fff7fbf))); - } else { - if ((wrdsp_mask & 0x1) == 0x1) { - /* Put bits 5-0 of rs to DSPControl register pos - field. */ - putDSPControl(binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xFFFF7F40)), - binop(Iop_And32, - getIReg(rs), - mkU32(0x0000003F)))); - } + 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; + } - if ((wrdsp_mask & 0x2) == 0x2) { - /* Put bits 12-7 of rs to DSPControl scount field. */ - putDSPControl(binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xFFFFE03F)), - binop(Iop_And32, - getIReg(rs), - mkU32(0x00001F80)))); - } + 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; + } + } - if ((wrdsp_mask & 0x4) == 0x4) { - /* Put bit 13 of rs to DSPControl register C - field. */ - putDSPControl(binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xFFFF5FBF)), - binop(Iop_And32, - getIReg(rs), - mkU32(0x00002000)))); - } + assign(t3, binop(Iop_AndV128, + mkexpr(t1), unop(Iop_NotV128, mkexpr(t2)))); + putWReg(wd, mkexpr(t3)); + break; + } - if ((wrdsp_mask & 0x8) == 0x8) { - /* Put bits 23-16 of rs to DSPControl reg outflag - field. */ - putDSPControl(binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xFF007FBF)), - binop(Iop_And32, - getIReg(rs), - mkU32(0x00FF0000)))); - } + case 0x04: { /* BSETI */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + t3 = newTemp(Ity_V128); + ULong tmp = 1; + assign(t1, getWReg(ws)); - if ((wrdsp_mask & 0x10) == 0x10) { - /* Put bits 31-24 of rs to DSPControl reg ccond - field. */ - putDSPControl(binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0x00FF7FBF)), - binop(Iop_And32, - getIReg(rs), - mode64 ? mkU32(0xFF000000) - : mkU32(0x0F000000)) - ) - ); - } + 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; + } - if ((wrdsp_mask & 0x20) == 0x20) { - /* Put bit 14 of rs to DSPControl register EFI - field. */ - putDSPControl(binop(Iop_Or32, - binop(Iop_And32, - getDSPControl(), - mkU32(0xFFFF3FBF)), - binop(Iop_And32, - getIReg(rs), - mkU32(0x00004000)))); - } - } - break; - } - case 0x1A: { /* SHILO */ - DIP("shilo ac%u, %u", ac, shift); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); + 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; + } - assign(t0, getAcc(ac)); + 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; + } - putAcc(ac, mkexpr(t0)); + 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; + } + } - if (0x20 == (shift & 0x3f)) { - putAcc(ac, binop(Iop_32HLto64, - unop(Iop_64to32, mkexpr(t0)), - mkU32(0x0))); - } else if (0x20 == (shift & 0x20)) { - assign(t1, binop(Iop_Shl64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_Add32, - unop(Iop_Not32, - mkU32(shift)), - mkU32(0x1))))); + assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2))); + putWReg(wd, mkexpr(t3)); + break; + } - putAcc(ac, mkexpr(t1)); - } else { - assign(t1, binop(Iop_Shr64, mkexpr(t0), mkU8(shift))); + case 0x05: { /* BNEGI.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + t3 = newTemp(Ity_V128); + ULong tmp = 1; + assign(t1, getWReg(ws)); - putAcc(ac, mkexpr(t1)); - } - break; - } - case 0x1B: { /* SHILOV */ - DIP("shilov ac%u, r%u", ac, rs); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - assign(t1, binop(Iop_And32, getIReg(rs), mkU32(0x3f))); - assign(t2, binop(Iop_CmpEQ32, mkexpr(t1), mkU32(0x20))); - assign(t3, binop(Iop_Shl64, - mkexpr(t0), - unop(Iop_32to8, - binop(Iop_Add32, - unop(Iop_Not32, - mkexpr(t1)), - mkU32(0x1))))); - assign(t4, binop(Iop_Shr64, - mkexpr(t0), - unop(Iop_32to8, - mkexpr(t1)))); - - putAcc(ac, - IRExpr_ITE(mkexpr(t2), - binop(Iop_32HLto64, - unop(Iop_64to32, mkexpr(t0)), - mkU32(0x0)), - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0x20)), - mkU32(0x20)), - mkexpr(t3), - mkexpr(t4)))); - break; - } - case 0x1F: { /* MTHLIP */ - DIP("mthlip r%u, ac%u", rs, ac); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - - assign(t0, getAcc(ac)); - putAcc(ac, binop(Iop_32HLto64, - unop(Iop_64to32, mkexpr(t0)), - getIReg(rs))); - assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpLE32U, - mkU32(32), - mkexpr(t1)), - binop(Iop_Or32, - binop(Iop_Sub32, - mkexpr(t1), - mkU32(32)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffffc0))), - binop(Iop_Or32, - binop(Iop_Add32, - mkexpr(t1), - mkU32(32)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffffc0))))); - break; - } - default: - return -1; - } - break; /* end of EXTR.W */ + 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 0xA: { /* LX */ - switch(sa) { - case 0x0: { /* LWX */ - DIP("lwx r%u, r%u(r%u)", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + 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; + } - putIReg(rd, load(Ity_I32, mkexpr(t0))); - break; - } - case 0x4: { /* LHX */ - DIP("lhx r%u, r%u(r%u)", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); + 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; + } - assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + 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; + } + } - putIReg(rd, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t0)))); - break; - } - case 0x6: { /* LBUX */ - DIP("lbux r%u, r%u(r%u)", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); + assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2))); + putWReg(wd, mkexpr(t3)); + break; + } - assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + 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; + } - putIReg(rd, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t0)))); - break; - } - default: - return -1; - } - break; /* end of LX */ - } - case 0xC: { /* INSV */ - switch(sa) { - case 0x0: { /* INSV */ - DIP("insv r%u, r%u", rt, rs); - vassert(!mode64); - - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - - /* t0 <- pos field of DSPControl register. */ - assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); - /* t1 <- scount field of DSPControl register. */ - assign(t1, binop(Iop_Shr32, - binop(Iop_And32, - getDSPControl(), - mkU32(0x1f80)), - mkU8(7))); - - assign(t2, unop(Iop_32to8, - binop(Iop_Add32, - mkexpr(t1), - mkexpr(t0)))); + 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; + } - /* 32-(pos+size) most significant bits of rt. */ - assign(t6, binop(Iop_Shl32, - binop(Iop_Shr32, - getIReg(rt), - mkexpr(t2)), - mkexpr(t2))); + 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; + } - assign(t3, unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(32), - mkexpr(t0)))); - /* Pos least significant bits of rt. */ - assign(t7, binop(Iop_Shr32, - binop(Iop_Shl32, - getIReg(rt), - mkexpr(t3)), - mkexpr(t3))); - - /* Size least significant bits of rs, - shifted to appropriate position. */ - assign(t8, binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rs), - unop(Iop_Not32, - binop(Iop_Shl32, - mkU32(0xffffffff), - unop(Iop_32to8, - mkexpr(t1))))), - unop(Iop_32to8, - mkexpr(t0)))); - - putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t0), - mkU32(0)), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t1), - mkU32(32)), - getIReg(rs), - binop(Iop_Or32, - mkexpr(t6), - mkexpr(t8))), - IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - mkexpr(t2)), - mkU32(32)), - binop(Iop_Or32, - mkexpr(t7), - mkexpr(t8)), - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t6), - mkexpr(t7)), - mkexpr(t8))))); - break; - } - default: - return -1; - } - break; /* enf of INSV */ - } - case 0x10: { /* ADDU.QB */ - switch(sa) { - case 0x00: { /* ADDU.QB */ - DIP("addu.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I32); - - /* Add rightmost bytes of rs and rt. */ - assign(t0, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - /* t1 will be 1 if there is overflow, 0 otherwise. */ - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00000100)), - mkU32(0x00000100))); - - /* Add bits 15-8 of rs and rt. */ - assign(t2, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - /* t3 will be 1 if there is overflow, 0 otherwise. */ - assign(t3, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00000100)), - mkU32(0x00000100))); + 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; + } - /* Add bits 15-8 of rs and rt. */ - assign(t4, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt)))))); - /* t5 will be 1 if there is overflow, 0 otherwise. */ - assign(t5, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x00000100)), - mkU32(0x00000100))); - - /* Add bits 15-8 of rs and rt. */ - assign(t6, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt)))))); - /* t7 will be 1 if there is overflow, 0 otherwise. */ - assign(t7, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0x00000100)), - mkU32(0x00000100))); - - assign(t8, - binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t7)), - unop(Iop_1Sto32, mkexpr(t5))), - unop(Iop_1Sto32, mkexpr(t3))), - unop(Iop_1Sto32, mkexpr(t1)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t8), - mkU32(0x0)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)))); - - putIReg(rd, binop(Iop_16HLto32, - binop(Iop_8HLto16, - unop(Iop_32to8, mkexpr(t6)), - unop(Iop_32to8, mkexpr(t4))), - binop(Iop_8HLto16, - unop(Iop_32to8, mkexpr(t2)), - unop(Iop_32to8, mkexpr(t0))))); - break; - } - case 0x1: { /* SUBU.QB */ - DIP("subu.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I32); - - /* Subtract rightmost bytes of rs and rt. */ - assign(t0, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - /* t1 will be 1 if there is overflow, 0 otherwise. */ - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00000100)), - mkU32(0x00000100))); - - /* Subtract bits 15-8 of rs and rt. */ - assign(t2, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - /* t3 will be 1 if there is overflow, 0 otherwise. */ - assign(t3, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00000100)), - mkU32(0x00000100))); - - /* Subtract bits 15-8 of rs and rt. */ - assign(t4, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt)))))); - /* t5 will be 1 if there is overflow, 0 otherwise. */ - assign(t5, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x00000100)), - mkU32(0x00000100))); - - /* Subtract bits 15-8 of rs and rt. */ - assign(t6, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt)))))); - /* t7 will be 1 if there is overflow, 0 otherwise. */ - assign(t7, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0x00000100)), - mkU32(0x00000100))); - - assign(t8, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t7)), - unop(Iop_1Sto32, mkexpr(t5))), - unop(Iop_1Sto32, mkexpr(t3))), - unop(Iop_1Sto32, mkexpr(t1)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t8), - mkU32(0x0)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)))); - - putIReg(rd, binop(Iop_16HLto32, - binop(Iop_8HLto16, - unop(Iop_32to8, mkexpr(t6)), - unop(Iop_32to8, mkexpr(t4))), - binop(Iop_8HLto16, - unop(Iop_32to8, mkexpr(t2)), - unop(Iop_32to8, mkexpr(t0))))); - break; - } - case 0x04: { /* ADDU_S.QB */ - DIP("addu_s.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I8); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I8); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I8); - t12 = newTemp(Ity_I32); - - /* Add rightmost bytes of rs and rt. */ - assign(t0, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - /* t1 will be 1 if there is overflow, 0 otherwise. */ - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00000100)), - mkU32(0x00000100))); - /* Saturate if necessary. */ - assign(t2, IRExpr_ITE(mkexpr(t1), - mkU8(0xff), - unop(Iop_32to8, mkexpr(t0)))); - - /* Add bits 15-8 of rs and rt. */ - assign(t3, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - /* t4 will be 1 if there is overflow, 0 otherwise. */ - assign(t4, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x00000100)), - mkU32(0x00000100))); - /* Saturate if necessary. */ - assign(t5, IRExpr_ITE(mkexpr(t4), - mkU8(0xff), - unop(Iop_32to8, mkexpr(t3)))); - - /* Add bits 15-8 of rs and rt. */ - assign(t6, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt)))))); - /* t7 will be 1 if there is overflow, 0 otherwise. */ - assign(t7, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0x00000100)), - mkU32(0x00000100))); - /* Saturate if necessary. */ - assign(t8, IRExpr_ITE(mkexpr(t7), - mkU8(0xff), - unop(Iop_32to8, mkexpr(t6)))); - - /* Add bits 15-8 of rs and rt. */ - assign(t9, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt)))))); - /* t10 will be 1 if there is overflow, 0 otherwise. */ - assign(t10, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t9), - mkU32(0x00000100)), - mkU32(0x00000100))); - /* Saturate if necessary. */ - assign(t11, IRExpr_ITE(mkexpr(t10), - mkU8(0xff), - unop(Iop_32to8, mkexpr(t9)))); - - assign(t12, - binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - unop(Iop_1Sto32, mkexpr(t10)), - unop(Iop_1Sto32, mkexpr(t7))), - unop(Iop_1Sto32, mkexpr(t4))), - unop(Iop_1Sto32, mkexpr(t1)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t12), - mkU32(0x0)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)))); - - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, mkexpr(t11), mkexpr(t8)), - binop(Iop_8HLto16, mkexpr(t5), mkexpr(t2)))); - break; - } - case 0x05: { /* SUBU_S.QB */ - DIP("subu_s.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - - /* Use C function to easily calculate the result - and write it in the register more conveniently - Underflow is checked using step by step subtraction. */ - assign(t1, binop(Iop_QSub8Ux4, getIReg(rs), getIReg(rt))); - - /* Subtract each byte of rs and rt. */ - assign(t6, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t7, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t8, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t9, - binop(Iop_Sub32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt)))))); - - /* Put 1 to bit 20 in DSPControl if there is underflow - in either byte. */ - assign(t2, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0x00000100)), - mkU32(0x00000100))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - assign(t3, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t7), - mkU32(0x00000100)), - mkU32(0x00000100))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - assign(t4, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t8), - mkU32(0x00000100)), - mkU32(0x00000100))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - assign(t5, binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t9), - mkU32(0x00000100)), - mkU32(0x00000100))); - putDSPControl(IRExpr_ITE(mkexpr(t5), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - putIReg(rd, mkexpr(t1)); - break; - } - case 0x6: { /* MULEU_S.PH.QBL */ - DIP("muleu_s.ph.qbl r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - - assign(t0, - unop(Iop_64to32, - binop(Iop_MullU32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t1, - unop(Iop_64to32, - binop(Iop_MullU32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt)))))); - - assign(t2, binop(Iop_CmpNE32, - mkU32(0x0), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x03ff0000)))); - assign(t3, binop(Iop_CmpNE32, - mkU32(0x0), - binop(Iop_And32, - mkexpr(t1), - mkU32(0x03ff0000)))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x200000)), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x200000)), - getDSPControl()))); - putIReg(rd, - binop(Iop_16HLto32, - IRExpr_ITE(mkexpr(t2), - mkU16(0xffff), - unop(Iop_32to16, mkexpr(t0))), - IRExpr_ITE(mkexpr(t3), - mkU16(0xffff), - unop(Iop_32to16, mkexpr(t1))))); - break; - } - case 0x7: { /* MULEU_S.PH.QBR */ - DIP("muleu_s.ph.qbr r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - - assign(t0, unop(Iop_64to32, - binop(Iop_MullU32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t1, unop(Iop_64to32, - binop(Iop_MullU32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rt)))))); - - assign(t2, binop(Iop_CmpNE32, - mkU32(0x0), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x03ff0000)))); - assign(t3, binop(Iop_CmpNE32, - mkU32(0x0), - binop(Iop_And32, - mkexpr(t1), - mkU32(0x03ff0000)))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x200000)), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x200000)), - getDSPControl()))); - putIReg(rd, binop(Iop_16HLto32, - IRExpr_ITE(mkexpr(t2), - mkU16(0xffff), - unop(Iop_32to16, - mkexpr(t0))), - IRExpr_ITE(mkexpr(t3), - mkU16(0xffff), - unop(Iop_32to16, - mkexpr(t1))))); - break; - } - case 0x08: { /* ADDU.PH */ - DIP("addu.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - - /* Add lower halves. */ - assign(t0, binop(Iop_Add32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Detect overflow. */ - assign(t1, binop(Iop_CmpLT32U, - unop(Iop_16Uto32, - unop(Iop_32to16, mkexpr(t0))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - /* Add higher halves. */ - assign(t2, binop(Iop_Add32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Detect overflow. */ - assign(t3, binop(Iop_CmpLT32U, - unop(Iop_16Uto32, - unop(Iop_32to16, mkexpr(t2))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rs))))); - - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t2)), - unop(Iop_32to16, mkexpr(t0)))); - break; - } - case 0x9: { /* SUBU.PH */ - DIP("subu.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - - /* Substract lower halves. */ - assign(t0, binop(Iop_Sub32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Detect underflow. */ - assign(t1, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00010000)), - mkU32(0x0))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - /* Subtract higher halves. */ - assign(t2, binop(Iop_Sub32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Detect underflow. */ - assign(t3, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00010000)), - mkU32(0x0))); - - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t2)), - unop(Iop_32to16, mkexpr(t0)))); - break; - } - case 0xA: { /* ADDQ.PH */ - DIP("addq.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - - /* Add lower halves. */ - assign(t0, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t6, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t0))), - mkU32(0x1))); - /* Detect overflow. */ - assign(t1, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x8000)), - mkU8(15)), - mkexpr(t6))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - /* Add higher halves. */ - assign(t2, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t7, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0x1))); - /* Detect overflow. */ - assign(t3, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00008000)), - mkU8(15)), - mkexpr(t7))); + default: + return -1; + } - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); + break; + } - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t2)), - unop(Iop_32to16, mkexpr(t0)))); - break; - } - case 0xB: { /* SUBQ.PH */ - DIP("subq.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - - /* Subtract lower halves. */ - assign(t0, binop(Iop_Sub32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t6, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t0))), - mkU32(0x1))); - /* Compare the signs of input value and the result. */ - assign(t1, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x8000)), - mkU8(15)), - mkexpr(t6))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - /* Subtract higher halves. */ - assign(t2, binop(Iop_Sub32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t7, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0x1))); - /* Compare the signs of input value and the result. */ - assign(t3, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00008000)), - mkU8(15)), - mkexpr(t7))); + 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; + } - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); + 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; + } - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t2)), - unop(Iop_32to16, mkexpr(t0)))); - break; - } - case 0xC: { /* ADDU_S.PH */ - DIP("addu_s.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - - /* Add lower halves. */ - assign(t0, binop(Iop_Add32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Detect overflow. */ - assign(t1, binop(Iop_CmpLT32U, - unop(Iop_16Uto32, - unop(Iop_32to16, mkexpr(t0))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - /* Add higher halves. */ - assign(t2, binop(Iop_Add32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Detect overflow. */ - assign(t3, binop(Iop_CmpLT32U, - unop(Iop_16Uto32, - unop(Iop_32to16, mkexpr(t2))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))))); - - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - putIReg(rd, binop(Iop_16HLto32, - IRExpr_ITE(mkexpr(t3), - mkU16(0xffff), - unop(Iop_32to16, - mkexpr(t2))), - IRExpr_ITE(mkexpr(t1), - mkU16(0xffff), - unop(Iop_32to16, - mkexpr(t0))))); - break; - } - case 0xD: { /* SUBU_S.PH */ - DIP("subu_s.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - - /* Subtract lower halves. */ - assign(t0, binop(Iop_Sub32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Detect underflow. */ - assign(t1, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), mkU32(0x00010000)), - mkU32(0x0))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - /* Subtract higher halves. */ - assign(t2, binop(Iop_Sub32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Detect underflow. */ - assign(t3, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t2), mkU32(0x00010000)), - mkU32(0x0))); - - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - putIReg(rd, - binop(Iop_16HLto32, - IRExpr_ITE(mkexpr(t3), - mkU16(0x0000), - unop(Iop_32to16, mkexpr(t2))), - IRExpr_ITE(mkexpr(t1), - mkU16(0x0000), - unop(Iop_32to16, mkexpr(t0))))); - break; - } - case 0xE: { /* ADDQ_S.PH */ - DIP("addq_s.ph r%u r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I16); - t5 = newTemp(Ity_I16); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - - /* Add lower halves. */ - assign(t0, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t6, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t0))), - mkU32(0x1))); - /* Detect overflow. */ - assign(t1, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x8000)), - mkU8(15)), - mkexpr(t6))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - /* Saturate if needed. */ - assign(t4, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t6), - mkU32(0x0)), - mkU16(0x7fff), - mkU16(0x8000)), - unop(Iop_32to16, mkexpr(t0)))); - - /* Add higher halves. */ - assign(t2, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t7, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0x1))); - /* Detect overflow. */ - assign(t3, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00008000)), - mkU8(15)), - mkexpr(t7))); - - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - /* Saturate if needed. */ - assign(t5, IRExpr_ITE(mkexpr(t3), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x0)), - mkU16(0x7fff), - mkU16(0x8000)), - unop(Iop_32to16, mkexpr(t2)))); - - putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4))); - break; - } - case 0xF: { /* SUBQ_S.PH */ - DIP("subq_s.ph r%u r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I16); - t5 = newTemp(Ity_I16); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - - /* Subtract lower halves. */ - assign(t0, binop(Iop_Sub32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t6, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t0))), - mkU32(0x1))); - /* Detect overflow or underflow. */ - assign(t1, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x8000)), - mkU8(15)), - mkexpr(t6))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - /* Saturate if needed. */ - assign(t4, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t6), - mkU32(0x0)), - mkU16(0x7fff), - mkU16(0x8000)), - unop(Iop_32to16, mkexpr(t0)))); - - /* Subtract higher halves. */ - assign(t2, binop(Iop_Sub32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Bit 16 of the result. */ - assign(t7, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0x1))); - /* Detect overflow or underflow. */ - assign(t3, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00008000)), - mkU8(15)), - mkexpr(t7))); - - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - /* Saturate if needed. */ - assign(t5, IRExpr_ITE(mkexpr(t3), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x0)), - mkU16(0x7fff), - mkU16(0x8000)), - unop(Iop_32to16, mkexpr(t2)))); - - putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4))); - break; - } - case 0x10: { /* ADDSC */ - DIP("addsc r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I1); - - /* The carry bit result out of the addition operation is - written to bit 13(the c field) of the DSPControl reg. */ - assign(t0, binop(Iop_Add64, - unop(Iop_32Uto64, getIReg(rs)), - unop(Iop_32Uto64, getIReg(rt)))); - - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t0)), - mkU32(0x1)), - mkU32(0x1))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x2000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xffffdfff)))); - - putIReg(rd, unop(Iop_64to32, mkexpr(t0))); - break; - } - case 0x11: { /* ADDWC */ - DIP("addwc r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I1); - - /* Get carry bit from DSPControl register. */ - assign(t0, binop(Iop_Shr32, - binop(Iop_And32, - getDSPControl(), - mkU32(0x2000)), - mkU8(0xd))); - assign(t1, binop(Iop_Add64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, - binop(Iop_Add32, - getIReg(rt), - mkexpr(t0))))); - - /* Extract bits 32 and 31. */ - assign(t2, binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t1)), - mkU32(0x1))); - assign(t3, binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t1)), - mkU32(0x80000000)), - mkU8(31))); - assign(t4, binop(Iop_CmpNE32, mkexpr(t2), mkexpr(t3))); - - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - putIReg(rd, unop(Iop_64to32, mkexpr(t1))); - break; - } - case 0x12: { /* MODSUB */ - DIP("modsub r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - - /* decr_7..0 */ - assign(t0, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - - /* lastindex_15..0 */ - assign(t1, - unop(Iop_16Uto32, - binop(Iop_8HLto16, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - /* temp_15..0 */ - assign(t2, - IRExpr_ITE(binop(Iop_CmpEQ32, - getIReg(rs), - mkU32(0x00000000)), - mkexpr(t1), - binop(Iop_Sub32, - getIReg(rs), mkexpr(t0)))); - putIReg(rd, mkexpr(t2)); - break; - } - case 0x14: { /* RADDU.W.QB */ - DIP("raddu.w.qb r%u, r%u", rd, rs); - vassert(!mode64); - putIReg(rd, binop(Iop_Add32, - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rs))))), - binop(Iop_Add32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs))))))); - break; - } - case 0x16: { /* ADDQ_S.W */ - DIP("addq_s.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - - assign(t0, binop(Iop_Add64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, getIReg(rt)))); - - assign(t3, binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t0)), - mkU32(0x1))); - assign(t1, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t0)), - mkU32(0x80000000)), - mkU8(31)), - mkexpr(t3))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - putIReg(rd, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t3), - mkU32(0x0)), - mkU32(0x7fffffff), - mkU32(0x80000000)), - unop(Iop_64to32, mkexpr(t0)))); - break; - } - case 0x17: { /* SUBQ_S.W */ - DIP("subq_s.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - - assign(t0, binop(Iop_Sub64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, getIReg(rt)))); - - assign(t3, binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t0)), - mkU32(0x1))); - assign(t1, binop(Iop_CmpNE32, - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t0)), - mkU32(0x80000000)), - mkU8(31)), - mkexpr(t3))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00100000)), - getDSPControl())); - - putIReg(rd, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t3), - mkU32(0x0)), - mkU32(0x7fffffff), - mkU32(0x80000000)), - unop(Iop_64to32, mkexpr(t0)))); - break; - } - case 0x1C: { /* MULEQ_S.W.PHL */ - DIP("muleq_s.w.phl r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I32); - - assign(t0, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs)))), - mkU8(0x1))); - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xffff0000)), - mkU32(0x80000000))); - assign(t2, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rs), - mkU32(0xffff0000)), - mkU32(0x80000000))); - assign(t3, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000)), - getDSPControl()), - getDSPControl())); - putDSPControl(mkexpr(t3)); - - putIReg(rd, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - mkU32(0x7fffffff), - mkexpr(t0)), - mkexpr(t0))); - break; - } - case 0x1D: { /* MULEQ_S.W.PHR */ - DIP("muleq_s.w.phr r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - - assign(t0, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs)))), - mkU8(0x1))); - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xffff)), - mkU32(0x8000))); - assign(t2, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rs), - mkU32(0xffff)), - mkU32(0x8000))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()), - getDSPControl())); - putIReg(rd, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - mkU32(0x7fffffff), - mkexpr(t0)), - mkexpr(t0))); - break; - } - case 0x1E: { /* MULQ_S.PH */ - DIP("mulq_s.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I16); - t3 = newTemp(Ity_I16); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t5, - unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rs)))); - assign(t6, - unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt)))); - - assign(t7, - unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rs)))); - assign(t8, - unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rt)))); - - assign(t0, binop(Iop_And32, - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t5), - mkU32(0xffff)), - mkU32(0x8000))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0xffff)), - mkU32(0x8000))))); - assign(t1, binop(Iop_And32, - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t7), - mkU32(0xffff)), - mkU32(0x8000))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t8), - mkU32(0xffff)), - mkU32(0x8000))))); + 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; + } - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_Or32, - mkexpr(t0), - mkexpr(t1)), - mkU32(0x0)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x200000)))); - - assign(t2, unop(Iop_32HIto16, - binop(Iop_Shl32, - unop(Iop_64to32, - binop(Iop_MullS32, - mkexpr(t7), - mkexpr(t8))), - mkU8(0x1)))); - assign(t3, unop(Iop_32HIto16, - binop(Iop_Shl32, - unop(Iop_64to32, - binop(Iop_MullS32, - mkexpr(t5), - mkexpr(t6))), - mkU8(0x1)))); - putIReg(rd, binop(Iop_16HLto32, - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t1), - mkU32(0x0)), - mkexpr(t2), - mkU16(0x7fff)), - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t0), - mkU32(0x0)), - mkexpr(t3), - mkU16(0x7fff)))); - break; - } - case 0x1F: { /* MULQ_RS.PH */ - DIP("mulq_rs.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I16); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I16); - - /* Multiply and round lower halfwords. */ - assign(t0, binop(Iop_Add32, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt))), - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rs)))), - mkU8(0x1)), - mkU32(0x00008000))); - assign(t1, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), mkU32(0xffff)), - mkU32(0x8000))); - assign(t2, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rs), mkU32(0xffff)), - mkU32(0x8000))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()), - getDSPControl())); - assign(t3, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - mkU16(0x7fff), - unop(Iop_32HIto16, - mkexpr(t0))), - unop(Iop_32HIto16, mkexpr(t0)))); - - /* Multiply and round higher halfwords. */ - assign(t4, binop(Iop_Add32, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs)))), - mkU8(0x1)), - mkU32(0x00008000))); - assign(t5, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xffff0000)), - mkU32(0x80000000))); - assign(t6, binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rs), - mkU32(0xffff0000)), - mkU32(0x80000000))); - putDSPControl(IRExpr_ITE(mkexpr(t5), - IRExpr_ITE(mkexpr(t6), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000)), - getDSPControl()), - getDSPControl())); - assign(t7, IRExpr_ITE(mkexpr(t5), - IRExpr_ITE(mkexpr(t6), - mkU16(0x7fff), - unop(Iop_32HIto16, - mkexpr(t4))), - unop(Iop_32HIto16, mkexpr(t4)))); - - putIReg(rd, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3))); - break; - } - default: - return -1; - } - break; /* end of ADDU.QB */ - } - case 0x11: { /* CMPU.EQ.QB */ - switch(sa) { - case 0x0: { /* CMPU.EQ.QB */ - DIP("cmpu.eq.qb r%u, r%u", rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); + 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; + } - assign(t1, - binop(Iop_CmpEQ32, - binop(Iop_And32, getIReg(rs), mkU32(0xff)), - binop(Iop_And32, getIReg(rt), mkU32(0xff)))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x04000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfbffffff)))); - - assign(t4, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x08000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xf7ffffff)))); - break; - } - case 0x1: { /* CMPU.LT.QB */ - DIP("cmpu.lt.qb r%u, r%u", rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - - assign(t1, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - - assign(t3, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x04000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfbffffff)))); - - assign(t4, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x08000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xf7ffffff)))); - break; - } - case 0x2: { /* CMPU.LE.QB */ - DIP("cmpu.le.qb r%u, r%u", rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - - assign(t1, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - - assign(t3, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x04000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfbffffff)))); - - assign(t4, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x08000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xf7ffffff)))); - break; - } - case 0x3: { /* PICK.QB */ - DIP("pick.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I8); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I8); + default: + return -1; + } - assign(t0, getDSPControl()); - assign(t1, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x01000000)), - mkU32(0x0)), - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rs))), - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt))))); - assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x02000000)), - mkU32(0x0)), - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt))))); - assign(t3, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x04000000)), - mkU32(0x0)), - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt))))); - assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x08000000)), - mkU32(0x0)), - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt))))); - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, mkexpr(t4), mkexpr(t3)), - binop(Iop_8HLto16, mkexpr(t2), mkexpr(t1)))); - break; - } - case 0x4: { /* CMPGU.EQ.QB */ - DIP("cmpgu.eq.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t1, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t5, IRExpr_ITE(mkexpr(t1), - mkU32(0x00000001), mkU32(0))); - - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t6, IRExpr_ITE(mkexpr(t2), - mkU32(0x00000002), mkU32(0))); - - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t7, IRExpr_ITE(mkexpr(t3), - mkU32(0x00000004), mkU32(0))); - - assign(t4, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t8, IRExpr_ITE(mkexpr(t4), - mkU32(0x00000008), mkU32(0))); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t5), mkexpr(t6)), - mkexpr(t7)), - mkexpr(t8))); - break; - } - case 0x5: { /* CMPGU.LT.QB */ - DIP("cmpgu.lt.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t1, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t5, IRExpr_ITE(mkexpr(t1), - mkU32(0x00000001), mkU32(0))); - - assign(t2, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t6, IRExpr_ITE(mkexpr(t2), - mkU32(0x00000002), mkU32(0))); - - assign(t3, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t7, IRExpr_ITE(mkexpr(t3), - mkU32(0x00000004), mkU32(0))); - - assign(t4, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t8, IRExpr_ITE(mkexpr(t4), - mkU32(0x00000008), mkU32(0))); - putIReg(rd, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t5), mkexpr(t6)), - mkexpr(t7)), - mkexpr(t8))); - break; - } - case 0x6: { /* CMPGU.LE.QB */ - DIP("cmpgu.le.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t1, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t5, IRExpr_ITE(mkexpr(t1), - mkU32(0x00000001), mkU32(0))); - - assign(t2, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t6, IRExpr_ITE(mkexpr(t2), - mkU32(0x00000002), mkU32(0))); - - assign(t3, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t7, IRExpr_ITE(mkexpr(t3), - mkU32(0x00000004), mkU32(0))); - - assign(t4, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t8, IRExpr_ITE(mkexpr(t4), - mkU32(0x00000008), mkU32(0))); - putIReg(rd, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t5), mkexpr(t6)), - mkexpr(t7)), - mkexpr(t8))); - break; - } - case 0x8: { /* CMP.EQ.PH */ - DIP("cmp.eq.ph r%u, r%u", rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - - assign(t1, binop(Iop_CmpEQ16, - unop(Iop_32to16, getIReg(rs)), - unop(Iop_32to16, getIReg(rt)))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - assign(t2, binop(Iop_CmpEQ16, - unop(Iop_32HIto16, getIReg(rs)), - unop(Iop_32HIto16, getIReg(rt)))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - break; - } - case 0x9: { /* CMP.LT.PH */ - DIP("cmp.lt.ph r%u, r%u", rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - - assign(t1, binop(Iop_CmpLT32S, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpLT32S, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - break; - } - case 0xA: { /* CMP.LE.PH */ - DIP("cmp.le.ph r%u, r%u", rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - - assign(t1, binop(Iop_CmpLE32S, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpLE32S, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - break; - } - case 0xB: { /* PICK.PH */ - DIP("pick.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I16); - t2 = newTemp(Ity_I16); + break; + } - assign(t0, getDSPControl()); + default: + return -1; + } - assign(t1, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x01000000)), - mkU32(0x0)), - unop(Iop_32to16, getIReg(rs)), - unop(Iop_32to16, getIReg(rt)))); + return 0; +} - assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x02000000)), - mkU32(0x0)), - unop(Iop_32HIto16, getIReg(rs)), - unop(Iop_32HIto16, getIReg(rt)))); +static Int msa_BIT_0A(UInt cins, UChar wd, UChar ws) /* BIT (0x0A) */ +{ + IRTemp t1, t2; + UShort operation; + UChar df, m; - putIReg(rd, binop(Iop_16HLto32, mkexpr(t2), mkexpr(t1))); - break; - } - case 0xC: { /* PRECRQ.QB.PH */ - DIP("precrq.qb.ph r%u, r%u, %u", rd, rs, rt); - vassert(!mode64); - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - binop(Iop_8HLto16, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - break; - } - case 0xD: { /* PRECR.QB.PH */ - DIP("precr.qb.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - binop(Iop_8HLto16, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - break; - } - case 0xF: { /* PRECRQU_S.QB.PH */ - DIP("precrqu_s.qb.ph r%u, r%u, %u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I8); - t1 = newTemp(Ity_I8); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I8); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I8); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I8); - t11 = newTemp(Ity_I1); - t12 = newTemp(Ity_I32); - t13 = newTemp(Ity_I8); - t14 = newTemp(Ity_I1); - t15 = newTemp(Ity_I32); - - assign(t4, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rs))), - mkU32(0x7fff))), - mkU8(0xff), - unop(Iop_16HIto8, - unop(Iop_32to16, - binop(Iop_Shl32, - getIReg(rs), - mkU8(1)))))); - assign(t0, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rs))), - mkU32(0x00008000)), - mkU32(0x0)), - mkexpr(t4), - mkU8(0x0))); - assign(t5, binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rs))), - mkU32(0x00008000))); - assign(t6, binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rs))), - mkU32(0x7fff)))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t5), - mkU32(0x0)), - IRExpr_ITE(mkexpr(t6), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000) - ), - getDSPControl()), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)))); - - assign(t7, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rs))), - mkU32(0x7fff))), - mkU8(0xff), - unop(Iop_16HIto8, - unop(Iop_32HIto16, - binop(Iop_Shl32, - getIReg(rs), - mkU8(1)))))); - assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rs))), - mkU32(0x00008000)), - mkU32(0x0)), - mkexpr(t7), - mkU8(0x0))); - assign(t8, binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rs))), - mkU32(0x00008000)), - mkU32(0x0))); - assign(t9, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rs))), - mkU32(0x7fff))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(mkexpr(t8), - mkexpr(t9), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)))); - - assign(t10, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rt))), - mkU32(0x7fff))), - mkU8(0xff), - unop(Iop_16HIto8, - unop(Iop_32to16, - binop(Iop_Shl32, - getIReg(rt), - mkU8(1)))))); - assign(t2, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rt))), - mkU32(0x00008000)), - mkU32(0x0)), - mkexpr(t10), - mkU8(0x0))); - assign(t11, binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rt))), - mkU32(0x00008000)), - mkU32(0x0))); - assign(t12, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rt))), - mkU32(0x7fff))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(mkexpr(t11), - mkexpr(t12), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)))); - - assign(t13, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rt))), - mkU32(0x7fff))), - mkU8(0xff), - unop(Iop_16HIto8, - unop(Iop_32HIto16, - binop(Iop_Shl32, - getIReg(rt), - mkU8(1)))))); - assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rt))), - mkU32(0x00008000)), - mkU32(0x0)), - mkexpr(t13), - mkU8(0x0))); - assign(t14, binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rt))), - mkU32(0x00008000)), - mkU32(0x0))); - assign(t15, IRExpr_ITE(binop(Iop_CmpLT32U, - mkU32(0x7f80), - binop(Iop_And32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rt))), - mkU32(0x7fff))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(mkexpr(t14), - mkexpr(t15), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00400000)))); - - putIReg(rd, binop(Iop_16HLto32, - binop(Iop_8HLto16, - mkexpr(t1), mkexpr(t0)), - binop(Iop_8HLto16, - mkexpr(t3), mkexpr(t2)))); - break; - } - case 0x14: { /* PRECRQ.PH.W */ - DIP("precrq.ph.w r%u, r%u, %u", rd, rs, rt); - vassert(!mode64); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32HIto16, getIReg(rs)), - unop(Iop_32HIto16, getIReg(rt)))); - break; - } - case 0x15: { /* PRECRQ_RS.PH.W */ - DIP("precrq_rs.ph.w r%u, r%u, %u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); + operation = (cins & 0x03800000) >> 23; + df = (cins & 0x007F0000) >> 16; - assign(t0, binop(Iop_Add64, - binop(Iop_32HLto64, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rs), - mkU32(0x80000000)), - mkU8(31)), - getIReg(rs)), - mkU64(0x0000000000008000ULL))); - assign(t1, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t0)), - mkU32(0x1)), - binop(Iop_And32, - binop(Iop_Shr32, - unop(Iop_64to32, mkexpr(t0)), - mkU8(31)), - mkU32(0x1)))); - assign(t2, IRExpr_ITE(mkexpr(t1), - mkU32(0x7fffffff), - unop(Iop_64to32, mkexpr(t0)))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - assign(t3, binop(Iop_Add64, - binop(Iop_32HLto64, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31)), - getIReg(rt)), - mkU64(0x0000000000008000ULL))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t3)), - mkU32(0x1)), - binop(Iop_And32, - binop(Iop_Shr32, - unop(Iop_64to32, mkexpr(t3)), - mkU8(31)), - mkU32(0x1)))); - assign(t5, IRExpr_ITE(mkexpr(t4), - mkU32(0x7fffffff), - unop(Iop_64to32, mkexpr(t3)))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32HIto16, mkexpr(t2)), - unop(Iop_32HIto16, mkexpr(t5)))); - break; - } - case 0x1E: { /* PRECR_SRA.PH.W */ - DIP("precr_sra.ph.w r%u, r%u, %u", rt, rs, rd); - vassert(!mode64); - - if (0 == rd) { - putIReg(rt, binop(Iop_16HLto32, - unop(Iop_32to16, getIReg(rt)), - unop(Iop_32to16, getIReg(rs)))); - } else { - putIReg(rt, binop(Iop_16HLto32, - unop(Iop_32to16, binop(Iop_Sar32, - getIReg(rt), - mkU8(rd))), - unop(Iop_32to16, binop(Iop_Sar32, - getIReg(rs), - mkU8(rd))))); - } - break; - } - case 0x1F: { /* PRECR_SRA_R.PH.W */ - DIP("precr_sra_r.ph.w r%u, r%u, %u", rt, rs, rd); - vassert(!mode64); + 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; + } - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); + 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 (0 == rd) { - putIReg(rt, binop(Iop_16HLto32, - unop(Iop_32to16, getIReg(rt)), - unop(Iop_32to16, getIReg(rs)))); - } else { - assign(t0, binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Sar32, - getIReg(rt), - mkU8(rd-1)), - mkU32(0x1)), - mkU8(0x1))); - assign(t1, binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Sar32, - getIReg(rs), - mkU8(rd-1)), - mkU32(0x1)), - mkU8(0x1))); - putIReg(rt, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t0)), - unop(Iop_32to16, mkexpr(t1)))); - }; - break; - } - case 0xE: { /* PACKRL.PH */ - DIP("packrl.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); + 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)))); + } - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, getIReg(rs)), - unop(Iop_32HIto16, getIReg(rt)))); - break; - } - case 0x18: { /* CMPGDU.EQ.QB */ - DIP("cmpgdu.eq.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); + break; + } - assign(t1, - binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t5, IRExpr_ITE(mkexpr(t1), - mkU32(0x00000001), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t6, IRExpr_ITE(mkexpr(t2), - mkU32(0x00000002), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t7, IRExpr_ITE(mkexpr(t3), - mkU32(0x00000004), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x04000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfbffffff)))); - - assign(t4, binop(Iop_CmpEQ32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t8, IRExpr_ITE(mkexpr(t4), - mkU32(0x00000008), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x08000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xf7ffffff)))); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t5), mkexpr(t6)), - mkexpr(t7)), - mkexpr(t8))); - break; - } - case 0x19: { /* CMPGDU.LT.QB */ - DIP("cmpgdu.lt.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t1, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t5, IRExpr_ITE(mkexpr(t1), - mkU32(0x00000001), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t6, IRExpr_ITE(mkexpr(t2), - mkU32(0x00000002), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - - assign(t3, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t7, IRExpr_ITE(mkexpr(t3), - mkU32(0x00000004), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x04000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfbffffff)))); - - assign(t4, binop(Iop_CmpLT32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t8, IRExpr_ITE(mkexpr(t4), - mkU32(0x00000008), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x08000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xf7ffffff)))); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t5), mkexpr(t6)), - mkexpr(t7)), - mkexpr(t8))); - break; - } - case 0x1A: { /* CMPGDU.LE.QB */ - DIP("cmpgdu.le.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - - assign(t1, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t5, IRExpr_ITE(mkexpr(t1), - mkU32(0x00000001), - mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x01000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfeffffff)))); - - assign(t2, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))))); - assign(t6, IRExpr_ITE(mkexpr(t2), - mkU32(0x00000002), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x02000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfdffffff)))); - - assign(t3, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t7, IRExpr_ITE(mkexpr(t3), - mkU32(0x00000004), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x04000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xfbffffff)))); - - assign(t4, binop(Iop_CmpLE32U, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))))); - assign(t8, IRExpr_ITE(mkexpr(t4), - mkU32(0x00000008), mkU32(0))); - putDSPControl(IRExpr_ITE(mkexpr(t4), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x08000000)), - binop(Iop_And32, - getDSPControl(), - mkU32(0xf7ffffff)))); - - putIReg(rd, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_Or32, - mkexpr(t5), mkexpr(t6)), - mkexpr(t7)), - mkexpr(t8))); - break; - } - default: - return -1; + 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; /* end of CMPU.EQ.QB */ - } - case 0x13: { /* SHLL.QB */ - switch(sa) { - case 0x0: { /* SHLL.QB */ - DIP("shll.qb r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I1); - t10 = newTemp(Ity_I1); - - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - /* Shift bits 7..0 and 23..16. */ - assign(t0, binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00ff00ff)), - mkU8(rs))); - assign(t1, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0xff000000)), - mkU32(0x00000000))); - assign(t2, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0xff000000)), - mkU32(0xff000000))); - assign(t7, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x0000ff00)), - mkU32(0x00000000))); - assign(t8, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x0000ff00)), - mkU32(0x000ff00))); - /* Shift bits 15..8 and 31..24. */ - assign(t3, binop(Iop_Shl32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xff00ff00)), - mkU8(8)), - mkU8(rs))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0xff000000)), - mkU32(0x00000000))); - assign(t5, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0xff000000)), - mkU32(0xff000000))); - assign(t9, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x0000ff00)), - mkU32(0x00000000))); - assign(t10, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x0000ff00)), - mkU32(0x0000ff00))); - - assign(t6, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t1)), - unop(Iop_1Uto32, - mkexpr(t2))), - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t7)), - unop(Iop_1Uto32, - mkexpr(t8)))), - binop(Iop_Or32, - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t4)), - unop(Iop_1Uto32, - mkexpr(t5))), - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t9)), - unop(Iop_1Uto32, - mkexpr(t10)))))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t6), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putIReg(rd, binop(Iop_Or32, - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x00ff00ff)), - mkU8(8)), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00ff00ff)))); - } - break; - } - case 0x3: { /* SHRL.QB */ - DIP("shrl.qb r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I8); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I8); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I8); - t9 = newTemp(Ity_I32); - - assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7))); - assign(t0, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t1, unop(Iop_32to8, - binop(Iop_Shr32, - mkexpr(t0), - unop(Iop_32to8, mkexpr(t9))))); - - assign(t2, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t3, unop(Iop_32to8, - binop(Iop_Shr32, - mkexpr(t2), - unop(Iop_32to8, mkexpr(t9))))); - assign(t4, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t5, unop(Iop_32to8, - binop(Iop_Shr32, - mkexpr(t4), - unop(Iop_32to8, mkexpr(t9))))); - - assign(t6, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t7, unop(Iop_32to8, - binop(Iop_Shr32, - mkexpr(t6), - unop(Iop_32to8, mkexpr(t9))))); - putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t9), - mkU32(0x0)), - getIReg(rt), - binop(Iop_16HLto32, - binop(Iop_8HLto16, - mkexpr(t7), - mkexpr(t5)), - binop(Iop_8HLto16, - mkexpr(t3), - mkexpr(t1))))); - break; - } - case 0x2: { /* SHLLV.QB */ - DIP("shllv.qb r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I1); - t10 = newTemp(Ity_I1); - t11 = newTemp(Ity_I8); - - assign(t11, unop(Iop_32to8, - binop(Iop_And32, - getIReg(rs), - mkU32(0x7)))); - /* Shift bits 7..0 and 23..16. */ - assign(t0, binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00ff00ff)), - mkexpr(t11))); - assign(t1, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0xff000000)), - mkU32(0x00000000))); - assign(t2, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0xff000000)), - mkU32(0xff000000))); - assign(t7, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x0000ff00)), - mkU32(0x00000000))); - assign(t8, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x0000ff00)), - mkU32(0x000ff00))); - /* Shift bits 15..8 and 31..24. */ - assign(t3, binop(Iop_Shl32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0xff00ff00)), - mkU8(8)), - mkexpr(t11))); - assign(t4, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0xff000000)), - mkU32(0x00000000))); - assign(t5, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0xff000000)), - mkU32(0xff000000))); - assign(t9, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x0000ff00)), - mkU32(0x00000000))); - assign(t10, binop(Iop_CmpNE32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0x0000ff00)), - mkU32(0x0000ff00))); + break; + } + } - assign(t6, binop(Iop_Or32, - binop(Iop_Or32, - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t1)), - unop(Iop_1Uto32, - mkexpr(t2))), - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t7)), - unop(Iop_1Uto32, - mkexpr(t8)))), - binop(Iop_Or32, - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t4)), - unop(Iop_1Uto32, - mkexpr(t5))), - binop(Iop_And32, - unop(Iop_1Uto32, - mkexpr(t9)), - unop(Iop_1Uto32, - mkexpr(t10)))))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t6), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_8Uto32, mkexpr(t11)), - mkU32(0)), - getIReg(rt), - binop(Iop_Or32, - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t3), - mkU32(0xff00ff)), - mkU8(8)), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00ff00ff))))); - break; - } - case 0x1: { /* SHRLV.QB */ - DIP("shrlv.qb r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I8); - t1 = newTemp(Ity_I8); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I8); + break; + } - assign(t0, unop(Iop_32to8, - binop(Iop_Shr32, - unop(Iop_8Uto32, - unop(Iop_32to8, getIReg(rt))), - mkU8(rs)))); - assign(t1, unop(Iop_32to8, - binop(Iop_Shr32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, - getIReg(rt)))), - mkU8(rs)))); - assign(t2, unop(Iop_32to8, - binop(Iop_Shr32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(rs)))); - assign(t3, unop(Iop_32to8, - binop(Iop_Shr32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(rs)))); - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, mkexpr(t3), mkexpr(t2)), - binop(Iop_8HLto16, mkexpr(t1), mkexpr(t0)))); - break; - } - case 0x4: { /* SHRA.QB */ - DIP("shra.qb r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - 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); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I32); - t11 = newTemp(Ity_I32); - - /* ========== GPR[rt]_31..24 ========== */ - assign(t1, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t2, - binop(Iop_Shr32, mkexpr(t1), mkU8(rs))); - /* tempD_7..0 */ - assign(t0, - binop(Iop_Or32, - mkexpr(t2), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); - - /* ========== GPR[rt]_23..16 ========== */ - assign(t4, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t5, binop(Iop_Shr32, mkexpr(t4), mkU8(rs))); - /* tempC_7..0 */ - assign(t3, - binop(Iop_Or32, - mkexpr(t5), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); - - /* ========== GPR[rt]_15..8 ========== */ - assign(t7, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t8, binop(Iop_Shr32, mkexpr(t7), mkU8(rs))); - /* tempB_7..0 */ - assign(t6, - binop(Iop_Or32, - mkexpr(t8), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t7), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); - - /* ========== GPR[rt]_7..0 ========== */ - assign(t10, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t11, binop(Iop_Shr32, mkexpr(t10), mkU8(rs))); - /* tempB_7..0 */ - assign(t9, - binop(Iop_Or32, - mkexpr(t11), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t10), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); - - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, - unop(Iop_32to8, mkexpr(t0)), - unop(Iop_32to8, mkexpr(t3))), - binop(Iop_8HLto16, - unop(Iop_32to8, mkexpr(t6)), - unop(Iop_32to8, mkexpr(t9))))); - break; - } - case 0x5: { /* SHRA_R.QB */ - DIP("shra_r.qb r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I8); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I8); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I8); - - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - assign(t0, unop(Iop_8Sto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t1, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t0), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs)))); - - assign(t2, unop(Iop_8Sto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t3, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t2), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs)))); - - assign(t4, unop(Iop_8Sto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t5, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t4), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs)))); - - assign(t6, unop(Iop_8Sto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t7, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t6), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs)))); - putIReg(rd, binop(Iop_16HLto32, - binop(Iop_8HLto16, - mkexpr(t7), mkexpr(t5)), - binop(Iop_8HLto16, - mkexpr(t3), mkexpr(t1)))); - } - break; - } - case 0x6: { /* SHRAV.QB */ - DIP("shrav.qb r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); + case 0x01: { /* SAT_U.df */ + switch (df) { + case 0x00: { /* SAT_U.B */ + DIP("SAT_U.B w%d, w%d, %d", wd, ws, m); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); + 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)))); + } - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); + break; + } - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); + case 0x01: { /* SAT_U.H */ + DIP("SAT_U.H w%d, w%d, %d", wd, ws, m); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I32); - t11 = newTemp(Ity_I32); + 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)))); + } - /* ========== GPR[rt]_31..24 ========== */ - assign(t1, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t2, - binop(Iop_Shr32, - mkexpr(t1), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))))); - /* tempD_7..0 */ - assign(t0, - binop(Iop_Or32, - mkexpr(t2), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, - mkU8(0x8), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))) - )))); - - /* ========== GPR[rt]_23..16 ========== */ - assign(t4, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t5, - binop(Iop_Shr32, - mkexpr(t4), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))))); - /* tempC_7..0 */ - assign(t3, - binop(Iop_Or32, - mkexpr(t5), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, - mkU8(0x8), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))) - )))); - - /* ========== GPR[rt]_15..8 ========== */ - assign(t7, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t8, - binop(Iop_Shr32, - mkexpr(t7), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))))); - /* tempB_7..0 */ - assign(t6, - binop(Iop_Or32, - mkexpr(t8), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t7), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, - mkU8(0x8), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))) - )))); - - /* ========== GPR[rt]_7..0 ========== */ - assign(t10, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t11, - binop(Iop_Shr32, - mkexpr(t10), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))))); - /* tempB_7..0 */ - assign(t9, - binop(Iop_Or32, - mkexpr(t11), - binop(Iop_Shl32, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t10), - mkU32(0x00000080) - ), - mkU32(0x00000080)), - mkU32(0xFFFFFFFF), - mkU32(0x00000000)), - binop(Iop_Sub8, - mkU8(0x8), - unop(Iop_32to8, binop(Iop_And32, - getIReg(rs), - mkU32(0x7))) - )))); - - putIReg(rd, - binop(Iop_16HLto32, - binop(Iop_8HLto16, - unop(Iop_32to8, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkU32(rs), - mkU32(0x7) - ), - mkU32(0x0)), - mkexpr(t1), - mkexpr(t0))), - unop(Iop_32to8, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkU32(rs), - mkU32(0x7) - ), - mkU32(0x0)), - mkexpr(t2), - mkexpr(t3)))), - binop(Iop_8HLto16, - unop(Iop_32to8, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkU32(rs), - mkU32(0x7) - ), - mkU32(0x0)), - mkexpr(t5), - mkexpr(t6))), - unop(Iop_32to8, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - mkU32(rs), - mkU32(0x7) - ), - mkU32(0x0)), - mkexpr(t8), - mkexpr(t9)))))); - break; - } - case 0x7: { /* SHRAV_R.QB */ - DIP("shrav_r.qb r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I8); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I8); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I8); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I8); - t8 = newTemp(Ity_I8); - t9 = newTemp(Ity_I32); - - assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7))); - assign(t8, unop(Iop_32to8, - binop(Iop_Sub32, mkexpr(t9), mkU32(0x1)))); - assign(t0, unop(Iop_8Sto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t1, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t0), - binop(Iop_Shl32, - mkU32(0x1), - mkexpr(t8))), - unop(Iop_32to8, - mkexpr(t9))))); - - assign(t2, unop(Iop_8Sto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t3, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t2), - binop(Iop_Shl32, - mkU32(0x1), - mkexpr(t8))), - unop(Iop_32to8, mkexpr(t9))))); - - assign(t4, unop(Iop_8Sto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t5, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t4), - binop(Iop_Shl32, - mkU32(0x1), - mkexpr(t8))), - unop(Iop_32to8, mkexpr(t9))))); - - assign(t6, unop(Iop_8Sto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t7, unop(Iop_32to8, - binop(Iop_Sar32, - binop(Iop_Add32, - mkexpr(t6), - binop(Iop_Shl32, - mkU32(0x1), - mkexpr(t8))), - unop(Iop_32to8, mkexpr(t9))))); - putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t9), - mkU32(0x0)), - getIReg(rt), - binop(Iop_16HLto32, - binop(Iop_8HLto16, - mkexpr(t7), - mkexpr(t5)), - binop(Iop_8HLto16, - mkexpr(t3), - mkexpr(t1))))); - break; - } - case 0x8: { /* SHLL.PH */ - DIP("shll.ph r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - 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); - t7 = newTemp(Ity_I32); + break; + } - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - /* Shift lower 16 bits. */ - assign(t0, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - mkU8(rs))); - - assign(t1, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t0), - mkU8(16)), - mkU32(0)))); - assign(t2, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t0), - mkU8(16)), - mkU32(0xffffffff)))); - assign(t3, binop(Iop_And32, - mkexpr(t1), - mkexpr(t2))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t3), - mkU32(0x1)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00008000)) - ), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)))); - /* Shift higher 16 bits. */ - assign(t4, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU8(rs))); - - assign(t5, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t4), - mkU8(16)), - mkU32(0)))); - assign(t6, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t4), - mkU8(16)), - mkU32(0xffffffff)))); - assign(t7, binop(Iop_And32, - mkexpr(t5), - mkexpr(t6))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x1)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x1)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x00008000)), - mkU8(16)) - ), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)))); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t4)), - unop(Iop_32to16, mkexpr(t0)))); - } - break; - } - case 0x9: { /* SHRA.PH */ - DIP("shra.ph r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - assign(t0, binop(Iop_Sar32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - mkU8(rs))); - assign(t1, binop(Iop_Sar32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU8(rs))); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t1)), - unop(Iop_32to16, mkexpr(t0)))); - } - break; - } - case 0xA: { /* SHLLV.PH */ - DIP("shllv.ph r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I32); - t11 = newTemp(Ity_I32); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); - - /* Shift lower 16 bits. */ - assign(t2, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - - assign(t3, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0x00000000))); - assign(t4, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0xffffffff))); - assign(t10, binop(Iop_And32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4)))); - assign(t5, binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - mkU8(15))); - assign(t12, binop(Iop_CmpEQ32, - mkexpr(t5), - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00008000)), - mkU8(15)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t10), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - IRExpr_ITE(mkexpr(t12), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000))) - )); - /* Shift higher 16 bits. */ - assign(t6, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - - assign(t7, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t6))), - mkU32(0x00000000))); - assign(t8, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t6))), - mkU32(0xffffffff))); - assign(t11, binop(Iop_And32, - unop(Iop_1Sto32, mkexpr(t7)), - unop(Iop_1Sto32, mkexpr(t8)))); - - assign(t9, binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31))); - assign(t13, binop(Iop_CmpEQ32, - mkexpr(t9), - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0x00008000)), - mkU8(15)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t11), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - IRExpr_ITE(mkexpr(t13), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000))) - )); - - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t6)), - unop(Iop_32to16, mkexpr(t2)))); - break; - } - case 0xB: { /* SHRAV.PH */ - DIP("shrav.ph r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); - assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); - assign(t2, binop(Iop_Sar32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - assign(t3, binop(Iop_Sar32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - putIReg(rd, - binop(Iop_16HLto32, - IRExpr_ITE(mkexpr(t1), - unop(Iop_32HIto16, getIReg(rt)), - unop(Iop_32to16, mkexpr(t3))), - IRExpr_ITE(mkexpr(t1), - unop(Iop_32to16, getIReg(rt)), - unop(Iop_32to16, mkexpr(t2))))); - break; - } - case 0xC: { /* SHLL_S.PH */ - DIP("shll_s.ph r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - 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); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I32); - t11 = newTemp(Ity_I32); - t12 = newTemp(Ity_I32); - t13 = newTemp(Ity_I32); - t14 = newTemp(Ity_I32); - - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - /* Shift lower 16 bits. */ - assign(t0, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - mkU8(rs))); - - assign(t1, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t0), - mkU8(16)), - mkU32(0)))); - assign(t2, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t0), - mkU8(16)), - mkU32(0xffffffff)))); - assign(t3, binop(Iop_And32, - mkexpr(t1), - mkexpr(t2))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t3), - mkU32(0x1)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00008000)) - ), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)))); - assign(t8, - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t3), - mkU32(0x1)), - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x8000)), - mkU32(0)), - mkU32(0x00007fff), - mkU32(0x00008000)), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x0000ffff)))); - assign(t10, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - binop(Iop_And32, - mkexpr(t0), - mkU32(0x00008000))), - mkexpr(t8), - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x8000)), - mkU32(0)), - mkU32(0x00007fff), - mkU32(0x00008000)))); - /* Shift higher 16 bits. */ - assign(t4, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU8(rs))); - - assign(t5, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t4), - mkU8(16)), - mkU32(0)))); - assign(t6, unop(Iop_1Uto32, - binop(Iop_CmpNE32, - binop(Iop_Sar32, - mkexpr(t4), - mkU8(16)), - mkU32(0xffffffff)))); - assign(t7, binop(Iop_And32, - mkexpr(t5), - mkexpr(t6))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x1)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x1)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - assign(t12, binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x8000)), - mkU8(16))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkexpr(t12)), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)))); - assign(t13, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU32(0)), - mkU32(0x7fff0000), - mkU32(0x80000000))); - assign(t9, - IRExpr_ITE(binop(Iop_CmpEQ32, - mkexpr(t7), - mkU32(0x1)), - mkexpr(t13), - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x0000ffff)), - mkU8(16)))); - assign(t14, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU32(0)), - mkU32(0x7fff0000), - mkU32(0x80000000))); - assign(t11, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - binop(Iop_Shl32, - binop(Iop_And32, - mkexpr(t4), - mkU32(0x00008000)), - mkU8(16))), - mkexpr(t9), - mkexpr(t14))); - putIReg(rd, binop(Iop_Or32, - mkexpr(t10), - mkexpr(t11))); - } - break; - } - case 0xD: { /* SHRA_R.PH */ - DIP("shra.ph r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - assign(t0, binop(Iop_Sar32, - binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt))), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs))); - assign(t1, binop(Iop_Sar32, - binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt))), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs))); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t1)), - unop(Iop_32to16, mkexpr(t0)))); - } - break; - } - case 0xE: { /* SHLLV_S.PH */ - DIP("shllv_s.ph r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I32); - t11 = newTemp(Ity_I32); - t12 = newTemp(Ity_I1); - t13 = newTemp(Ity_I1); - t14 = newTemp(Ity_I16); - t15 = newTemp(Ity_I16); - t16 = newTemp(Ity_I16); - t17 = newTemp(Ity_I16); - - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); - - /* Shift lower 16 bits. */ - assign(t2, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - - assign(t3, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0x00000000))); - assign(t4, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t2))), - mkU32(0xffffffff))); - assign(t10, binop(Iop_And32, - unop(Iop_1Sto32, mkexpr(t3)), - unop(Iop_1Sto32, mkexpr(t4)))); - assign(t5, binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x00008000)), - mkU8(15))); - assign(t12, binop(Iop_CmpEQ32, - mkexpr(t5), - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x00008000)), - mkU8(15)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t10), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - IRExpr_ITE(mkexpr(t12), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000))) - )); - assign(t14, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t5), - mkU32(0x0)), - mkU16(0x8000), - mkU16(0x7fff))); - assign(t15, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t10), - mkU32(0x0)), - mkexpr(t14), - IRExpr_ITE(mkexpr(t12), - unop(Iop_32to16, - mkexpr(t2)), - mkexpr(t14)))); - /* Shift higher 16 bits. */ - assign(t6, binop(Iop_Shl32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - - assign(t7, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t6))), - mkU32(0x00000000))); - assign(t8, binop(Iop_CmpNE32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, mkexpr(t6))), - mkU32(0xffffffff))); - assign(t11, binop(Iop_And32, - unop(Iop_1Sto32, mkexpr(t7)), - unop(Iop_1Sto32, mkexpr(t8)))); - - assign(t9, binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31))); - assign(t13, binop(Iop_CmpEQ32, - mkexpr(t9), - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t6), - mkU32(0x00008000)), - mkU8(15)))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t11), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - IRExpr_ITE(mkexpr(t13), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000))) - )); - - assign(t16, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t9), - mkU32(0x0)), - mkU16(0x8000), - mkU16(0x7fff))); - assign(t17, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t11), - mkU32(0x0)), - mkexpr(t16), - IRExpr_ITE(mkexpr(t13), - unop(Iop_32to16, - mkexpr(t6)), - mkexpr(t16)))); - - putIReg(rd, binop(Iop_16HLto32, mkexpr(t17), mkexpr(t15))); - break; - } - case 0xF: { /* SHRAV_R.PH */ - DIP("shrav_r.ph r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); - assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); - assign(t2, unop(Iop_32to8, - binop(Iop_Sub32, mkexpr(t0), mkU32(1)))); - - assign(t3, binop(Iop_Sar32, - binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - binop(Iop_Shl32, - mkU32(0x1), - mkexpr(t2))), - unop(Iop_32to8, mkexpr(t0)))); - assign(t4, binop(Iop_Sar32, - binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt))), - binop(Iop_Shl32, - mkU32(0x1), - mkexpr(t2))), - unop(Iop_32to8, mkexpr(t0)))); - - putIReg(rd, binop(Iop_16HLto32, - IRExpr_ITE(mkexpr(t1), - unop(Iop_32HIto16, - getIReg(rt)), - unop(Iop_32to16, - mkexpr(t4))), - IRExpr_ITE(mkexpr(t1), - unop(Iop_32to16, getIReg(rt)), - unop(Iop_32to16, - mkexpr(t3))))); - break; - } - case 0x14: { /* SHLL_S.W */ - DIP("shll_s.w r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); + case 0x02: { /* SAT_U.W */ + DIP("SAT_U.W w%d, w%d, %d", wd, ws, m); - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - /* t0-bits that will be discarded, sign extended to - 32bits. */ - assign(t0, binop(Iop_Sar32, - binop(Iop_And32, - getIReg(rt), - binop(Iop_Sar32, - mkU32(0x80000000), - mkU8(rs-1))), - mkU8(32-rs))); - - assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU32(0x0)), - mkU32(0x7fffffff), - mkU32(0x80000000))); - - assign(t2, binop(Iop_Shl32, getIReg(rt), mkU8(rs))); - assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - binop(Iop_And32, - mkexpr(t2), - mkU32(0x80000000))), - mkexpr(t2), - mkexpr(t1))); - - assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t0), - mkU32(0x0)), - IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t0), - mkU32(0xffffffff) - ), - mkexpr(t1), - mkexpr(t3)), - mkexpr(t3))); - assign(t5, IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t0), - mkU32(0xffffffff)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t0), - mkU32(0x0)), - mkexpr(t5), - getDSPControl())); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - binop(Iop_And32, - mkexpr(t2), - mkU32(0x80000000)) - ), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)))); - putIReg(rd, mkexpr(t4)); - } - break; - } - case 0x15: { /* SHRA_R.W */ - DIP("shra_r.w r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - if (0 == rs) { - putIReg(rd, getIReg(rt)); - } else { - putIReg(rd, binop(Iop_Add32, - binop(Iop_Sar32, - getIReg(rt), mkU8(rs)), - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(rs-1))), - mkU8(rs-1)))); - } - break; - } - case 0x16: { /* SHLLV_S.W */ - DIP("shllv_s.w r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I1); - t5 = newTemp(Ity_I1); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I32); - - /* Check if shift amount is zero. */ - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); - assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); - - /* t2 = sign of the input value. */ - assign(t2, binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31))); - /* Shift left input value and check for overflow. */ - assign(t3, binop(Iop_Shl64, - unop(Iop_32Sto64, getIReg(rt)), - unop(Iop_32to8, mkexpr(t0)))); - assign(t4, binop(Iop_CmpNE32, - unop(Iop_64HIto32, mkexpr(t3)), - mkU32(0x00000000))); - assign(t5, binop(Iop_CmpNE32, - unop(Iop_64HIto32, mkexpr(t3)), - mkU32(0xffffffff))); - assign(t6, binop(Iop_And32, - unop(Iop_1Uto32, mkexpr(t4)), - unop(Iop_1Uto32, mkexpr(t5)))); - assign(t7, binop(Iop_CmpEQ32, - binop(Iop_Shr32, - binop(Iop_And32, - getIReg(rt), - mkU32(0x80000000)), - mkU8(31)), - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t3)), - mkU32(0x80000000)), - mkU8(31)))); - - putDSPControl(IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000)), - IRExpr_ITE(mkexpr(t7), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x400000))) - )); - - assign(t8, IRExpr_ITE(unop(Iop_32to1, - mkexpr(t2)), - mkU32(0x80000000), - mkU32(0x7fffffff))); - putIReg(rd, IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)), - IRExpr_ITE(unop(Iop_32to1, - mkexpr(t2)), - mkU32(0x80000000), - mkU32(0x7fffffff)), - IRExpr_ITE(mkexpr(t7), - unop(Iop_64to32, - mkexpr(t3)), - mkexpr(t8)))); - break; - } - case 0x17: { /* SHRAV_R.W */ - DIP("shrav_r.w r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I32); - - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); - assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); - assign(t2, unop(Iop_32to8, - binop(Iop_Sub32, mkexpr(t0), mkU32(1)))); - - putIReg(rd, IRExpr_ITE(mkexpr(t1), - getIReg(rt), - binop(Iop_Sar32, - binop(Iop_Add32, - binop(Iop_Sar32, - getIReg(rt), - mkexpr(t2)), - mkU32(0x1)), - mkU8(1)))); - break; - } - case 0x19: { /* SHRL.PH */ - DIP("shrl.ph r%u, r%u, %u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - assign(t0, binop(Iop_Shr32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU8(rs))); - assign(t1, binop(Iop_Shr32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU8(rs))); - putIReg(rd, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t1)), - unop(Iop_32to16, mkexpr(t0)))); - break; - } - case 0x1B: { /* SHRLV.PH */ - DIP("shrlv.ph r%u, r%u, r%u", rd, rt, rs); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I16); - t5 = newTemp(Ity_I16); - - /* Get shift amount from lower 5 bits of rs - and check if it is zero. */ - assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); - assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); - - assign(t2, binop(Iop_Shr32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - assign(t3, binop(Iop_Shr32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_32to8, mkexpr(t0)))); - - assign(t4, IRExpr_ITE(mkexpr(t1), - unop(Iop_32HIto16, getIReg(rt)), - unop(Iop_32to16, mkexpr(t3)))); - assign(t5, IRExpr_ITE(mkexpr(t1), - unop(Iop_32to16, getIReg(rt)), - unop(Iop_32to16, mkexpr(t2)))); - putIReg(rd, binop(Iop_16HLto32, mkexpr(t4), mkexpr(t5))); - break; - } - default: - return -1; + 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; /* end of SHLL.QB */ + + break; } - case 0x18: { /* ADDUH.QB/MUL.PH */ - switch(sa) { - case 0x00: { /* ADDUH.QB */ - DIP("adduh.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - assign(t0, binop(Iop_HAdd8Ux4, getIReg(rs), getIReg(rt))); + case 0x03: { /* SAT_U.D */ + DIP("SAT_U.D w%d, w%d, %d", wd, ws, m); - putIReg(rd, mkexpr(t0)); - break; - } - case 0x1: { /* SUBUH.QB */ - DIP("subuh.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); + 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)))); + } - assign(t0, binop(Iop_HSub8Ux4, getIReg(rs), getIReg(rt))); + break; + } + } - putIReg(rd, mkexpr(t0)); - break; - } - case 0x02: { /* ADDUH_R.QB */ - DIP("adduh_r.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I8); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I8); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I8); - t9 = newTemp(Ity_I32); - t10 = newTemp(Ity_I32); - t11 = newTemp(Ity_I8); - - /* Extract input bytes, add values, add 1 and half the - result. */ - assign(t0, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs))))); - assign(t1, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t2, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Add32, - mkexpr(t0), - mkexpr(t1)), - mkU32(0x00000001)), - mkU8(0x01))))); - - assign(t3, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs))))); - assign(t4, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t5, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Add32, - mkexpr(t3), - mkexpr(t4)), - mkU32(0x00000001)), - mkU8(0x01))))); - - assign(t6, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs))))); - assign(t7, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t8, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Add32, - mkexpr(t7), - mkexpr(t6)), - mkU32(0x00000001)), - mkU8(0x01))))); - - assign(t9, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs))))); - assign(t10, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t11, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Add32, - mkexpr(t9), - mkexpr(t10)), - mkU32(0x00000001)), - mkU8(0x01))))); - - putIReg(rd, binop(Iop_16HLto32, - binop(Iop_8HLto16, - mkexpr(t11), mkexpr(t8)), - binop(Iop_8HLto16, - mkexpr(t5), mkexpr(t2)))); - break; - } - case 0x3: { /* SUBUH_R.QB */ - DIP("subuh_r.qb r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); - t6 = newTemp(Ity_I32); - t7 = newTemp(Ity_I32); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I8); - t10 = newTemp(Ity_I8); - t11 = newTemp(Ity_I8); - t12 = newTemp(Ity_I8); - - /* Extract each byte of rs and rt. */ - assign(t1, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs))))); - assign(t2, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs))))); - assign(t3, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs))))); - assign(t4, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs))))); + break; + } - assign(t5, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt))))); - assign(t6, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt))))); - assign(t7, unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t8, unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt))))); - - /* Add 1 to each resulting byte and half the results. */ - assign(t9, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Sub32, - mkexpr(t1), - mkexpr(t5)), - mkU32(0x00000001)), - mkU8(0x01))))); - assign(t10, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Sub32, - mkexpr(t2), - mkexpr(t6)), - mkU32(0x00000001)), - mkU8(0x01))))); - assign(t11, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Sub32, - mkexpr(t3), - mkexpr(t7)), - mkU32(0x00000001)), - mkU8(0x01))))); - assign(t12, unop(Iop_16to8, - unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_Add32, - binop(Iop_Sub32, - mkexpr(t4), - mkexpr(t8)), - mkU32(0x00000001)), - mkU8(0x01))))); - - putIReg(rd, binop(Iop_16HLto32, - binop(Iop_8HLto16, - mkexpr(t12), mkexpr(t11)), - binop(Iop_8HLto16, - mkexpr(t10), mkexpr(t9)))); - break; - } - case 0x8: { /* ADDQH.PH */ - DIP("addqh.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I16); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I16); - - /* Add lower halfs of rs and rt - and right shift the result by 1. */ - assign(t0, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - assign(t1, unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0x0001fffe)), - mkU8(0x1)))); - /* Add higher halfs of rs and rt - and right shift the result by 1. */ - assign(t2, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t3, unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_And32, - mkexpr(t2), - mkU32(0x0001fffe)), - mkU8(0x1)))); - putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); - break; - } - case 0x9: { /* SUBQH.PH */ - DIP("subqh.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); + 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))); - putIReg(rd, binop(Iop_HSub16Sx2, - getIReg(rs), getIReg(rt))); - break; - } - case 0xA: {/* ADDQH_R.PH */ - DIP("addqh_r.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I16); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I16); - - /* Add lower halfs of rs and rt, add 1 - and right shift the result by 1. */ - assign(t0, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - assign(t1, unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_And32, - binop(Iop_Add32, - mkexpr(t0), - mkU32(0x1)), - mkU32(0x0001fffe)), - mkU8(0x1)))); - /* Add higher halfs of rs and rt, add 1 - and right shift the result by 1. */ - assign(t2, binop(Iop_Add32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t3, unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_And32, - binop(Iop_Add32, - mkexpr(t2), - mkU32(0x1)), - mkU32(0x0001fffe)), - mkU8(0x1)))); + if (m) putWReg(wd, binop(Iop_Add8x16, + mkexpr(t1), + mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); - putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); - break; - } - case 0xB: { /* SUBQH_R.PH */ - DIP("subqh_r.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I16); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I16); - - /* Sub lower halfs of rs and rt, add 1 - and right shift the result by 1. */ - assign(t0, binop(Iop_Sub32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - assign(t1, unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_And32, - binop(Iop_Add32, - mkexpr(t0), - mkU32(0x1)), - mkU32(0x0001fffe)), - mkU8(0x1)))); - /* Sub higher halfs of rs and rt, add 1 - and right shift the result by 1. */ - assign(t2, binop(Iop_Sub32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - assign(t3, unop(Iop_32to16, - binop(Iop_Shr32, - binop(Iop_And32, - binop(Iop_Add32, - mkexpr(t2), - mkU32(0x1)), - mkU32(0x0001fffe)), - mkU8(0x1)))); + break; + } - putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); - break; - } - case 0xC: { /* MUL.PH */ - DIP("mul.ph r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - - assign(t0, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); - /* DSP Control flag. */ - putDSPControl(IRExpr_ITE(unop(Iop_Not1, - binop(Iop_CmpLE32S, - mkexpr(t0), - mkU32(0x7FFF))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000)), - IRExpr_ITE(binop(Iop_CmpLT32S, - mkexpr(t0), - mkU32(0xFFFF8000) - ), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()))); + 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))); - assign(t1, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - /* DSP Control flag. */ - putDSPControl(IRExpr_ITE(unop(Iop_Not1, - binop(Iop_CmpLE32S, - mkexpr(t1), - mkU32(0x7FFF))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000)), - IRExpr_ITE(binop(Iop_CmpLT32S, - mkexpr(t1), - mkU32(0xFFFF8000) - ), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()))); - - assign(t2, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t0)), - unop(Iop_32to16, mkexpr(t1)))); - putIReg(rd, mkexpr(t2)); - break; - } - case 0xE: { /* MUL_S.PH */ - DIP("mul_s.ph r%u r%u, r%u", rd, rs, rt); - vassert(!mode64); - - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - t4 = newTemp(Ity_I32); - - /* t0 - signed intermediate result. */ - assign(t0, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))))); + if (m) + putWReg(wd, + binop(Iop_Add16x8, + mkexpr(t1), mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); - assign(t1, - IRExpr_ITE(unop(Iop_Not1, - binop(Iop_CmpLE32S, - mkexpr(t0), - mkU32(0x7FFF))), - mkU32(0x00007FFF), - IRExpr_ITE(binop(Iop_CmpLT32S, - mkexpr(t0), - mkU32(0xFFFF8000)), - mkU32(0xFFFF8000), - mkexpr(t0)))); - - /* DSP Control flag. */ - putDSPControl(IRExpr_ITE(unop(Iop_Not1, - binop(Iop_CmpLE32S, - mkexpr(t0), - mkU32(0x7FFF))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000)), - IRExpr_ITE(binop(Iop_CmpLT32S, - mkexpr(t0), - mkU32(0xFFFF8000) - ), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()))); - - /* t2 - signed intermediate result. */ - assign(t2, binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))))); - - assign(t3, IRExpr_ITE(unop(Iop_Not1, - binop(Iop_CmpLE32S, - mkexpr(t2), - mkU32(0x7FFF))), - mkU32(0x00007FFF), - IRExpr_ITE(binop(Iop_CmpLT32S, - mkexpr(t2), - mkU32(0xFFFF8000)), - mkU32(0xFFFF8000), - mkexpr(t2)))); - - /* DSP Control flag. */ - putDSPControl(IRExpr_ITE(unop(Iop_Not1, - binop(Iop_CmpLE32S, - mkexpr(t2), - mkU32(0x7FFF))), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000)), - IRExpr_ITE(binop(Iop_CmpLT32S, - mkexpr(t2), - mkU32(0xFFFF8000) - ), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()))); - - assign(t4, binop(Iop_16HLto32, - unop(Iop_32to16, mkexpr(t1)), - unop(Iop_32to16, mkexpr(t3)))); - putIReg(rd, mkexpr(t4)); - break; - } - case 0x10: { /* ADDQH.W */ - DIP("addqh.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); + break; + } - assign(t0, binop(Iop_Add64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, getIReg(rt)))); - assign(t1, binop(Iop_And64, - mkexpr(t0), - mkU64(0x00000001fffffffeULL))); - putIReg(rd, unop(Iop_64to32, - binop(Iop_Shr64, mkexpr(t1), mkU8(0x1)))); - break; - } - case 0x11: { /* SUBQH.W */ - DIP("subqh.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); + 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))); - assign(t0, binop(Iop_Sub64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, getIReg(rt)))); - assign(t1, binop(Iop_And64, - mkexpr(t0), - mkU64(0x00000001fffffffeULL))); - putIReg(rd, unop(Iop_64to32, - binop(Iop_Shr64, mkexpr(t1), mkU8(0x1)))); - break; - } - case 0x12: { /* ADDQH_R.W */ - DIP("addqh_r.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - - assign(t0, binop(Iop_Add64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, getIReg(rt)))); - assign(t1, binop(Iop_Add64, - mkexpr(t0), - mkU64(0x0000000000000001ULL))); - assign(t2, binop(Iop_And64, - mkexpr(t1), - mkU64(0x00000001fffffffeULL))); - putIReg(rd, unop(Iop_64to32, - binop(Iop_Shr64, mkexpr(t2), mkU8(0x1)))); - break; - } - case 0x13: { /* SUBQH_R.W */ - DIP("subqh_r.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - - assign(t0, binop(Iop_Sub64, - unop(Iop_32Sto64, getIReg(rs)), - unop(Iop_32Sto64, getIReg(rt)))); - assign(t1, binop(Iop_Add64, - mkexpr(t0), - mkU64(0x0000000000000001ULL))); - assign(t2, binop(Iop_And64, - mkexpr(t1), - mkU64(0x00000001fffffffeULL))); - putIReg(rd, unop(Iop_64to32, - binop(Iop_Shr64, mkexpr(t2), mkU8(0x1)))); - break; - } - case 0x16: { /* MULQ_S.W */ - DIP("mulq_s.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - - assign(t0, binop(Iop_Shl64, - binop(Iop_MullS32, - getIReg(rt), getIReg(rs)), - mkU8(0x1))); - assign(t1, binop(Iop_CmpEQ32, - getIReg(rt), mkU32(0x80000000))); - assign(t2, binop(Iop_CmpEQ32, - getIReg(rs), mkU32(0x80000000))); - - putDSPControl(IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()), - getDSPControl())); - putIReg(rd, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - mkU32(0x7fffffff), - unop(Iop_64HIto32, - mkexpr(t0))), - unop(Iop_64HIto32, mkexpr(t0)))); - break; - } - case 0x17: { /* MULQ_RS.W */ - DIP("mulq_rs.w r%u, r%u, r%u", rd, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I1); - t2 = newTemp(Ity_I1); - - assign(t0, binop(Iop_Add64, - binop(Iop_Shl64, - binop(Iop_MullS32, - getIReg(rt), - getIReg(rs)), - mkU8(0x1)), - mkU64(0x0000000080000000ULL))); - assign(t1, - binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000))); - assign(t2, - binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x80000000))); - putDSPControl(IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - binop(Iop_Or32, - getDSPControl(), - mkU32(0x00200000) - ), - getDSPControl()), - getDSPControl())); - putIReg(rd, IRExpr_ITE(mkexpr(t1), - IRExpr_ITE(mkexpr(t2), - mkU32(0x7fffffff), - unop(Iop_64HIto32, - mkexpr(t0))), - unop(Iop_64HIto32, mkexpr(t0)))); - break; - } - default: - return -1; - } - break; /* end of ADDUH.QB/MUL.PH */ + if (m) + putWReg(wd, + binop(Iop_Add32x4, + mkexpr(t1), mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); + + break; } - case 0x30: { /* DPAQ.W.PH */ - switch(sa) { - case 0x0: { /* DPA.W.PH */ - DIP("dpa.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - - assign(t0, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t1, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))))); - assign(t2, - binop(Iop_Add64, - getAcc(ac), - binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); - putAcc(ac, mkexpr(t2)); - break; - } - case 0x1: { /* DPS.W.PH */ - DIP("dps.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); + 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))); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - - assign(t0, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t1, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))))); - assign(t2, - binop(Iop_Sub64, - getAcc(ac), - binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); - putAcc(ac, mkexpr(t2)); - break; - } - case 0x2: { /* MULSA.W.PH */ - DIP("mulsa.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - - assign(t4, getAcc(ac)); - assign(t0, binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))))); - assign(t1, binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))))); - assign(t2, binop(Iop_Sub32, mkexpr(t1), mkexpr(t0))); - putAcc(ac, binop(Iop_Add64, - mkexpr(t4), - unop(Iop_32Sto64, mkexpr(t2)))); - break; - } - case 0x3: { /* DPAU.H.QBL */ - DIP("dpau.h.qbl ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - - assign(t0, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t1, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t2, - unop(Iop_32Uto64, - binop(Iop_Add32, - mkexpr(t0), - mkexpr(t1)))); - assign(t3, - binop(Iop_Add64, getAcc(ac), mkexpr(t2))); - putAcc(ac, mkexpr(t3)); - break; - } - case 0x4: { /* DPAQ_S.W.PH */ - DIP("dpaq_s.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - - assign(t1, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1))); - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x000000007fffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t5, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt))) - ), - mkU8(0x1))); - assign(t6, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t7, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - assign(t8, - IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - mkU64(0x000000007fffffffULL), - mkexpr(t5)), - mkexpr(t5))); - - putDSPControl(IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t9, binop(Iop_Add64, - binop(Iop_Add64, mkexpr(t4), mkexpr(t8)), - mkexpr(t0))); - putAcc(ac, mkexpr(t9)); - break; - } - case 0x5: { /* DPSQ_S.W.PH */ - DIP("dpsq_s.w.ph ac%u r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - - assign(t1, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1))); - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x000000007fffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t5, - binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))), - mkU8(0x1))); - assign(t6, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t7, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - assign(t8, - IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - mkU64(0x000000007fffffffULL), - mkexpr(t5)), - mkexpr(t5))); - - putDSPControl(IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t9, - binop(Iop_Sub64, - mkexpr(t0), - binop(Iop_Add64, mkexpr(t4), mkexpr(t8)))); - putAcc(ac, mkexpr(t9)); - break; - } - case 0x6: { /* MULSAQ_S.W.PH */ - DIP("mulsaq_s.w.ph ac%u r%u, r%u", ac, rs, rt); - vassert(!mode64); - - 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_I64); - t7 = newTemp(Ity_I64); - t8 = newTemp(Ity_I32); - t9 = newTemp(Ity_I32); - - assign(t0, unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs)))); - assign(t1, unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt)))); - - assign(t8, binop(Iop_And32, - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rs))), - mkU32(0x8000))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, - getIReg(rt))), - mkU32(0x8000))))); - /* DSPControl_outflag:16+acc <- 1 */ - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t8), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x00010000), - mkU8(ac))), - getDSPControl())); - - /* tempB_31..0 */ - assign(t2, - IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t8), mkU32(0x0)), - mkU32(0x7FFFFFFF), - binop(Iop_Shl32, - binop(Iop_Mul32, - mkexpr(t0), mkexpr(t1)), - mkU8(1)))); - - assign(t3, unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs)))); - assign(t4, unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))); - - assign(t9, binop(Iop_And32, - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rs))), - mkU32(0x8000))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, - getIReg(rt))), - mkU32(0x8000))))); - /* DSPControl_outflag:16+acc <- 1 */ - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t9), - mkU32(0x0)), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x00010000), - mkU8(ac))), - getDSPControl())); - /* tempA_31..0 */ - assign(t5, - IRExpr_ITE(binop(Iop_CmpNE32, - mkexpr(t9), - mkU32(0x0)), - mkU32(0x7FFFFFFF), - binop(Iop_Shl32, - binop(Iop_Mul32, - mkexpr(t3), - mkexpr(t4)), - mkU8(1)))); - /* dotp_63..0 */ - assign(t6, - binop(Iop_Sub64, - unop(Iop_32Sto64, mkexpr(t2)), - unop(Iop_32Sto64, mkexpr(t5)))); - /* tempC_63..0 */ - assign(t7, binop(Iop_Add64, getAcc(ac), mkexpr(t6))); - - putAcc(ac, mkexpr(t7)); - break; - } - case 0x7: { /* DPAU.H.QBR */ - DIP("dpau.h.qbr ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - - assign(t0, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t1, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t2, unop(Iop_32Uto64, - binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); - assign(t3, binop(Iop_Add64, getAcc(ac), mkexpr(t2))); - putAcc(ac, mkexpr(t3)); - break; - } - case 0x8: { /* DPAX.W.PH */ - DIP("dpax.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - - assign(t0, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))))); - assign(t1, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t2, - binop(Iop_Add64, - getAcc(ac), - binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); - putAcc(ac, mkexpr(t2)); - break; - } - case 0x9: { /* DPSX.W.PH */ - DIP("dpsx.w.ph ac%u r%u, r%u", ac, rs, rt); - vassert(!mode64); + if (m) + putWReg(wd, + binop(Iop_Add64x2, + mkexpr(t1), mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - - assign(t0, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))))); - assign(t1, - unop(Iop_32Sto64, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t2, - binop(Iop_Sub64, - getAcc(ac), - binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); - putAcc(ac, mkexpr(t2)); - break; - } - case 0xB: { /* DPSU.H.QBL */ - DIP("dpsu.h.qbl ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - - assign(t0, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t1, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32HIto16, getIReg(rt)))))); - assign(t2, - unop(Iop_32Uto64, - binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); - assign(t3, - binop(Iop_Sub64, getAcc(ac), mkexpr(t2))); - putAcc(ac, mkexpr(t3)); - break; - } - case 0xC: { /* DPAQ_SA.L.W */ - DIP("dpaq_sa.l.w ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I64); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I1); - - assign(t0, getAcc(ac)); - - assign(t1, binop(Iop_Shl64, - binop(Iop_MullS32, - getIReg(rs), getIReg(rt)), - mkU8(0x1))); - - assign(t2, binop(Iop_CmpEQ32, - getIReg(rs), - mkU32(0x80000000))); - assign(t3, binop(Iop_CmpEQ32, - getIReg(rt), - mkU32(0x80000000))); - - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x7fffffffffffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t5, binop(Iop_Add64, - unop(Iop_32Uto64, - unop(Iop_64to32, mkexpr(t0))), - unop(Iop_32Uto64, - unop(Iop_64to32, mkexpr(t4))))); - assign(t6, - binop(Iop_Add64, - binop(Iop_Add64, - unop(Iop_32Sto64, - unop(Iop_64HIto32, mkexpr(t0))), - unop(Iop_32Sto64, - unop(Iop_64HIto32, mkexpr(t4)))), - unop(Iop_32Uto64, - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t5)), - mkU32(0x1))))); - assign(t7, binop(Iop_32HLto64, - unop(Iop_64to32, mkexpr(t6)), - unop(Iop_64to32, mkexpr(t5)))); - assign(t8, binop(Iop_CmpEQ32, - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t6)), - mkU32(0x80000000)), - mkU8(31)), - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t6)), - mkU32(0x00000001)))); - assign(t9, binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t6)), - mkU32(0x00000001)), - mkU32(0x1))); - putDSPControl(IRExpr_ITE(mkexpr(t8), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - putAcc(ac, - IRExpr_ITE(mkexpr(t8), - mkexpr(t7), - IRExpr_ITE(mkexpr(t9), - mkU64(0x8000000000000000ULL), - mkU64(0x7fffffffffffffffULL))) - ); - break; - } - case 0xD: { /* DPSQ_SA.L.W */ - DIP("dpsq_sa.l.w ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I64); - t7 = newTemp(Ity_I64); - t8 = newTemp(Ity_I1); - t9 = newTemp(Ity_I1); - - assign(t0, getAcc(ac)); - - assign(t1, binop(Iop_Shl64, - binop(Iop_MullS32, - getIReg(rs), getIReg(rt)), - mkU8(0x1))); - - assign(t2, binop(Iop_CmpEQ32, - getIReg(rs), - mkU32(0x80000000))); - assign(t3, binop(Iop_CmpEQ32, - getIReg(rt), - mkU32(0x80000000))); - - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x7fffffffffffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t5, binop(Iop_Sub64, - unop(Iop_32Uto64, - unop(Iop_64to32, mkexpr(t0))), - unop(Iop_32Uto64, - unop(Iop_64to32, mkexpr(t4))))); - assign(t6, binop(Iop_Sub64, - binop(Iop_Add64, - unop(Iop_32Sto64, - unop(Iop_64HIto32, mkexpr(t0)) - ), - unop(Iop_32Sto64, - unop(Iop_1Sto32, - binop(Iop_CmpLT32U, - unop(Iop_64to32, - mkexpr(t0)), - unop(Iop_64to32, - mkexpr(t4)))))), - unop(Iop_32Sto64, - unop(Iop_64HIto32, mkexpr(t4))))); - assign(t7, binop(Iop_32HLto64, - unop(Iop_64to32, mkexpr(t6)), - unop(Iop_64to32, mkexpr(t5)))); - assign(t8, binop(Iop_CmpEQ32, - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t6)), - mkU32(0x80000000)), - mkU8(31)), - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t6)), - mkU32(0x00000001)))); - assign(t9, binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t6)), - mkU32(0x00000001)), - mkU32(0x1))); - putDSPControl(IRExpr_ITE(mkexpr(t8), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - putAcc(ac, - IRExpr_ITE(mkexpr(t8), - mkexpr(t7), - IRExpr_ITE(mkexpr(t9), - mkU64(0x8000000000000000ULL), - mkU64(0x7fffffffffffffffULL))) - ); - break; - } - case 0xF: { /* DPSU.H.QBR */ - DIP("dpsu.h.qbr ac%u r%u, r%u", ac, rs, rt); - vassert(!mode64); - - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - - assign(t0, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16HIto8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t1, - binop(Iop_Mul32, - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rs)))), - unop(Iop_8Uto32, - unop(Iop_16to8, - unop(Iop_32to16, getIReg(rt)))))); - assign(t2, unop(Iop_32Uto64, - binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); - assign(t3, binop(Iop_Sub64, getAcc(ac), mkexpr(t2))); - putAcc(ac, mkexpr(t3)); + break; + } + } - break; - } - case 0x10: { /* MAQ_SA.W.PHL */ - DIP("maq_sa.w.phl ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - assign(t1, unop(Iop_32Sto64, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1)))); - - /* If both input arguments are equal 0x8000, saturate - intermediate product and write to DSPControl register. - */ - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x000000007fffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - /* Add intermediate product and value in the - accumulator. */ - assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4))); - - /* Compare bits 31 and 32 of the value in t5. */ - assign(t6, binop(Iop_CmpEQ32, - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t5)), - mkU32(0x80000000)), - mkU8(31)), - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t5)), - mkU32(1)))); - putDSPControl(IRExpr_ITE(mkexpr(t6), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - assign(t7, - IRExpr_ITE(mkexpr(t6), - mkexpr(t5), - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t5)), - mkU32(1)), - mkU32(0x0)), - mkU64(0x000000007fffffffULL), - mkU64(0xffffffff80000000ULL))) - ); - putAcc(ac, mkexpr(t7)); - break; - } - case 0x12: { /* MAQ_SA.W.PHR */ - DIP("maq_sa.w.phr ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - assign(t1, unop(Iop_32Sto64, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt)))), - mkU8(0x1)))); - - /* If both input arguments are equal 0x8000, saturate - intermediate product and write to DSPControl - register. */ - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x000000007fffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - /* Add intermediate product and value in the - accumulator. */ - assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4))); - - /* Compare bits 31 and 32 of the value in t5. */ - assign(t6, binop(Iop_CmpEQ32, - binop(Iop_Shr32, - binop(Iop_And32, - unop(Iop_64to32, mkexpr(t5)), - mkU32(0x80000000)), - mkU8(31)), - binop(Iop_And32, - unop(Iop_64HIto32, mkexpr(t5)), - mkU32(1)))); - putDSPControl(IRExpr_ITE(mkexpr(t6), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - assign(t7, - IRExpr_ITE(mkexpr(t6), - mkexpr(t5), - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t5)), - mkU32(1)), - mkU32(0x0)), - mkU64(0x000000007fffffffULL), - mkU64(0xffffffff80000000ULL))) - ); - putAcc(ac, mkexpr(t7)); - break; - } - case 0x14: { /* MAQ_S.W.PHL */ - DIP("maq_s.w.phl ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I64); - - assign(t5, getAcc(ac)); - - assign(t0, unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rs)))); - assign(t1, unop(Iop_16Sto32, - unop(Iop_32HIto16, getIReg(rt)))); - - assign(t2, binop(Iop_And32, - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0xffff)), - mkU32(0x8000))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0xffff)), - mkU32(0x8000))))); + break; + } - assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0))); + 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))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); + if (m) + putWReg(wd, + binop(Iop_Add8x16, + mkexpr(t1), mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); - assign(t4, unop(Iop_64to32, - binop(Iop_MullS32, - mkexpr(t0), mkexpr(t1)))); - putAcc(ac, IRExpr_ITE(mkexpr(t3), - binop(Iop_Add64, - unop(Iop_32Sto64, - binop(Iop_Shl32, - mkexpr(t4), - mkU8(0x1))), - mkexpr(t5)), - binop(Iop_Add64, - mkexpr(t5), - unop(Iop_32Sto64, - mkU32(0x7fffffff))))); - break; - } - case 0x16: { /* MAQ_S.W.PHR */ - DIP("maq_s.w.phr ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I32); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I64); - - assign(t5, getAcc(ac)); - - assign(t0, unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rs)))); - assign(t1, unop(Iop_16Sto32, - unop(Iop_32to16, getIReg(rt)))); - - assign(t2, binop(Iop_And32, - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t0), - mkU32(0xffff)), - mkU32(0x8000))), - unop(Iop_1Sto32, - binop(Iop_CmpEQ32, - binop(Iop_And32, - mkexpr(t1), - mkU32(0xffff)), - mkU32(0x8000))))); + break; + } - assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0))); + 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))); - putDSPControl(IRExpr_ITE(mkexpr(t3), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); + if (m) + putWReg(wd, + binop(Iop_Add16x8, + mkexpr(t1), mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); - assign(t4, unop(Iop_64to32, - binop(Iop_MullS32, - mkexpr(t0), mkexpr(t1)))); - putAcc(ac, IRExpr_ITE(mkexpr(t3), - binop(Iop_Add64, - unop(Iop_32Sto64, - binop(Iop_Shl32, - mkexpr(t4), - mkU8(0x1))), - mkexpr(t5)), - binop(Iop_Add64, - mkexpr(t5), - unop(Iop_32Sto64, - mkU32(0x7fffffff))))); - break; - } - case 0x18: { /* DPAQX_S.W.PH */ - DIP("dpaqx_s.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - - assign(t1, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt)))), - mkU8(0x1))); - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x000000007fffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))), - getDSPControl()), - getDSPControl())); - - assign(t5, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1))); - assign(t6, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t7, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - assign(t8, - IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - mkU64(0x000000007fffffffULL), - mkexpr(t5)), - mkexpr(t5))); - - putDSPControl(IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t9, binop(Iop_Add64, - binop(Iop_Add64, mkexpr(t4), mkexpr(t8)), - mkexpr(t0))); - putAcc(ac, mkexpr(t9)); - break; - } - case 0x19: { /* DPSQX_S.W.PH */ - DIP("dpsqx_s.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - - assign(t0, getAcc(ac)); - - assign(t1, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt)))), - mkU8(0x1))); - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - assign(t4, - IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - mkU64(0x000000007fffffffULL), - mkexpr(t1)), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(mkexpr(t2), - IRExpr_ITE(mkexpr(t3), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t5, binop(Iop_Shl64, - binop(Iop_MullS32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1))); - assign(t6, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t7, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - assign(t8, - IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - mkU64(0x000000007fffffffULL), - mkexpr(t5)), - mkexpr(t5))); - - putDSPControl(IRExpr_ITE(mkexpr(t6), - IRExpr_ITE(mkexpr(t7), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16) - ) - ), - getDSPControl()), - getDSPControl())); - - assign(t9, binop(Iop_Sub64, - mkexpr(t0), - binop(Iop_Add64, mkexpr(t4), mkexpr(t8)))); - putAcc(ac, mkexpr(t9)); - break; - } - case 0x1A: { /* DPAQX_SA.W.PH */ - DIP("dpaqx_sa.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I32); - - assign(t0, getAcc(ac)); - /* Calculate the first cross dot product and saturate if - needed. */ - assign(t1, unop(Iop_32Sto64, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt)))), - mkU8(0x1)))); - - /* If both input arguments are equal 0x8000, saturate - intermediate product and write to DSPControl - register. */ - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - - assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t2)), - unop(Iop_1Sto32, - mkexpr(t3))), - mkU32(0)), - mkU64(0x000000007fffffffULL), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t2)), - unop(Iop_1Sto32, - mkexpr(t3))), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))), - getDSPControl())); - /* Calculate second cross dot product and saturate if - needed. */ - assign(t5, unop(Iop_32Sto64, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1)))); - - /* If both input arguments are equal 0x8000, saturate - intermediate product and write to DSPControl - register. */ - assign(t6, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t7, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - - assign(t8, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t6)), - unop(Iop_1Sto32, - mkexpr(t7))), - mkU32(0)), - mkU64(0x000000007fffffffULL), - mkexpr(t5))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t6)), - unop(Iop_1Sto32, - mkexpr(t7))), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))), - getDSPControl())); - /* Subtract intermediate products from value in the - accumulator. */ - assign(t9, - binop(Iop_Add64, - mkexpr(t0), - binop(Iop_Add64, mkexpr(t8), mkexpr(t4)))); - - putAcc(ac, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x0)), - IRExpr_ITE(binop(Iop_CmpNE32, - unop(Iop_64HIto32, - binop(Iop_Shl64, - mkexpr(t9), - mkU8(1))), - mkU32(0x0)), - mkU64(0x000000007fffffffULL), - mkexpr(t9)), - IRExpr_ITE(binop(Iop_CmpNE32, - unop(Iop_64HIto32, - binop(Iop_Shl64, - mkexpr(t9), - mkU8(1))), - mkU32(0xffffffff)), - mkU64(0xffffffff80000000ULL), - mkexpr(t9)))); - assign(t10, IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_64to32, - mkexpr(t9)), - unop(Iop_64to32, - getAcc(ac))), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_64HIto32, - mkexpr(t9)), - unop(Iop_64HIto32, - getAcc(ac))), - mkexpr(t10), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - break; - } - case 0x1B: { /* DPSQX_SA.W.PH */ - DIP("dpsqx_sa.w.ph ac%u, r%u, r%u", ac, rs, rt); - vassert(!mode64); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I1); - t3 = newTemp(Ity_I1); - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); - t6 = newTemp(Ity_I1); - t7 = newTemp(Ity_I1); - t8 = newTemp(Ity_I64); - t9 = newTemp(Ity_I64); - t10 = newTemp(Ity_I32); - - assign(t0, getAcc(ac)); - /* Calculate the first cross dot product and saturate if - needed. */ - assign(t1, unop(Iop_32Sto64, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rt)))), - mkU8(0x1)))); - - /* If both input arguments are equal 0x8000, saturate - intermediate product and write to DSPControl - register. */ - assign(t2, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rs))), - mkU32(0x00008000))); - assign(t3, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rt))), - mkU32(0x00008000))); - - assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t2)), - unop(Iop_1Sto32, - mkexpr(t3))), - mkU32(0)), - mkU64(0x000000007fffffffULL), - mkexpr(t1))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t2)), - unop(Iop_1Sto32, - mkexpr(t3))), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))), - getDSPControl())); - /* Calculate second cross dot product and saturate if - needed. */ - assign(t5, unop(Iop_32Sto64, - binop(Iop_Shl32, - binop(Iop_Mul32, - unop(Iop_16Sto32, - unop(Iop_32to16, - getIReg(rs))), - unop(Iop_16Sto32, - unop(Iop_32HIto16, - getIReg(rt)))), - mkU8(0x1)))); - - /* If both input arguments are equal 0x8000, saturate - intermediate product and write to DSPControl - register. */ - assign(t6, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32to16, getIReg(rs))), - mkU32(0x00008000))); - assign(t7, binop(Iop_CmpEQ32, - unop(Iop_16Uto32, - unop(Iop_32HIto16, getIReg(rt))), - mkU32(0x00008000))); - - assign(t8, IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t6)), - unop(Iop_1Sto32, - mkexpr(t7))), - mkU32(0)), - mkU64(0x000000007fffffffULL), - mkexpr(t5))); - - putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, - binop(Iop_And32, - unop(Iop_1Sto32, - mkexpr(t6)), - unop(Iop_1Sto32, - mkexpr(t7))), - mkU32(0)), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))), - getDSPControl())); - /* Subtract intermediate products from value in the - accumulator. */ - assign(t9, - binop(Iop_Sub64, - mkexpr(t0), - binop(Iop_Add64, mkexpr(t8), mkexpr(t4)))); - - putAcc(ac, - IRExpr_ITE(binop(Iop_CmpEQ32, - binop(Iop_And32, - unop(Iop_64HIto32, - mkexpr(t9)), - mkU32(0x80000000)), - mkU32(0x0)), - IRExpr_ITE(binop(Iop_CmpNE32, - unop(Iop_64HIto32, - binop(Iop_Shl64, - mkexpr(t9), - mkU8(1))), - mkU32(0x0)), - mkU64(0x000000007fffffffULL), - mkexpr(t9)), - IRExpr_ITE(binop(Iop_CmpNE32, - unop(Iop_64HIto32, - binop(Iop_Shl64, - mkexpr(t9), - mkU8(1))), - mkU32(0xffffffff)), - mkU64(0xffffffff80000000ULL), - mkexpr(t9)))); - assign(t10, IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_64to32, - mkexpr(t9)), - unop(Iop_64to32, - getAcc(ac))), - getDSPControl(), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, - unop(Iop_64HIto32, - mkexpr(t9)), - unop(Iop_64HIto32, - getAcc(ac))), - mkexpr(t10), - binop(Iop_Or32, - getDSPControl(), - binop(Iop_Shl32, - mkU32(0x1), - mkU8(ac+16))))); - break; - } - default: - return -1; - } - break; /* end of DPAQ.W.PH */ + break; } - case 0x31: { /* APPEND */ - switch(sa) { - case 0x0: { /* APPEND */ - DIP("append r%u, r%u, %u", rt, rs, rd); - vassert(!mode64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - assign(t1, binop(Iop_Shl32, getIReg(rt), mkU8(rd))); + 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)); - if (31 == rd) { - putIReg(rt, binop(Iop_Or32, - mkexpr(t1), - binop(Iop_And32, - getIReg(rs), - mkU32(0x7fffffff)))); - } else if (1 == rd) { - putIReg(rt, - binop(Iop_Or32, - mkexpr(t1), - binop(Iop_And32, - getIReg(rs), mkU32(0x1)))); - } else { - assign(t2, - unop(Iop_Not32, - binop(Iop_Shl32, - mkU32(0xffffffff), mkU8(rd)))); + break; + } - putIReg(rt, binop(Iop_Or32, - mkexpr(t1), - binop(Iop_And32, - getIReg(rs), mkexpr(t2)))); - } - break; - } - case 0x1: { /* PREPEND */ - DIP("prepend r%u, r%u, %u", rt, rs, rd); - vassert(!mode64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - - if (0 != rd) { - assign(t1, binop(Iop_Shr32, getIReg(rt), mkU8(rd))); - - if (31 == rd) { - putIReg(rt, binop(Iop_Or32, - mkexpr(t1), - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rs), - mkU32(0x7fffffff)), - mkU8(1)))); - } else if (1 == rd) { - putIReg(rt, binop(Iop_Or32, - mkexpr(t1), - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rs), - mkU32(0x1)), - mkU8(31)))); - } else { - assign(t2, binop(Iop_Add32, mkU32(rd), mkU32(0x1))); + 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))); - assign(t3, unop(Iop_Not32, - binop(Iop_Shl32, - mkU32(0xffffffff), - unop(Iop_32to8, mkexpr(t2))))); + if (m) + putWReg(wd, + binop(Iop_Add64x2, + mkexpr(t1), mkexpr(t2))); + else putWReg(wd, mkexpr(t1)); - putIReg(rt, binop(Iop_Or32, - mkexpr(t1), - binop(Iop_Shl32, - binop(Iop_And32, - getIReg(rs), - mkexpr(t3)), - mkU8(32-rd)))); - } - } - break; - } - case 0x10: { /* BALIGN */ - DIP("balign r%u, r%u, %u", rt, rs, rd); - vassert(!mode64); - t1 = newTemp(Ity_I32); - t2 = newTemp(Ity_I32); - t3 = newTemp(Ity_I32); - - if ((2 != rd) && (0 != rd)) { - assign(t1, binop(Iop_Shl32, - binop(Iop_And32, - mkU32(rd), mkU32(0x3)), - mkU8(0x3))); - assign(t2, binop(Iop_Shl32, - getIReg(rt), - unop(Iop_32to8, mkexpr(t1)))); - assign(t3, binop(Iop_Shr32, - getIReg(rs), - unop(Iop_32to8, - binop(Iop_Shl32, - binop(Iop_Sub32, - mkU32(0x4), - binop(Iop_And32, - mkU32(rd), - mkU32(0x3))), - mkU8(0x3))))); - putIReg(rt, binop(Iop_Or32, mkexpr(t2), mkexpr(t3))); - } - break; - } - default: - return -1; - } - break; /* end of APPEND */ + break; } - default: - return -1; } + break; } + default: - return -1; + return -1; } + return 0; } -static Int msa_I8_logical(UInt cins, UChar wd, UChar ws) { - IRTemp t1, t2; +static Int msa_3R_0D(UInt cins, UChar wd, UChar ws) /* 3R (0x0D) */ +{ + IRTemp t1, t2, t3; UShort operation; - UChar i8; + UChar df, wt; + + operation = (cins & 0x03800000) >> 23; + df = (cins & 0x00600000) >> 21; + wt = (cins & 0x001F0000) >> 16; - 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 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; } - 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; + 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; } - 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; + 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; } - 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; + 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; + } } - default: - return -1; - } + assign(t3, + binop(Iop_AndV128, + mkexpr(t1), unop(Iop_NotV128, mkexpr(t2)))); + putWReg(wd, mkexpr(t3)); + break; + } - return 0; -} + case 0x04: { /* BSET.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + t3 = newTemp(Ity_V128); + ULong tmp = 1; + assign(t1, getWReg(ws)); -static Int msa_I8_branch(UInt cins, UChar wd, UChar ws) { - IRTemp t1, t2, t3, t4; - UShort operation; - UChar i8; + 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; + } - 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: { /* 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; + } } - 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; + 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; + } } - 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; + 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; } - 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; + } - return 0; -} + 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; + } -static Int msa_I8_shift(UInt cins, UChar wd, UChar ws) { - IRTemp t1, t2; - UShort operation; - UChar i8; + 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; + } - 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 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; + } - 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; + default: + return -1; } - 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; - } + break; + } default: return -1; @@ -12920,8 +6115,9 @@ static Int msa_I8_shift(UInt cins, UChar wd, UChar ws) { return 0; } -static Int msa_I5_06(UInt cins, UChar wd, UChar ws) { /* I5 (0x06) */ - IRTemp t1, t2, t3; +static Int msa_3R_0E(UInt cins, UChar wd, UChar ws) /* 3R (0x0E) */ +{ + IRTemp t1, t2, t3, t4; UShort operation; UChar df, wt; @@ -12930,809 +6126,878 @@ static Int msa_I5_06(UInt cins, UChar wd, UChar ws) { /* I5 (0x06) */ wt = (cins & 0x001F0000) >> 16; switch (operation) { - case 0x00: { /* ADDVI */ - ULong tmp = wt; + 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; + } - 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: { /* 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 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: { /* 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 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: { /* 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; + } - 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; - } + 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; } - 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; } - case 0x01: { /* SUBVI */ - ULong tmp = wt; + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - break; + default: + return -1; } - case 0x02: { /* MAXI_S */ - ULong tmp = wt; + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - break; + default: + return -1; } - case 0x03: { /* MAXI_U */ - ULong tmp = wt; + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - 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; } - case 0x04: { /* MINI_S */ - ULong tmp = wt; + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - break; + default: + return -1; } - case 0x05: { /* MINI_U */ - ULong tmp = wt; + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - break; + default: + return -1; } - default: { - return -1; - } + break; + } + + default: + return -1; } return 0; } -static Int msa_I5_07(UInt cins, UChar wd, UChar ws) { /* I5 (0x07) / I10 */ +static Int msa_3R_0F(UInt cins, UChar wd, UChar ws) /* 3R (0x0F) */ +{ IRTemp t1, t2, t3; UShort operation; - UChar df, i5; + UChar df, wt; operation = (cins & 0x03800000) >> 23; df = (cins & 0x00600000) >> 21; - i5 = (cins & 0x001F0000) >> 16; + wt = (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; - } + 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; } - 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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: { /* 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 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 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 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; - } + 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; } - 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; + } - case 0x04: { /* CLEI_S.df */ - ULong tmp = i5; + default: + return -1; + } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x05: { /* CLEI_U.df */ - ULong tmp = i5; + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - break; + default: + return -1; } - 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; + 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 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 0x02: /* LDI.W */ - DIP("LDI.W w%d, %d", wd, s10); - tmp = extend_s_10to32(s10); - tmp = tmp | (tmp << 32); - 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 0x03: /* LDI.D */ - DIP("LDI.D w%d, %d", wd, s10); - tmp = extend_s_10to64(s10); - 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; + } - default: - return -1; + 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; } - putWReg(wd, binop(Iop_64HLtoV128, mkU64(tmp), mkU64(tmp))); - break; + default: + return -1; } + break; + } + default: return -1; } @@ -13740,472 +7005,707 @@ static Int msa_I5_07(UInt cins, UChar wd, UChar ws) { /* I5 (0x07) / I10 */ return 0; } -static Int msa_BIT_09(UInt cins, UChar wd, UChar ws) { /* BIT (0x09) */ - IRTemp t1, t2, t3; +static Int msa_3R_10(UInt cins, UChar wd, UChar ws) /* 3R (0x10) */ +{ + IRTemp t1, t2, t3, t4; UShort operation; - UChar df, m; + UChar df, wt; 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; - } + df = (cins & 0x00600000) >> 21; + wt = (cins & 0x001F0000) >> 16; 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 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: { /* SLLI.H */ - DIP("SLLI.H w%d, w%d, %d", wd, ws, m); - putWReg(wd, binop(Iop_ShlN16x8, getWReg(ws), mkU8(m))); - 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: { /* SLLI.W */ - DIP("SLLI.W w%d, w%d, %d", wd, ws, m); - putWReg(wd, binop(Iop_ShlN32x4, getWReg(ws), mkU8(m))); - 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: { /* SLLI.D */ - DIP("SLLI.D w%d, w%d, %d", wd, ws, m); - putWReg(wd, binop(Iop_ShlN64x2, getWReg(ws), mkU8(m))); - 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; } - break; + default: + return -1; } - 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; - } + 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 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 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 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 0x03: { /* SRAI.D */ - DIP("SRAI.D w%d, w%d, %d", wd, ws, m); - putWReg(wd, binop(Iop_SarN64x2, getWReg(ws), mkU8(m))); - 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; } - 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; } - 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; - } + 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: { /* 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 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 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 0x03: { /* SRLI.D */ - DIP("SRLI.D w%d, w%d, %d", wd, ws, m); - putWReg(wd, binop(Iop_ShrN64x2, getWReg(ws), mkU8(m))); - 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; } - 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; + } - case 0x03: { /* BCLRI.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - t3 = newTemp(Ity_V128); - ULong tmp = 1; - assign(t1, getWReg(ws)); + default: + return -1; + } - 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; - } + 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 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 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 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 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; - } + 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; } - assign(t3, binop(Iop_AndV128, - mkexpr(t1), unop(Iop_NotV128, 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; } - case 0x04: { /* BSETI */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - t3 = newTemp(Ity_V128); - ULong tmp = 1; - assign(t1, getWReg(ws)); + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2))); - putWReg(wd, mkexpr(t3)); - break; + default: + return -1; } - case 0x05: { /* BNEGI.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - t3 = newTemp(Ity_V128); - ULong tmp = 1; - assign(t1, getWReg(ws)); + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2))); - putWReg(wd, mkexpr(t3)); - break; + default: + return -1; } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } + break; + } + default: return -1; } @@ -14213,498 +7713,682 @@ static Int msa_BIT_09(UInt cins, UChar wd, UChar ws) { /* BIT (0x09) */ return 0; } -static Int msa_BIT_0A(UInt cins, UChar wd, UChar ws) { /* BIT (0x0A) */ - IRTemp t1, t2; +static Int msa_3R_11(UInt cins, UChar wd, UChar ws) /* 3R (0x11) */ +{ + IRTemp t1, t2, t3; UShort operation; - UChar df, m; + UChar df, wt; 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; - } + df = (cins & 0x00600000) >> 21; + wt = (cins & 0x001F0000) >> 16; 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 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 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))); + 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; + } - 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)))); - } + 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; + } - 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; } - break; + default: + return -1; } - 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; + } - 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 0x02: { /* SAT_U.W */ - DIP("SAT_U.W w%d, w%d, %d", wd, ws, m); + 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; + } - 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)))); - } + 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; + } - 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; + } - case 0x03: { /* SAT_U.D */ - DIP("SAT_U.D w%d, w%d, %d", wd, ws, m); + default: + return -1; + } - 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: { /* 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; } - 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: { /* 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, + 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), - mkU8(m))); - assign(t2, - binop(Iop_ShrN8x16, - binop(Iop_ShlN8x16, - getWReg(ws), - mkU8(8 - m)), - mkU8(7))); + 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; + } - if (m) putWReg(wd, binop(Iop_Add8x16, - mkexpr(t1), - mkexpr(t2))); - else putWReg(wd, mkexpr(t1)); + 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; + } - break; - } + default: + return -1; + } - 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))); + break; + } - if (m) - putWReg(wd, - binop(Iop_Add16x8, - mkexpr(t1), mkexpr(t2))); - else putWReg(wd, mkexpr(t1)); + 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; + } - 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: { /* SRARI.W */ - DIP("SRARI.W w%d, w%d, %d", wd, ws, m); - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, + 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(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; - } + 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: { /* SRARI.D */ - DIP("SRARI.D w%d, w%d, %d", wd, ws, m); - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, + 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(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; - } + 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; } - break; + default: + return -1; } - 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; + } - 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: { /* 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))); + 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; + } - if (m) - putWReg(wd, - binop(Iop_Add16x8, - mkexpr(t1), mkexpr(t2))); - else putWReg(wd, mkexpr(t1)); + 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; + } - 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; + } - 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))); + default: + return -1; + } - if (m) - putWReg(wd, - binop(Iop_Add32x4, - mkexpr(t1), mkexpr(t2))); - else putWReg(wd, mkexpr(t1)); + break; + } - 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 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))); + 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; + } - if (m) - putWReg(wd, - binop(Iop_Add64x2, - mkexpr(t1), mkexpr(t2))); - else putWReg(wd, mkexpr(t1)); + 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; + } - 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; } - break; + default: + return -1; } + break; + } + default: return -1; } @@ -14712,8 +8396,9 @@ static Int msa_BIT_0A(UInt cins, UChar wd, UChar ws) { /* BIT (0x0A) */ return 0; } -static Int msa_3R_0D(UInt cins, UChar wd, UChar ws) { /* 3R (0x0D) */ - IRTemp t1, t2, t3; +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; @@ -14722,1453 +8407,1644 @@ static Int msa_3R_0D(UInt cins, UChar wd, UChar ws) { /* 3R (0x0D) */ 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; + 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; } - 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x03: { /* BCLR.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - t3 = newTemp(Ity_V128); - ULong tmp = 1; - assign(t1, getWReg(ws)); + break; + } - 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 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: { /* 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 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: { /* 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 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: { /* 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; - } + 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; } - assign(t3, - binop(Iop_AndV128, - mkexpr(t1), unop(Iop_NotV128, mkexpr(t2)))); - putWReg(wd, mkexpr(t3)); - break; + default: + return -1; } - 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; - } + 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 0x04: { /* DIV_S.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))); + } - 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; - } + 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; } - assign(t3, binop(Iop_OrV128, mkexpr(t1), mkexpr(t2))); - putWReg(wd, mkexpr(t3)); - break; - } + case 0x01: { /* DIV_S.H */ + DIP("DIV_S.H w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[8]; + Int i; - case 0x05: { /* BNEG.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - t3 = newTemp(Ity_V128); - ULong tmp = 1; - assign(t1, getWReg(ws)); + 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))); + } - 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; - } + 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 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: { /* DIV_S.W */ + DIP("DIV_S.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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)))); + } - 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; - } + putWReg(wd, + binop(Iop_64HLtoV128, \ + binop(Iop_32HLto64, + mkexpr(tmp[3]), + mkexpr(tmp[2])), + binop(Iop_32HLto64, + mkexpr(tmp[1]), + mkexpr(tmp[0])))); + break; } - assign(t3, binop(Iop_XorV128, mkexpr(t1), mkexpr(t2))); - putWReg(wd, mkexpr(t3)); - 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; + } - 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; - } + default: + return -1; + } - 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; - } + 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 0x05: { /* DIV_U.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))); + } - default: - return -1; + 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; } - break; - } + case 0x01: { /* DIV_U.H */ + DIP("DIV_U.H w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[8]; + Int i; - 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; - } + 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))); + } - 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; - } + 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: { /* 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 0x02: { /* DIV_U.W */ + DIP("DIV_U.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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)))); + } - default: - return -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; } - 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; } - default: - return -1; - } + break; + } - return 0; -} + case 0x06: { /* MOD_S.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); -static Int msa_3R_0E(UInt cins, UChar wd, UChar ws) { /* 3R (0x0E) */ - IRTemp t1, t2, t3, t4; - UShort operation; - UChar df, 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))); + } - operation = (cins & 0x03800000) >> 23; - df = (cins & 0x00600000) >> 21; - wt = (cins & 0x001F0000) >> 16; + 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; + } - 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: { /* MOD_S.H */ + DIP("MOD_S.H w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[8]; + Int i; - 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; - } + 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))); + } - 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; - } + 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 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; - } + 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))))); + } - default: - return -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; } - 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; + } - 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; - } + default: + return -1; + } - 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; - } + 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 0x07: { /* MOD_U.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))); + } - default: - return -1; + 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; } - break; - } + case 0x01: { /* MOD_U.H */ + DIP("MOD_U.H w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[8]; + Int i; - 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; - } + 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))); + } - 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; - } + 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: { /* 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 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))))); + } - 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; - } + 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; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + default: + return -1; + } - 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; - } + return 0; +} - 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; - } +static Int msa_3R_13(UInt cins, UChar wd, UChar ws) /* 3R (0x13) */ +{ + IRTemp t1, t2; + UShort operation; + UChar df, wt; - default: - return -1; + 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; } - break; - } + case 0x02: { /* DOTP_S.W */ + DIP("DOTP_S.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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))))); + } - 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; - } + 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 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: { /* DOTP_S.D */ + DIP("DOTP_S.D w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[2]; + Int i; - 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; - } + 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))))); + } - default: - return -1; + putWReg(wd, + binop(Iop_64HLtoV128, + mkexpr(tmp[1]), mkexpr(tmp[0]))); + break; } - break; + default: + return -1; } - 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; - } + 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 0x01: { /* DOTP_U.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))))); + } - default: - return -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; } - break; - } + case 0x02: { /* DOTP_U.W */ + DIP("DOTP_U.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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))))); + } - 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; - } + 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 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: { /* DOTP_U.D */ + DIP("DOTP_U.D w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[2]; + Int i; - 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; - } + 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))))); + } - default: - return -1; + putWReg(wd, + binop(Iop_64HLtoV128, + mkexpr(tmp[1]), mkexpr(tmp[0]))); + break; } - break; + default: + return -1; } - 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; - } + 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: { /* DPADD_S.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))))); + } - 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; - } + 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; + } - default: - return -1; + 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; } - 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; } - default: - return -1; - } + break; + } - return 0; -} + case 0x03: { /* DPADD_U.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); -static Int msa_3R_0F(UInt cins, UChar wd, UChar ws) { /* 3R (0x0F) */ - IRTemp t1, t2, t3; - UShort operation; - UChar df, 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))))); + } - operation = (cins & 0x03800000) >> 23; - df = (cins & 0x00600000) >> 21; - wt = (cins & 0x001F0000) >> 16; + 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; + } - 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 0x02: { /* DPADD_U.W */ + DIP("DPADD_U.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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))))); + } - 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; - } + 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: { /* 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; - } + case 0x03: { /* DPADD_U.D */ + DIP("DPADD_U.D w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[2]; + Int i; - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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 0x04: { /* DPSUB_S.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))))); + } - default: - return -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; } - break; - } + case 0x02: { /* DPSUB_S.W */ + DIP("DPSUB_S.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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))))); + } - 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; - } + 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 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: { /* DPSUB_S.D */ + DIP("DPSUB_S.D w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[2]; + Int i; - 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; - } + 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))))); + } - default: - return -1; + putWReg(wd, + binop(Iop_Sub64x2, + getWReg(wd), + binop(Iop_64HLtoV128, + mkexpr(tmp[1]), + mkexpr(tmp[0])))); + break; } - break; + default: + return -1; } - 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; - } + 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 0x05: { /* DPSUB_U.df */ + t1 = newTemp(Ity_V128); + t2 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + assign(t2, getWReg(wt)); - 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; - } + 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))))); + } - default: - return -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; } - break; - } + case 0x02: { /* DPSUB_U.W */ + DIP("DPSUB_U.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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))))); + } - 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; - } + 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 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: { /* DPSUB_U.D */ + DIP("DPSUB_U.D w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[2]; + Int i; - 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; - } + 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))))); + } - default: - return -1; + putWReg(wd, + binop(Iop_Sub64x2, + getWReg(wd), + binop(Iop_64HLtoV128, + mkexpr(tmp[1]), + mkexpr(tmp[0])))); + break; } - break; + default: + return -1; } + break; + } + default: return -1; } @@ -16176,706 +10052,723 @@ static Int msa_3R_0F(UInt cins, UChar wd, UChar ws) { /* 3R (0x0F) */ 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; - } +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; - 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; - } + operation = (cins & 0x03800000) >> 23; + df = (cins & 0x00600000) >> 21; + wt = (cins & 0x001F0000) >> 16; + ty = mode64 ? Ity_I64 : Ity_I32; - 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; - } + 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 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; - } + 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; + } - default: - return -1; + 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; } - 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; + } } - 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; - } + 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 0x01: { /* SPLAT.df */ + switch (df) { + Int i; - 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 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)))); + } - 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; - } + 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; + } - default: - return -1; + 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; } - 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)))); + } - 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; - } + 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 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 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)))); + } - 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; - } + putWReg(wd, + binop(Iop_64HLtoV128, + mkexpr(tmp[1]), mkexpr(tmp[0]))); + 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; - } + break; + } - default: - return -1; + 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; } - 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 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 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 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 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; + } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - 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; } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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 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 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; - } + 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; + } - default: - return -1; + 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; } - 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; + } } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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 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 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 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } + break; + } + default: return -1; } @@ -16883,8 +10776,9 @@ static Int msa_3R_10(UInt cins, UChar wd, UChar ws) { /* 3R (0x10) */ return 0; } -static Int msa_3R_11(UInt cins, UChar wd, UChar ws) { /* 3R (0x11) */ - IRTemp t1, t2, t3; +static Int msa_3R_15(UInt cins, UChar wd, UChar ws) /* 3R (0x15) */ +{ + IRTemp t1, t2, t3, t4; UShort operation; UChar df, wt; @@ -16893,671 +10787,831 @@ static Int msa_3R_11(UInt cins, UChar wd, UChar ws) { /* 3R (0x11) */ 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 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)); - 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; - } + 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))); + } - 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; - } + 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 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; - } + 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))); + } - default: - return -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; } - break; - } + case 0x02: { /* VSHF.W */ + DIP("VSHF.W w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[4]; + Int i; - 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; - } + 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))); + } - 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; - } + 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 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: { /* VSHF.D */ + DIP("VSHF.D w%d, w%d, w%d", wd, ws, wt); + IRTemp tmp[2]; + Int i; - 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; - } + 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))); + } - default: - return -1; + putWReg(wd, + binop(Iop_64HLtoV128, + mkexpr(tmp[1]), mkexpr(tmp[0]))); + break; } - break; + default: + return -1; } - 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; - } + 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, + 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), - 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; - } + mkexpr(t2)), + mkexpr(t4)), + mkU8(7))); + putWReg(wd, + binop(Iop_Add8x16, + mkexpr(t1), mkexpr(t3))); + 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, + 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), - 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; - } + mkexpr(t2)), + mkexpr(t4)), + mkU8(15))); + putWReg(wd, + binop(Iop_Add16x8, + mkexpr(t1), mkexpr(t3))); + 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, + 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), - 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; - } + mkexpr(t2)), + mkexpr(t4)), + mkU8(31))); + putWReg(wd, + binop(Iop_Add32x4, + mkexpr(t1), mkexpr(t3))); + break; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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, + 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_SarN16x8, + binop(Iop_Shl8x16, 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; - } + mkexpr(t2)), + mkexpr(t4)), + mkU8(7))); + putWReg(wd, + binop(Iop_Add8x16, + mkexpr(t1), 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, + 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_SarN32x4, + binop(Iop_Shl16x8, 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; - } + mkexpr(t2)), + mkexpr(t4)), + mkU8(15))); + putWReg(wd, + binop(Iop_Add16x8, + mkexpr(t1), 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, + 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_SarN64x2, + binop(Iop_Shl32x4, 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; - } + mkexpr(t2)), + mkexpr(t4)), + mkU8(31))); + putWReg(wd, + binop(Iop_Add32x4, + mkexpr(t1), mkexpr(t3))); + break; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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 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: { /* 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 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: { /* 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; - } + 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; + 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; } - 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; } - 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; - } + 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, + 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, - 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; - } + mkexpr(t1), mkU8(8)), + binop(Iop_SarN16x8, + binop(Iop_ShlN16x8, + mkexpr(t2), mkU8(8)), + mkU8(8)))); + putWReg(wd, mkexpr(t3)); + 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, + 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, - 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; - } + 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 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } + break; + } + default: return -1; } @@ -17565,1653 +11619,2129 @@ static Int msa_3R_11(UInt cins, UChar wd, UChar ws) { /* 3R (0x11) */ return 0; } -static Int msa_3R_12(UInt cins, UChar wd, UChar ws) { /* 3R (0x12) */ - IRTemp t1, t2, t3, t4, t5, t6; +static Int msa_3R_1A(UInt cins, UChar wd, UChar ws) /* 3R (0x1A) */ +{ UShort operation; UChar df, wt; - operation = (cins & 0x03800000) >> 23; - df = (cins & 0x00600000) >> 21; + operation = (cins & 0x03C00000) >> 22; + df = (cins & 0x00200000) >> 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 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: { /* 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 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; + } - 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; - } + default: + return -1; + } - 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; - } + break; + } - default: - return -1; + 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; } - 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; } - 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; - } + 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: { /* 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 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 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; + } - 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; + } - 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; } - 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; } - 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; - } + 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 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 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 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; + } - 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; + } - 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; } - break; + default: + return -1; } - 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; + break; + } - 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))); - } + 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; + } - 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: { /* 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; + } - case 0x01: { /* DIV_S.H */ - DIP("DIV_S.H w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[8]; - Int i; + default: + return -1; + } - 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))); - } + break; + } - 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 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 0x02: { /* DIV_S.W */ - DIP("DIV_S.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + 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; + } - 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)))); - } + default: + return -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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x05: { /* DIV_U.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))); - } + 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; + } - 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; - } + default: + return -1; + } - case 0x01: { /* DIV_U.H */ - DIP("DIV_U.H w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[8]; - Int i; + break; + } - 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))); - } + 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; + } - 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; - } + break; + } - case 0x02: { /* DIV_U.W */ - DIP("DIV_U.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + 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; + } - 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)))); - } + 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; + } - 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; + } - 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; - } + break; + } - default: - return -1; + 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; } - 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; } - case 0x06: { /* MOD_S.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + default: + return -1; + } - 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))); - } + return 0; +} - 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; - } +static Int msa_3R_1B(UInt cins, UChar wd, UChar ws) /* 3R (0x1B) */ +{ + IRTemp t1, t2, t3, t4; + UShort operation; + UChar df, wt; - case 0x01: { /* MOD_S.H */ - DIP("MOD_S.H w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[8]; - Int i; + operation = (cins & 0x03C00000) >> 22; + df = (cins & 0x00200000) >> 21; + wt = (cins & 0x001F0000) >> 16; - 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))); - } + 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; + } - 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 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; + } - case 0x02: { /* MOD_S.W */ - DIP("MOD_S.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - 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 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 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; - } + 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; + 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; } - 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; } - case 0x07: { /* MOD_U.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))); - } + 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; + } - 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; - } + default: + return -1; + } - case 0x01: { /* MOD_U.H */ - DIP("MOD_U.H w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[8]; - Int i; + break; + } - 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))); - } + 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, - 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; - } + 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))))); + } - case 0x02: { /* MOD_U.W */ - DIP("MOD_U.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + putWReg(wd, + binop(Iop_64HLtoV128, + unop(Iop_ReinterpF64asI64, + mkexpr(tmp[1])), + unop(Iop_ReinterpF64asI64, + mkexpr(tmp[0])))); + break; + } - 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))))); - } + default: + return -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; - } + 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; - } + 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))))); + } - default: - return -1; + 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; } - 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; } - default: - return -1; - } + break; + } - return 0; -} + 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; + } -static Int msa_3R_13(UInt cins, UChar wd, UChar ws) { /* 3R (0x13) */ - IRTemp t1, t2; - UShort operation; - UChar df, wt; + 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; + } - operation = (cins & 0x03800000) >> 23; - df = (cins & 0x00600000) >> 21; - wt = (cins & 0x001F0000) >> 16; + default: + return -1; + } - switch (operation) { - case 0x00: { /* DOTP_S.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))))); - } + 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; + } - 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; - } + default: + return -1; + } - case 0x02: { /* DOTP_S.W */ - DIP("DOTP_S.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + break; + } - 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))))); - } + 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; + } - 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 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; + } - case 0x03: { /* DOTP_S.D */ - DIP("DOTP_S.D w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[2]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - putWReg(wd, - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), mkexpr(tmp[0]))); - 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x01: { /* DOTP_U.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))))); - } + 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; + } - 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; - } + default: + return -1; + } - case 0x02: { /* DOTP_U.W */ - DIP("DOTP_U.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + break; + } - 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))))); - } + 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; + } - 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 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; + } - case 0x03: { /* DOTP_U.D */ - DIP("DOTP_U.D w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[2]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - putWReg(wd, - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), mkexpr(tmp[0]))); - 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x02: { /* DPADD_S.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + default: + return -1; + } - 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))))); - } + return 0; +} - 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; - } +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; - case 0x02: { /* DPADD_S.W */ - DIP("DPADD_S.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + operation = (cins & 0x03C00000) >> 22; + df = (cins & 0x00200000) >> 21; + wt = (cins & 0x001F0000) >> 16; - 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))))); - } + 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; + } - 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 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; + } - case 0x03: { /* DPADD_S.D */ - DIP("DPADD_S.D w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[2]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - putWReg(wd, - binop(Iop_Add64x2, - getWReg(wd), - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), - mkexpr(tmp[0])))); - 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x03: { /* DPADD_U.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))))); - } + 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; + } - 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 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; + } - case 0x02: { /* DPADD_U.W */ - DIP("DPADD_U.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - 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 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 0x03: { /* DPADD_U.D */ - DIP("DPADD_U.D w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[2]; - Int i; + 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; + } - 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))))); - } + default: + return -1; + } - putWReg(wd, - binop(Iop_Add64x2, - getWReg(wd), - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), - mkexpr(tmp[0])))); - break; - } + break; + } - default: - return -1; + 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; } - 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; } - case 0x04: { /* DPSUB_S.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))))); - } + 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; + } - 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; - } + default: + return -1; + } - case 0x02: { /* DPSUB_S.W */ - DIP("DPSUB_S.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + break; + } - 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))))); - } + 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; + } - 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 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; + } - case 0x03: { /* DPSUB_S.D */ - DIP("DPSUB_S.D w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[2]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - putWReg(wd, - binop(Iop_Sub64x2, - getWReg(wd), - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), - mkexpr(tmp[0])))); - 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - case 0x05: { /* DPSUB_U.df */ - t1 = newTemp(Ity_V128); - t2 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); + break; + } - 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; + 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; + } - 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))))); - } + 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; + } - 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; - } + default: + return -1; + } - case 0x02: { /* DPSUB_U.W */ - DIP("DPSUB_U.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + break; + } - 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))))); - } + 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; + } - 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 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; + } - case 0x03: { /* DPSUB_U.D */ - DIP("DPSUB_U.D w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[2]; - Int i; + default: + return -1; + } - 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))))); - } + break; + } - putWReg(wd, - binop(Iop_Sub64x2, - getWReg(wd), - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), - mkexpr(tmp[0])))); - 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } + break; + } + default: return -1; } @@ -19219,1563 +13749,1331 @@ static Int msa_3R_13(UInt cins, UChar wd, UChar ws) { /* 3R (0x13) */ return 0; } -static Int msa_3R_14(UInt cins, UChar wd, UChar ws) { /* 3R (0x14) */ - IRTemp t1, t2, t3, t4; +static Int msa_ELM(UInt cins, UChar wd, UChar ws) /* ELM (0x19) */ +{ + IRTemp t1, t2, t3, t4, t5; IRType ty; UShort operation; - UChar df, wt; + 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; - operation = (cins & 0x03800000) >> 23; - df = (cins & 0x00600000) >> 21; - wt = (cins & 0x001F0000) >> 16; - ty = mode64 ? Ity_I64 : Ity_I32; + 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: { /* SLD.df */ - switch (df) { - case 0x00: { - DIP("SLD.B w%d, w%d[%d]", wd, ws, wt); - t1 = newTemp(Ity_I32); + 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); - 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, + mkU8(n << 3))); + assign(t2, binop(Iop_ShlV128, getWReg(wd), - unop(Iop_32to8, - binop(Iop_Sub32, - mkU32(128), - mkexpr(t1))))); + mkU8(n ? + (16 - n) << 3 : 0))); putWReg(wd, - binop(Iop_OrV128, - mkexpr(t2), mkexpr(t3))); + binop(Iop_OrV128, mkexpr(t1), mkexpr(t2))); 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 0x20: /* SLDI.H */ + DIP("SLDI.H w%d, w%d[%d]", wd, ws, n); - 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; - } + 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))); + } - 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]; + case 0x30: /* SLDI.W */ + DIP("SLDI.W w%d, w%d[%d]", wd, ws, n); - for (i = 0; i < 16; i++) { - tmp[i] = newTemp(Ity_I8); - assign(tmp[i], - binop(Iop_GetElem8x16, - mkexpr(t1), - unop(Iop_32to8, mkexpr(t2)))); + 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))); } - 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]; + case 0x38: /* SLDI.D */ + DIP("SLDI.D w%d, w%d[%d]", wd, ws, n); - for (i = 0; i < 8; i++) { - tmp[i] = newTemp(Ity_I16); - assign(tmp[i], - binop(Iop_GetElem16x8, - mkexpr(t1), - unop(Iop_32to8, mkexpr(t2)))); + 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))); } - 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)))); - } + default: + return -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; - } + break; - case 0x03: { /* SPLAT.D */ - DIP("SPLAT.D w%d, w%d, w%d", wd, ws, wt); + 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_I32); - assign(t1, getWReg(ws)); - assign(t2, - mkNarrowTo32(ty, getIReg(wt))); - IRTemp tmp[2]; + t2 = newTemp(Ity_V128); + t3 = newTemp(Ity_V128); + t4 = newTemp(Ity_V128); - for (i = 0; i < 2; i++) { - tmp[i] = newTemp(Ity_I64); - assign(tmp[i], - binop(Iop_GetElem64x2, - mkexpr(t1), - unop(Iop_32to8, mkexpr(t2)))); - } + if (n & 1) + assign(t1, + binop(Iop_InterleaveOddLanes8x16, + getWReg(ws), + getWReg(ws))); + else + assign(t1, + binop(Iop_InterleaveEvenLanes8x16, + getWReg(ws), + getWReg(ws))); - putWReg(wd, - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), mkexpr(tmp[0]))); - break; - } - } + n /= 2; - break; - } + if (n & 1) + assign(t2, + binop(Iop_InterleaveOddLanes16x8, + mkexpr(t1), mkexpr(t1))); + else + assign(t2, + binop(Iop_InterleaveEvenLanes16x8, + mkexpr(t1), mkexpr(t1))); - 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)); + 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 0x01: { /* PCKEV.H */ - DIP("PCKEV.H w%d, w%d, w%d", wd, ws, wt); + 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); - assign(t1, getWReg(ws)); - assign(t2, getWReg(wt)); - assign(t3, - binop(Iop_PackEvenLanes16x8, - mkexpr(t1), mkexpr(t2))); + + 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 0x02: { /* PCKEV.W */ - DIP("PCKEV.W w%d, w%d, w%d", wd, ws, wt); + 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)); - assign(t2, getWReg(wt)); - assign(t3, - binop(Iop_PackEvenLanes32x4, - mkexpr(t1), mkexpr(t2))); + + 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 0x03: { /* PCKEV.D */ - DIP("PCKEV.D w%d, w%d, w%d", wd, ws, wt); + case 0x38: /* SPLATI.D */ + DIP("SPLATI.D w%d, w%d[%d]", wd, ws, n); 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))); + + 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; - } + default: + return -1; + } - break; - } + 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)); + 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 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 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 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 4: + assign(t1, + unop(Iop_32to16, + unop(Iop_64to32, + unop(Iop_V128HIto64, + getWReg(ws))))); + 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; - } + case 5: + assign(t1, + unop(Iop_32HIto16, + unop(Iop_64to32, + unop(Iop_V128HIto64, + getWReg(ws))))); + break; - default: - return -1; - } + case 6: + assign(t1, + unop(Iop_32to16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws))))); + break; - break; - } + case 7: + assign(t1, + unop(Iop_32HIto16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws))))); + 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)); + putIReg(wd, + unop(mode64 ? Iop_16Sto64 : Iop_16Sto32, + mkexpr(t1))); 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 0x30: /* COPY_S.W */ + DIP("COPY_S.W r%d, w%d[%d]", wd, ws, n); - 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; - } + switch (n) { + case 0: + putIReg(wd, + mkWidenFrom32(ty, + unop(Iop_V128to32, + getWReg(ws)), + True)); + 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; - } + case 1: + t2 = newTemp(Ity_I64); + assign(t2, + unop(Iop_V128to64, getWReg(ws))); + putIReg(wd, + mkWidenFrom32(ty, + unop(Iop_64HIto32, + mkexpr(t2)), + True)); + break; - default: - return -1; - } + case 2: + t2 = newTemp(Ity_I64); + assign(t2, + unop(Iop_V128HIto64, + getWReg(ws))); + putIReg(wd, + mkWidenFrom32(ty, + unop(Iop_64to32, + mkexpr(t2)), + True)); + break; - 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; - 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; - } + default: + 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 0x38: /* COPY_S.D */ + if (mode64) { + DIP("COPY_S.D r%d, w%d[%d]", wd, ws, n); - 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; - } - } + switch (n) { + case 0: + putIReg(wd, + unop(Iop_V128to64, + getWReg(ws))); + break; - break; - } + case 1: + putIReg(wd, + unop(Iop_V128HIto64, + getWReg(ws))); + break; + } + } else { + return -2; + } - 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; - } + default: + return -1; + } - 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; - } + 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; - } + 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); - default: - return -1; - } + 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; - break; - } + case 2: + assign(t1, + unop(Iop_16to8, + unop(Iop_32HIto16, + unop(Iop_64to32, + unop(Iop_V128to64, + getWReg(ws)))))); + 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 3: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + unop(Iop_64to32, + unop(Iop_V128to64, + getWReg(ws)))))); + 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 4: + assign(t1, + unop(Iop_16to8, + unop(Iop_32to16, + unop(Iop_64HIto32, + unop(Iop_V128to64, + getWReg(ws)))))); + 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 5: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32to16, + unop(Iop_64HIto32, + unop(Iop_V128to64, + getWReg(ws)))))); + 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; - } + case 6: + assign(t1, + unop(Iop_16to8, + unop(Iop_32HIto16, + unop(Iop_64HIto32, + unop(Iop_V128to64, + getWReg(ws)))))); + break; - default: - return -1; - } + case 7: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + unop(Iop_64HIto32, + unop(Iop_V128to64, + getWReg(ws)))))); + break; - break; - } + case 8: + assign(t1, + unop(Iop_16to8, + unop(Iop_32to16, + unop(Iop_64to32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; - default: - return -1; - } + case 9: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32to16, + unop(Iop_64to32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; - return 0; -} + case 10: + assign(t1, + unop(Iop_16to8, + unop(Iop_32HIto16, + unop(Iop_64to32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; -static Int msa_3R_15(UInt cins, UChar wd, UChar ws) { /* 3R (0x15) */ - IRTemp t1, t2, t3, t4; - UShort operation; - UChar df, wt; + case 11: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + unop(Iop_64to32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; - operation = (cins & 0x03800000) >> 23; - df = (cins & 0x00600000) >> 21; - wt = (cins & 0x001F0000) >> 16; + case 12: + assign(t1, + unop(Iop_16to8, + unop(Iop_32to16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; - 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)); + case 13: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32to16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; - switch (df) { - case 0x00: { /* VSHF.B */ - DIP("VSHF.B w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[16]; - Int i; + case 14: + assign(t1, + unop(Iop_16to8, + unop(Iop_32HIto16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; - 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))); + case 15: + assign(t1, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws)))))); + break; } - 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])))))); + putIReg(wd, + unop(mode64 ? Iop_8Uto64 : Iop_8Uto32, + mkexpr(t1))); break; - } - case 0x01: { /* VSHF.H */ - DIP("VSHF.H w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[8]; - Int i; + case 0x20: /* COPY_U.H */ + DIP("COPY_U.H r%d, w%d[%d]", wd, ws, n); + t1 = newTemp(Ity_I16); - 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))); - } + switch (n) { + case 0: + assign(t1, + unop(Iop_32to16, + unop(Iop_64to32, + unop(Iop_V128to64, + getWReg(ws))))); + break; - 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 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 0x02: { /* VSHF.W */ - DIP("VSHF.W w%d, w%d, w%d", wd, ws, wt); - IRTemp tmp[4]; - Int i; + case 6: + assign(t1, + unop(Iop_32to16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws))))); + break; - 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))); + case 7: + assign(t1, + unop(Iop_32HIto16, + unop(Iop_64HIto32, + unop(Iop_V128HIto64, + getWReg(ws))))); + break; } - putWReg(wd, - binop(Iop_64HLtoV128, - binop(Iop_32HLto64, - mkexpr(tmp[3]), - mkexpr(tmp[2])), - binop(Iop_32HLto64, - mkexpr(tmp[1]), - mkexpr(tmp[0])))); + putIReg(wd, + unop(mode64 ? Iop_16Uto64 : Iop_16Uto32, + mkexpr(t1))); 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))); - } + case 0x30: /* COPY_U.W */ + DIP("COPY_U.W r%d, w%d[%d]", wd, ws, n); - putWReg(wd, - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), mkexpr(tmp[0]))); - break; - } + switch (n) { + case 0: + putIReg(wd, + mkWidenFrom32(ty, + unop(Iop_V128to32, + getWReg(ws)), + False)); + break; - default: - return -1; - } + case 1: + t2 = newTemp(Ity_I64); + assign(t2, + unop(Iop_V128to64, + getWReg(ws))); + putIReg(wd, + mkWidenFrom32(ty, + unop(Iop_64HIto32, + mkexpr(t2)), + False)); + break; - 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 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 3: + t2 = newTemp(Ity_I64); + assign(t2, + unop(Iop_V128HIto64, + getWReg(ws))); + putIReg(wd, + mkWidenFrom32(ty, + unop(Iop_64HIto32, + mkexpr(t2)), + False)); + 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; - } + default: + 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; + } - default: - return -1; + break; } - 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 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))); - 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; - } + 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)))); + } - 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; + } 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))); + } - default: - return -1; - } + switch (df) { + case 0x00: /* INSERT.B */ + DIP("INSERT.B w%d[%d], r%d", wd, n, ws); - break; - } + if (n >= 8) { + n -= 8; + } else { + hi = 0; + } - 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)); + n <<= 3; + mask = 0xFFull; 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 0x20: /* INSERT.H */ + DIP("INSERT.H w%d[%d], r%d", wd, n, ws); - 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)); + if (n >= 4) { + n -= 4; + } else { + hi = 0; + } + + n <<= 4; + mask = 0xFFFFull; break; - } - default: - return -1; - } + case 0x30: /* INSERT.W */ + DIP("INSERT.W w%d[%d], r%d", wd, n, ws); - break; - } + if (n >= 2) { + n -= 2; + } else { + hi = 0; + } - 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)); + n <<= 5; + mask = 0xFFFFFFFFull; break; - } - case 0x02: { /* HADD_U.W */ - DIP("HADD_U.W w%d, w%d, w%d", wd, ws, wt); + 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); - 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)); + 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 0x03: { /* HADD_U.D */ - DIP("HADD_U.D w%d, w%d, w%d", wd, ws, wt); + case 0x20: { /* INSVE.H */ + DIP("INSVE.H w%d[%d], r%d[0]", wd, n, ws); 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; - } + assign(t1, getWReg(wd)); + assign(t2, getWReg(ws)); + Int i; + IRTemp tmp[8]; - default: - return -1; - } + for (i = 0; i < 8; i++) { + tmp[i] = newTemp(Ity_I16); - break; - } + if (n == i) + assign(tmp[i], + binop(Iop_GetElem16x8, + mkexpr(t2), mkU8(0x0))); + else + assign(tmp[i], + binop(Iop_GetElem16x8, + mkexpr(t1), mkU8(i))); + } - 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)); + 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: { /* HSUB_S.W */ - DIP("HSUB_S.W w%d, w%d, w%d", wd, ws, wt); + case 0x30: { /* INSVE.W */ + DIP("INSVE.W w%d[%d], r%d[0]", wd, n, ws); 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)); + 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 0x03: { /* HSUB_S.D */ - DIP("HSUB_S.D w%d, w%d, w%d", wd, ws, wt); + case 0x38: { /* INSVE.D */ + DIP("INSVE.D w%d[%d], r%d[0]", wd, n, ws); 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)); + 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; } + } - default: - return -1; + break; } - break; + default: + return -1; } + } - 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; - } + 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 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 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 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; - } + 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; + } - default: - return -1; - } + 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; + } - 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; @@ -20784,3718 +15082,3285 @@ static Int msa_3R_15(UInt cins, UChar wd, UChar ws) { /* 3R (0x15) */ return 0; } -static Int msa_3R_1A(UInt cins, UChar wd, UChar ws) { /* 3R (0x1A) */ +static Int msa_2R(UInt cins, UChar wd, UChar ws) /* 2R */ +{ + IRTemp t1, t2, t3, t4; + IRType ty; UShort operation; - UChar df, wt; + UChar df; - operation = (cins & 0x03C00000) >> 22; - df = (cins & 0x00200000) >> 21; - wt = (cins & 0x001F0000) >> 16; + vassert((cins & 0x00200000) == 0); + + operation = (cins & 0x03FC0000) >> 18; + df = (cins & 0x00030000) >> 16; + ty = mode64 ? Ity_I64 : Ity_I32; 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 0xC0: { /* FILL.df */ + t1 = newTemp(Ity_I64); - 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; - } + 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; - default: - return -1; - } + 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; - 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; } - 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; - } + putWReg(wd, + binop(Iop_64HLtoV128, mkexpr(t1), mkexpr(t1))); + 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; - } + 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; - default: - return -1; - } + 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; - 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; } - 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; - } + 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; - } + 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; - default: - return -1; - } + case 0x01: /* NLOC.H */ + DIP("NLOC.H w%d, w%d", wd, ws); + putWReg(wd, + unop(Iop_Cls16x8, getWReg(ws))); + break; - 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; } - 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; - } + 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; - } + 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; - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; + } + + return 0; +} + +static Int msa_2RF(UInt cins, UChar wd, UChar ws) /* 2RF */ +{ + IRTemp t1, t2, t3, t4, t5; + UShort operation; + UChar df, wt; - default: - return -1; - } + operation = (cins & 0x03FE0000) >> 17; + df = (cins & 0x00010000) >> 16; + wt = (cins & 0x001F0000) >> 16; - break; - } + switch (operation) { - 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 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); - 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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, + 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_CmpEQ32Fx4, - getWReg(ws), - getWReg(wt)), - binop(Iop_CmpUN32Fx4, - getWReg(ws), - getWReg(wt)))); - break; - } + 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: { /* FSUEQ.D */ - DIP("FSUEQ.D w%d, w%d, w%d", wd, ws, wt); - calculateMSACSR(ws, wt, FSUEQD, 2); - putWReg(wd, + 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_CmpEQ64Fx2, - getWReg(ws), - getWReg(wt)), - binop(Iop_CmpUN64Fx2, - getWReg(ws), - getWReg(wt)))); - break; - } + 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; + 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; } - 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; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - default: - return -1; - } + break; + } - return 0; -} + 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; + } -static Int msa_3R_1B(UInt cins, UChar wd, UChar ws) { /* 3R (0x1B) */ - IRTemp t1, t2, t3, t4; - UShort operation; - UChar df, wt; + 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; + } - operation = (cins & 0x03C00000) >> 22; - df = (cins & 0x00200000) >> 21; - wt = (cins & 0x001F0000) >> 16; + default: + return -1; + } - 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; - } + 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; - } + 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; + } - default: - return -1; + 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; } - break; + default: + return -1; } - 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; - } + 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; - } + case 0x19E: { /* FFINT_S.df */ + t1 = newTemp(Ity_V128); + assign(t1, getWReg(ws)); + IRExpr *rm = get_IR_roundingmode_MSA(); - default: - return -1; - } + 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)))); + } - break; - } + 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 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: { /* FFINT_S.D */ + DIP("FFINT_S.D w%d, w%d", wd, ws); + calculateMSACSR(ws, wt, FFINTSD, 1); + IRTemp tmp[2]; + Int i; - 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; - } + 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)))); + } - default: - return -1; + putWReg(wd, + binop(Iop_64HLtoV128, + unop(Iop_ReinterpF64asI64, + mkexpr(tmp[1])), + unop(Iop_ReinterpF64asI64, + mkexpr(tmp[0])))); + break; } - break; + default: + return -1; } - 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; - } + 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; - } + case 0x19F: { /* FFINT_U.df */ + IRExpr *rm = get_IR_roundingmode_MSA(); - default: - return -1; + 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; } - 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; } - 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; + break; + } - 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))))); - } + default: + return -1; + } - 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; - } + return 0; +} - 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; +static Int msa_MI10_load(UInt cins, UChar wd, UChar ws) /* MI10 (0x20) */ +{ + IRTemp t1; + UShort i10; + UChar df; - 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))))); - } + i10 = (cins & 0x03FF0000) >> 16; + df = cins & 0x00000003; - putWReg(wd, - binop(Iop_64HLtoV128, - unop(Iop_ReinterpF64asI64, - mkexpr(tmp[1])), - unop(Iop_ReinterpF64asI64, - mkexpr(tmp[0])))); - break; - } + 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; + } - default: - return -1; - } + 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; + } - 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 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; + 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; + } - 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))))); - } + default: + return -1; + } - 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; - } + return 0; +} - 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; +static Int msa_MI10_store(UInt cins, UChar wd, UChar ws) /* MI10 (0x24) */ +{ + IRTemp t1; + UShort i10; + UChar df; - 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))))); - } + df = cins & 0x00000003; + i10 = (cins & 0x03FF0000) >> 16; - putWReg(wd, - binop(Iop_64HLtoV128, - unop(Iop_ReinterpF64asI64, - mkexpr(tmp[1])), - unop(Iop_ReinterpF64asI64, - mkexpr(tmp[0])))); - break; - } + 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; + } - default: - return -1; - } + 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; + } - 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 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 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; + } - 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; + } - default: - return -1; - } + return 0; +} - break; - } +/*------------------------------------------------------------*/ +/*--- 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; - 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; - } + vassert(has_msa); + vassert((cins & 0xFC000000) == 0x78000000); - 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; - } + minor_opcode = (cins & 0x20) > 0 ? (cins & 0x3C) : (cins & 0x3F); + wd = (cins & 0x000007C0) >> 6; + ws = (cins & 0x0000F800) >> 11; - default: - return -1; - } + switch (minor_opcode) { + case 0x0: + return msa_I8_logical(cins, wd, ws); - break; - } + case 0x01: + return msa_I8_branch(cins, wd, ws); - 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 0x02: + return msa_I8_shift(cins, wd, ws); - 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; - } + case 0x06: + return msa_I5_06(cins, wd, ws); - default: - return -1; - } + case 0x07: + return msa_I5_07(cins, wd, ws); - break; - } + case 0x09: + return msa_BIT_09(cins, wd, ws); - 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 0x0A: + return msa_BIT_0A(cins, wd, ws); - 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; - } + case 0x0D: + return msa_3R_0D(cins, wd, ws); - default: - return -1; - } + case 0x0E: + return msa_3R_0E(cins, wd, ws); - break; - } + case 0x0F: + return msa_3R_0F(cins, wd, ws); - 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 0x10: + return msa_3R_10(cins, wd, ws); - 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; - } + case 0x11: + return msa_3R_11(cins, wd, ws); - default: - return -1; - } + case 0x12: + return msa_3R_12(cins, wd, ws); - break; - } + case 0x13: + return msa_3R_13(cins, wd, ws); - 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 0x14: + return msa_3R_14(cins, wd, ws); - 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; - } + case 0x15: + return msa_3R_15(cins, wd, ws); - default: - return -1; - } + case 0x19: + return msa_ELM(cins, wd, ws); - break; - } + case 0x1A: + return msa_3R_1A(cins, wd, ws); - 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 0x1B: + return msa_3R_1B(cins, wd, ws); - 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; - } + case 0x1C: + return msa_3R_1C(cins, wd, ws); - default: - return -1; - } + 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); - break; - } + case 0x20: + return msa_MI10_load(cins, wd, ws); - default: - return -1; + case 0x24: + return msa_MI10_store(cins, wd, ws); } - return 0; + return -1; } -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; +/*------------------------------------------------------------*/ +/*--- DSP to IR function ---*/ +/*------------------------------------------------------------*/ - operation = (cins & 0x03C00000) >> 22; - df = (cins & 0x00200000) >> 21; - wt = (cins & 0x001F0000) >> 16; +extern UInt disDSPInstr_MIPS_WRK ( UInt ); - 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; - } +/*------------------------------------------------------------*/ +/*--- Disassemble a single instruction ---*/ +/*------------------------------------------------------------*/ - 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; - } +/* 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. */ - default: - return -1; + +static UInt disInstr_MIPS_WRK_Special(UInt cins, const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, DisResult* dres, + IRStmt** bstmt, IRExpr** lastn, + Bool(*resteerOkFn) (/*opaque */void *, + Addr), + void* callback_opaque) +{ + 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); - break; - } + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); - 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; - } + assign(t1, binop(Iop_And64, getIReg(rt), /* hi */ + mkU64(0xFFFFFFFF00000000ULL))); - 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; - } + assign(t2, binop(Iop_Sar64, mkexpr(t1), mkU8(sa))); - default: - return -1; - } + assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt))); + assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkU8(sa))); - break; + putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True)); + } else { + SXX_PATTERN(Iop_Sar32); } - 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; - } + break; - default: - return -1; - } + case 0x04: { /* SLLV */ + DIP("sllv r%u, r%u, r%u", rd, rt, rs); - break; + 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); } - 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; - } + 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; - } + case 0x05: { /* LSA */ + UInt imm2 = (imm & 0xC0) >> 6; - default: - return -1; - } + 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 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 0x06: { /* SRLV */ + rot = get_rotv(cins); - 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; - } + 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); - default: - return -1; + if (mode64) { + SXXV_PATTERN64(Iop_Shr32); + } else { + SXXV_PATTERN(Iop_Shr32); } 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 0x07: /* SRAV */ + DIP("srav r%u, r%u, r%u", rd, rt, rs); - 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; - } + if (mode64) { + IRTemp tmpRt32 = newTemp(Ity_I32); + IRTemp tmpSh32 = newTemp(Ity_I32); - default: - return -1; - } + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I8); - break; - } + assign(t4, unop(Iop_32to8, binop(Iop_And32, + mkNarrowTo32(ty, getIReg(rs)), mkU32(0x0000001F)))); - 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; - } + assign(t1, binop(Iop_And64, getIReg(rt), /* hi */ + mkU64(0xFFFFFFFF00000000ULL))); - 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; - } + assign(t2, binop(Iop_Sar64, mkexpr(t1), mkexpr(t4))); - default: - return -1; - } + assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt))); + assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkexpr(t4))); - break; + putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True)); + } else { + SXXV_PATTERN(Iop_Sar32); } - 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; - } + 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; - } + case 0x08: /* JR */ + DIP("jr r%u", rs); + t0 = newTemp(ty); + assign(t0, getIReg(rs)); + *lastn = mkexpr(t0); + break; - default: - return -1; - } + case 0x09: /* JALR */ + DIP("jalr r%u r%u", rd, rs); - break; + 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); } - 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; - } + 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; - } + case 0x0A: { /* MOVZ */ + DIP("movz r%u, r%u, r%u", rd, rs, rt); + t1 = newTemp(ty); + t2 = newTemp(ty); - default: - return -1; - } + 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; + 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)))); } - 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; - } + 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; - } + case 0x0C: /* SYSCALL */ + DIP("syscall"); - default: - return -1; - } + if (mode64) + putPC(mkU64(guest_PC_curr_instr + 4)); + else + putPC(mkU32(guest_PC_curr_instr + 4)); - break; - } + dres->jk_StopHere = Ijk_Sys_syscall; + dres->whatNext = Dis_StopHere; + 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 0x0D: /* BREAK */ + DIP("break 0x%x", trap_code); - 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; - } + if (mode64) + jmp_lit64(dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4)); + else + jmp_lit32(dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4)); - default: - return -1; - } + vassert(dres->whatNext == Dis_StopHere); + break; - break; - } + case 0x0F: /* SYNC */ + DIP("sync 0x%x", sel); + /* Just ignore it. */ + 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 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); - 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; - } + if (mode64) { + IRTemp tmpClz32 = newTemp(Ity_I32); + IRTemp tmpRs32 = newTemp(Ity_I32); - default: - return -1; + 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 ); - default: - return -1; - } + if (0 != retVal ) { + return -1; + } - return 0; -} + break; + } else { + DIP("mfhi r%u", rd); + putIReg(rd, getHI()); + break; + } + } -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; + 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); - operation = (cins & 0x03C00000) >> 22; - ty = mode64 ? Ity_I64 : Ity_I32; + if (mode64) { + IRTemp tmpClo32 = newTemp(Ity_I32); + IRTemp tmpRs32 = newTemp(Ity_I32); + assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); - switch ((cins & 0x03FF0000) >> 16) { - case 0x07E: /* CFCMSA */ - DIP("CFCMSA r%d, c%d", wd, ws); + 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))))); - 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)); + 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; + } - case 1: /* MSACSR */ - putIReg(wd, - mkWidenFrom32(ty, getMSACSR(), True)); - break; + break; + } else if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + /* If DSP is present -> DSP ASE MTHI */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - default: - putIReg(wd, - mkWidenFrom32(ty, mkU32(0), False)); - break; - } + if (0 != retVal ) { + return -1; + } - break; + break; + } else { + DIP("mthi r%u", rs); + putHI(getIReg(rs)); + break; + } + } - case 0x03E: /* CTCMSA */ - DIP("CTCMSA r%d, c%d", ws, wd); + case 0x12: { /* MFLO */ + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + /* If DSP is present -> DSP ASE MFLO */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (wd == 1) { /* MSACSR */ - putMSACSR( - binop(Iop_And32, mkNarrowTo32(ty, getIReg(ws)), - mkU32(0x1FFFFFF))); - } + if (0 != retVal ) { + return -1; + } - break; + break; + } else { + switch (sa) { + case 0: + DIP("mflo r%u", rd); - case 0x0BE: /* MOVE.V */ - DIP("MOVE.V w%d, w%d", ws, wd); - putWReg(wd, getWReg(ws)); - break; + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - 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; - } + putIReg(rd, getLO()); + break; - 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 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; + } - case 0x20: /* SLDI.H */ - DIP("SLDI.H w%d, w%d[%d]", wd, ws, n); + break; + } + } - 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))); - } + case 0x13: { /* MTLO */ + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + /* If DSP is present -> DSP ASE MTLO */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - break; + if (0 != retVal ) { + return -1; + } - case 0x30: /* SLDI.W */ - DIP("SLDI.W w%d, w%d[%d]", wd, ws, n); + break; + } else { + switch (sa) { + case 0: + DIP("mtlo r%u", rs); - 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))); - } + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - break; + putLO(getIReg(rs)); + break; - case 0x38: /* SLDI.D */ - DIP("SLDI.D w%d, w%d[%d]", wd, ws, n); + 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; + } - 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; + } + } - break; + case 0x15: { /* DLSA */ + UInt imm2 = (imm & 0xC0) >> 6; - default: - return -1; - } + 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; + 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); + 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 (n & 1) - assign(t1, - binop(Iop_InterleaveOddLanes8x16, - getWReg(ws), - getWReg(ws))); - else - assign(t1, - binop(Iop_InterleaveEvenLanes8x16, - getWReg(ws), - getWReg(ws))); + if (0 != retVal) { + return -2; + } - n /= 2; + break; + } else { + return -2; + } + } else { + DIP("mult r%u, r%u", rs, rt); - if (n & 1) - assign(t2, - binop(Iop_InterleaveOddLanes16x8, - mkexpr(t1), mkexpr(t1))); - else - assign(t2, - binop(Iop_InterleaveEvenLanes16x8, - mkexpr(t1), mkexpr(t1))); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - n /= 2; + t2 = newTemp(Ity_I64); - if (n & 1) - assign(t3, - binop(Iop_InterleaveOddLanes32x4, - mkexpr(t2), mkexpr(t2))); - else - assign(t3, - binop(Iop_InterleaveEvenLanes32x4, - mkexpr(t2), mkexpr(t2))); + assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - n /= 2; + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); + break; + } + } - if (n & 1) - assign(t4, - binop(Iop_InterleaveHI64x2, - mkexpr(t3), mkexpr(t3))); - else - assign(t4, - binop(Iop_InterleaveLO64x2, - mkexpr(t3), mkexpr(t3))); + case 2: { /* MUL R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("mul r%u, r%u, r%u", rs, rt, rd); - putWReg(wd, mkexpr(t4)); - break; - } + 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; + } - 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); + break; + } - if (n & 1) - assign(t1, - binop(Iop_InterleaveOddLanes16x8, - getWReg(ws), - getWReg(ws))); - else - assign(t1, - binop(Iop_InterleaveEvenLanes16x8, - getWReg(ws), - getWReg(ws))); + case 3: { /* MUH R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("muh r%u, r%u, r%u", rs, rt, rd); - n /= 2; + 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; + } - if (n & 1) - assign(t2, - binop(Iop_InterleaveOddLanes32x4, - mkexpr(t1), mkexpr(t1))); - else - assign(t2, - binop(Iop_InterleaveEvenLanes32x4, - mkexpr(t1), mkexpr(t1))); + break; + } + } - n /= 2; + break; + } - if (n & 1) - assign(t3, - binop(Iop_InterleaveHI64x2, - mkexpr(t2), mkexpr(t2))); - else - assign(t3, - binop(Iop_InterleaveLO64x2, - mkexpr(t2), mkexpr(t2))); + 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 ); - putWReg(wd, mkexpr(t3)); - break; + if (0 != retVal) { + return -2; } - 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)); + break; + } else { + return -2; + } + } else { + DIP("multu r%u, r%u", rs, rt); - if (n & 1) - assign(t2, - binop(Iop_InterleaveOddLanes32x4, - mkexpr(t1), mkexpr(t1))); - else - assign(t2, - binop(Iop_InterleaveEvenLanes32x4, - mkexpr(t1), mkexpr(t1))); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - n /= 2; + t2 = newTemp(Ity_I64); - if (n & 1) - assign(t3, - binop(Iop_InterleaveHI64x2, - mkexpr(t2), mkexpr(t2))); - else - assign(t3, - binop(Iop_InterleaveLO64x2, - mkexpr(t2), mkexpr(t2))); + assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - putWReg(wd, mkexpr(t3)); - break; - } + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); + 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)); + case 2: { /* MULU R6 */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("mulu r%u, r%u, r%u", rs, rt, rd); - if (n) - assign(t3, - binop(Iop_InterleaveHI64x2, - mkexpr(t1), mkexpr(t1))); - else - assign(t3, - binop(Iop_InterleaveLO64x2, - mkexpr(t1), mkexpr(t1))); + 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; + } - putWReg(wd, mkexpr(t3)); - break; + break; + } - default: - return -1; + 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; + } + } - 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); + break; + } - switch (n) { - case 0: - assign(t1, - unop(Iop_32to8, - unop(Iop_V128to32, - getWReg(ws)))); - break; + case 0x1A: /* DIV */ + switch (sa & 0x3) { + case 0: + DIP("div r%u, r%u", rs, rt); - case 1: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_V128to32, - getWReg(ws))))); - break; + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - case 2: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + if (mode64) { + t2 = newTemp(Ity_I64); - case 3: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + assign(t2, binop(Iop_DivModS32to32, + mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - case 4: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); + } else { + t1 = newTemp(Ity_I64); - case 5: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt))); - case 6: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + putHI(unop(Iop_64HIto32, mkexpr(t1))); + putLO(unop(Iop_64to32, mkexpr(t1))); + } - case 7: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + break; - case 8: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + case 2: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("div r%u, r%u, r%u", rs, rt, rd); - case 9: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + 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 + } - case 10: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + break; - case 11: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + case 3: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("mod r%u, r%u, r%u", rs, rt, rd); - case 12: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + 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); - case 13: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + assign(t1, binop(Iop_DivModS32to32, getIReg(rs), getIReg(rt))); + putIReg(rd, unop(Iop_64HIto32, mkexpr(t1))); + } + } else { + ILLEGAL_INSTRUCTON + } - case 14: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + break; + } - case 15: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; - } + break; - putIReg(wd, - unop(mode64 ? Iop_8Sto64 : Iop_8Sto32, - mkexpr(t1))); - break; + case 0x1B: /* DIVU */ + switch (sa & 0x3) { + case 0: + DIP("divu r%u, r%u", rs, rt); - case 0x20: /* COPY_S.H */ - DIP("COPY_S.H r%d, w%d[%d]", wd, ws, n); - t1 = newTemp(Ity_I16); + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - switch (n) { - case 0: - assign(t1, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + if (mode64) { + t1 = newTemp(Ity_I64); - case 1: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + assign(t1, binop(Iop_DivModU32to32, + mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - case 2: - assign(t1, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t1)), True)); + putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t1)), True)); + } else { + t1 = newTemp(Ity_I64); - case 3: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + assign(t1, binop(Iop_DivModU32to32, getIReg(rs), getIReg(rt))); + putHI(unop(Iop_64HIto32, mkexpr(t1))); + putLO(unop(Iop_64to32, mkexpr(t1))); + } - case 4: - assign(t1, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; + break; - case 5: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; + case 2: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("divu r%u, r%u, r%u", rs, rt, rd); - case 6: - assign(t1, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; + 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))); + } - case 7: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; - } + break; + } else { + ILLEGAL_INSTRUCTON + } - putIReg(wd, - unop(mode64 ? Iop_16Sto64 : Iop_16Sto32, - mkexpr(t1))); - break; + break; - case 0x30: /* COPY_S.W */ - DIP("COPY_S.W r%d, w%d[%d]", wd, ws, n); + case 3: + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("modu r%u, r%u, r%u", rs, rt, rd); - switch (n) { - case 0: - putIReg(wd, - mkWidenFrom32(ty, - unop(Iop_V128to32, - getWReg(ws)), - True)); - break; + 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 + } - case 1: - t2 = newTemp(Ity_I64); - assign(t2, - unop(Iop_V128to64, getWReg(ws))); - putIReg(wd, - mkWidenFrom32(ty, - unop(Iop_64HIto32, - mkexpr(t2)), - True)); - break; + 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; + 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; + case 0x1C: /* Doubleword Multiply - DMULT; MIPS64 */ + switch (sa) { + case 0: + DIP("dmult r%u, r%u", rs, rt); - default: - break; - } + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - break; + t0 = newTemp(Ity_I128); - case 0x38: /* COPY_S.D */ - if (mode64) { - DIP("COPY_S.D r%d, w%d[%d]", wd, ws, n); + assign(t0, binop(Iop_MullS64, getIReg(rs), getIReg(rt))); - switch (n) { - case 0: - putIReg(wd, - unop(Iop_V128to64, - getWReg(ws))); - break; + putHI(unop(Iop_128HIto64, mkexpr(t0))); + putLO(unop(Iop_128to64, mkexpr(t0))); + break; - case 1: - putIReg(wd, - unop(Iop_V128HIto64, - getWReg(ws))); - break; - } - } else { - return -2; - } + 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; + break; - default: - return -1; + 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; + } - 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); + break; - switch (n) { - case 0: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + case 0x1D: /* Doubleword Multiply Unsigned - DMULTU; MIPS64 */ + switch (sa) { + case 0: + DIP("dmultu r%u, r%u", rs, rt); - case 1: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - case 2: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + t0 = newTemp(Ity_I128); - case 3: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + assign(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt))); - case 4: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + putHI(unop(Iop_128HIto64, mkexpr(t0))); + putLO(unop(Iop_128to64, mkexpr(t0))); + break; - case 5: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - 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 + } - case 6: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - break; + break; - case 7: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws)))))); - 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 + } - case 8: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + break; + } - case 9: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + break; - case 10: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + case 0x1E: /* Doubleword Divide DDIV; MIPS64 */ + switch (sa) { + case 0: + DIP("ddiv r%u, r%u", rs, rt); - case 11: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - case 12: - assign(t1, - unop(Iop_16to8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + t1 = newTemp(Ity_I128); - case 13: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + assign(t1, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt))); - case 14: - assign(t1, - unop(Iop_16to8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - break; + putHI(unop(Iop_128HIto64, mkexpr(t1))); + putLO(unop(Iop_128to64, mkexpr(t1))); + break; - case 15: - assign(t1, - unop(Iop_16HIto8, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws)))))); - 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 + } - putIReg(wd, - unop(mode64 ? Iop_8Uto64 : Iop_8Uto32, - mkexpr(t1))); - break; + break; - case 0x20: /* COPY_U.H */ - DIP("COPY_U.H r%d, w%d[%d]", wd, ws, n); - t1 = newTemp(Ity_I16); + 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 + } - switch (n) { - case 0: - assign(t1, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + break; + } - case 1: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + break; - case 2: - assign(t1, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + case 0x1F: /* Doubleword Divide Unsigned DDIVU; MIPS64 check this */ + switch (sa) { + case 0: + DIP("ddivu r%u, r%u", rs, rt); - case 3: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128to64, - getWReg(ws))))); - break; + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps) && + !VEX_MIPS_CPU_HAS_MIPS32R2(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - case 4: - assign(t1, - unop(Iop_32to16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; + t1 = newTemp(Ity_I128); - case 5: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64to32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; + assign(t1, binop(Iop_DivModU64to64, getIReg(rs), getIReg(rt))); - case 6: - assign(t1, - unop(Iop_32to16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws))))); - break; + putHI(unop(Iop_128HIto64, mkexpr(t1))); + putLO(unop(Iop_128to64, mkexpr(t1))); + break; - case 7: - assign(t1, - unop(Iop_32HIto16, - unop(Iop_64HIto32, - unop(Iop_V128HIto64, - getWReg(ws))))); - 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 + } - putIReg(wd, - unop(mode64 ? Iop_16Uto64 : Iop_16Uto32, - mkexpr(t1))); - break; + break; - case 0x30: /* COPY_U.W */ - DIP("COPY_U.W r%d, w%d[%d]", wd, ws, n); + 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 + } - switch (n) { - case 0: - putIReg(wd, - mkWidenFrom32(ty, - unop(Iop_V128to32, - getWReg(ws)), - False)); - break; + 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; + 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 0x20: { /* ADD */ + DIP("add r%u, r%u, r%u", rd, rs, rt); + IRTemp tmpRs32 = newTemp(Ity_I32); + IRTemp tmpRt32 = newTemp(Ity_I32); - case 3: - t2 = newTemp(Ity_I64); - assign(t2, - unop(Iop_V128HIto64, - getWReg(ws))); - putIReg(wd, - mkWidenFrom32(ty, - unop(Iop_64HIto32, - mkexpr(t2)), - False)); - break; + assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); + assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt))); - default: - break; - } + 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! */ - break; + 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)))); - default: - return -1; - } + 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)))); - break; - } + 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)); - 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); + putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True)); + break; + } - 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)))); - } + case 0x21: /* ADDU */ + DIP("addu r%u, r%u, r%u", rd, rs, rt); - 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))); - } + if (mode64) { + ALU_PATTERN64(Iop_Add32); + } else { + ALU_PATTERN(Iop_Add32); + } - switch (df) { - case 0x00: /* INSERT.B */ - DIP("INSERT.B w%d[%d], r%d", wd, n, ws); + break; - if (n >= 8) { - n -= 8; - } else { - hi = 0; - } + case 0x22: { /* SUB */ + DIP("sub r%u, r%u, r%u", rd, rs, rt); + IRTemp tmpRs32 = newTemp(Ity_I32); + IRTemp tmpRt32 = newTemp(Ity_I32); - n <<= 3; - mask = 0xFFull; - break; + 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! */ - case 0x20: /* INSERT.H */ - DIP("INSERT.H w%d[%d], r%d", wd, n, ws); + 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)))); - if (n >= 4) { - n -= 4; - } else { - hi = 0; - } + 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)))); - n <<= 4; - mask = 0xFFFFull; - break; + 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)); - case 0x30: /* INSERT.W */ - DIP("INSERT.W w%d[%d], r%d", wd, n, ws); + putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True)); + break; + } - if (n >= 2) { - n -= 2; - } else { - hi = 0; - } + case 0x23: /* SUBU */ + DIP("subu r%u, r%u, r%u", rd, rs, rt); - n <<= 5; - mask = 0xFFFFFFFFull; - break; + if (mode64) { + ALU_PATTERN64(Iop_Sub32); + } else { + ALU_PATTERN(Iop_Sub32); + } - default: - return -1; - } + break; - if (hi) { - t4 = newTemp(Ity_I64); - src = &t2; - dst = &t4; - t3 = t1; - } else { - t3 = newTemp(Ity_I64); - src = &t1; - dst = &t3; - t4 = t2; - } + case 0x24: /* AND */ + DIP("and r%u, r%u, r%u", rd, rs, rt); - 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; - } + if (mode64) { + ALU_PATTERN(Iop_And64); + } else { + ALU_PATTERN(Iop_And32); + } - 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))); - } + break; - 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 0x25: /* OR */ + DIP("or r%u, r%u, r%u", rd, rs, rt); - 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]; + if (mode64) { + ALU_PATTERN(Iop_Or64); + } else { + ALU_PATTERN(Iop_Or32); + } - for (i = 0; i < 8; i++) { - tmp[i] = newTemp(Ity_I16); + break; - if (n == i) - assign(tmp[i], - binop(Iop_GetElem16x8, - mkexpr(t2), mkU8(0x0))); - else - assign(tmp[i], - binop(Iop_GetElem16x8, - mkexpr(t1), mkU8(i))); - } + case 0x26: /* XOR */ + DIP("xor r%u, r%u, r%u", rd, rs, rt); - 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; - } + if (mode64) { + ALU_PATTERN(Iop_Xor64); + } else { + ALU_PATTERN(Iop_Xor32); + } - 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]; + break; - for (i = 0; i < 4; i++) { - tmp[i] = newTemp(Ity_I32); + case 0x27: /* NOR */ + DIP("nor r%u, r%u, r%u", rd, rs, rt); - if (n == i) - assign(tmp[i], - binop(Iop_GetElem32x4, - mkexpr(t2), mkU8(0x0))); - else - assign(tmp[i], - binop(Iop_GetElem32x4, - mkexpr(t1), mkU8(i))); - } + 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)))); - putWReg(wd, - binop(Iop_64HLtoV128, - binop(Iop_32HLto64, - mkexpr(tmp[3]), - mkexpr(tmp[2])), - binop(Iop_32HLto64, - mkexpr(tmp[1]), - mkexpr(tmp[0])))); - break; - } + 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]; + case 0x2A: /* SLT */ + DIP("slt r%u, r%u, r%u", rd, rs, rt); - for (i = 0; i < 2; i++) { - tmp[i] = newTemp(Ity_I64); + 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)))); - if (n == i) - assign(tmp[i], - binop(Iop_GetElem64x2, - mkexpr(t2), mkU8(0x0))); - else - assign(tmp[i], - binop(Iop_GetElem64x2, - mkexpr(t1), mkU8(i))); - } + break; - putWReg(wd, - binop(Iop_64HLtoV128, - mkexpr(tmp[1]), mkexpr(tmp[0]))); - break; - } - } + case 0x2B: /* SLTU */ + DIP("sltu r%u, r%u, r%u", rd, rs, rt); - break; - } + 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)))); - default: - return -1; - } - } - return 0; -} + break; -static Int msa_VEC(UInt cins, UChar wd, UChar ws) { /* VEC */ - IRTemp t1, t2, t3; - UShort operation; - UChar wt; + 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); - vassert((cins & 0x03000000) == 0); + assign(tmpRs64, getIReg(rs)); + assign(tmpRt64, getIReg(rt)); - operation = (cins & 0x03E00000) >> 21; - wt = (cins & 0x001F0000) >> 16; + 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! */ - 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; - } + 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)))); - 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; - } + 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)))); - 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; - } + 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)); - 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; - } + putIReg(rd, mkexpr(t0)); + 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 0x2D: /* Doubleword Add Unsigned - DADDU; MIPS64 */ + DIP("daddu r%u, r%u, r%u", rd, rs, rt); + ALU_PATTERN(Iop_Add64); + 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 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); - 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; - } + 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! */ - default: - return -1; - } + 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)))); - return 0; -} + 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)))); -static Int msa_2R(UInt cins, UChar wd, UChar ws) { /* 2R */ - IRTemp t1, t2, t3, t4; - IRType ty; - UShort operation; - UChar df; + 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)); - vassert((cins & 0x00200000) == 0); + putIReg(rd, binop(Iop_Sub64, getIReg(rs), getIReg(rt))); + break; + } - operation = (cins & 0x03FC0000) >> 18; - df = (cins & 0x00030000) >> 16; - ty = mode64 ? Ity_I64 : Ity_I32; + case 0x2F: /* Doubleword Subtract Unsigned - DSUBU; MIPS64 */ + DIP("dsub r%u, r%u,r%u", rd, rt, rt); + ALU_PATTERN(Iop_Sub64); + break; - switch (operation) { - case 0xC0: { /* FILL.df */ - t1 = newTemp(Ity_I64); + case 0x30: { /* TGE */ + DIP("tge r%u, r%u %u", rs, rt, trap_code); - 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; + 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)); + } - 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; + 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 0x31: { /* TGEU */ + DIP("tgeu r%u, r%u %u", rs, rt, trap_code); - 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; - } + 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; + break; + } - default: - return -1; - } + case 0x32: { /* TLT */ + DIP("tlt r%u, r%u %u", rs, rt, trap_code); - putWReg(wd, - binop(Iop_64HLtoV128, mkexpr(t1), mkexpr(t1))); - break; + 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)); } - 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; + 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 0x33: { /* TLTU */ + DIP("tltu r%u, r%u %u", rs, rt, trap_code); - 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; + 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)); + } - 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; + break; + } - default: - return -1; - } + case 0x34: { /* TEQ */ + DIP("teq r%u, r%u, %u", rs, rt, trap_code); - break; + 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)); } - 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; + 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; + case 0x35: { /* SELEQZ */ + if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + DIP("seleqz r%u, r%u, r%u", rd, rs, rt); - default: - return -1; + 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))); } - - break; + } else { + ILLEGAL_INSTRUCTON; } - 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; + break; + } - case 0x01: /* NLZC.H */ - DIP("NLZC.H w%d, w%d", wd, ws); - putWReg(wd, - unop(Iop_Clz16x8, getWReg(ws))); - break; + case 0x36: { /* TNE */ + DIP("tne r%u, r%u %u", rs, rt, trap_code); - case 0x02: /* NLZC.W */ - DIP("NLZC.W w%d, w%d", wd, ws); - putWReg(wd, - unop(Iop_Clz32x4, getWReg(ws))); - break; + 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)); + } - case 0x03: {/* NLZC.D */ - putWReg(wd, - unop(Iop_Clz64x2, getWReg(ws))); - break; - } + break; + } - default: - return -1; + 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; @@ -24504,1277 +18369,481 @@ static Int msa_2R(UInt cins, UChar wd, UChar ws) { /* 2R */ 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; +static UInt disInstr_MIPS_WRK_Special2(UInt cins, const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, DisResult* dres, + IRStmt** bstmt, IRExpr** lastn, + Bool(*resteerOkFn) (/*opaque */void *, + Addr), + void* callback_opaque) +{ + 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; - switch (operation) { + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + function = get_function(cins); + IRType ty = mode64 ? Ity_I64 : Ity_I32; - 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); + ac = get_acNo(cins); - 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; - } + switch (function) { + /* Cavium Specific instructions */ + case 0x03: + case 0x32: + case 0x33: /* DMUL, CINS , CINS32 */ + case 0x3A: + case 0x3B: + case 0x2B: /* EXT, EXT32, SNE */ - 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; - } + /* CVM Compare Instructions */ + case 0x2A: + case 0x2E: + case 0x2F: /* SEQ, SEQI, SNEI */ - default: - return -1; - } + /* 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; - break; + return -1; + } else { + return -1; } - 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; - break; - } + case 0x02: { /* MUL */ + DIP("mul r%u, r%u, r%u", rd, rs, rt); - 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; - } + if (mode64) { + IRTemp tmpRs32 = newTemp(Ity_I32); + IRTemp tmpRt32 = newTemp(Ity_I32); + IRTemp tmpRes = newTemp(Ity_I32); - 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; - } + 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))); - default: - return -1; - } + break; + } - 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); - 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; - } + assign(t1, mkNarrowTo32(ty, getHI())); + assign(t2, mkNarrowTo32(ty, getLO())); - 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; - } + assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - default: - return -1; - } + assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); + assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); - break; - } + 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 ); - 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; + if (0 != retVal ) { + return -2; } - 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; - } + 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); - default: - return -1; - } + assign(t1, getHI()); + assign(t2, getLO()); - break; - } + assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); - 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; - } + assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32, + mkexpr(t3)))); - 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; - } + assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4), + unop(Iop_64to32, mkexpr(t3))))); + assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1))); - default: - return -1; + putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, + mkexpr(t3)))); + putLO(mkexpr(t4)); + break; } - - 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)); + break; + } - 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; + 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); - 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)))))); - } + assign(t1, mkNarrowTo32(ty, getHI())); + assign(t2, mkNarrowTo32(ty, getLO())); - 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; - } + assign(t3, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - 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; + assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); + assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); - 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)))))); - } + 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 ); - 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; + if (0 != retVal ) { + return -2; } - default: - return -1; - } - - break; - } + 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); - case 0x197: { /* FLOG2.df */ + assign(t1, getHI()); + assign(t2, getLO()); - 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; - } + assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); - 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; - } + 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))); - default: - return -1; + putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, + mkexpr(t3)))); + putLO(mkexpr(t4)); + break; } - - 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; - } + 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 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); - 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; - } + assign(t1, mkNarrowTo32(ty, getHI())); + assign(t2, mkNarrowTo32(ty, getLO())); - default: - return -1; - } + assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), + mkNarrowTo32(ty, getIReg(rt)))); - break; - } + assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); + assign(t5, binop(Iop_Sub64, mkexpr(t4), mkexpr(t3))); - 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; - } + 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 ); - 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; + if (0 != retVal ) { + return -2; } - default: - return -1; - } + 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); - break; - } + assign(t1, getHI()); + assign(t2, getLO()); - 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; - } + assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ - 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; - } + /* if lo= ac) ) { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + /* If DSP is present -> DSP ASE MSUBU */ + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - default: - return -1; - } + if (0 != retVal ) { + return -2; + } - break; - } + 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); - case 0x19E: { /* FFINT_S.df */ - t1 = newTemp(Ity_V128); - assign(t1, getWReg(ws)); - IRExpr *rm = get_IR_roundingmode_MSA(); + assign(t1, getHI()); + assign(t2, getLO()); - 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; + assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ - 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)))); - } + /* if lo> 16; - df = cins & 0x00000003; + case 0x14: /* SWAPW - Swap Word - Netlogic */ + DIP("swapw r%u, r%u", rt, rs); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + assign(t0, mkNarrowTo32(ty, getIReg(rt))); + assign(t1, load(Ity_I32, getIReg(rs))); + putIReg(rt, mkWidenFrom32(ty, mkexpr(t1), True)); + store(getIReg(rs), mkexpr(t0)); + break; - 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 0x16: /* SWAPD - Swap Double - Netlogic */ + DIP("swapw r%u, r%u", rt, rs); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + assign(t0, getIReg(rt)); + assign(t1, load(Ity_I64, getIReg(rs))); + putIReg(rt, mkexpr(t1)); + store(getIReg(rs), mkexpr(t0)); + 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 0x20: { /* CLZ */ + DIP("clz r%u, r%u", rd, rs); - 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; - } + if (mode64) { + IRTemp tmpClz32 = newTemp(Ity_I32); + IRTemp tmpRs32 = newTemp(Ity_I32); - 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; + 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)))); } - default: - return -1; - } + break; + } - return 0; -} + case 0x21: { /* CLO */ + DIP("clo r%u, r%u", rd, rs); -static Int msa_MI10_store(UInt cins, UChar wd, UChar ws) { /* MI10 (0x24) */ - IRTemp t1; - UShort i10; - UChar df; + if (mode64) { + IRTemp tmpClo32 = newTemp(Ity_I32); + IRTemp tmpRs32 = newTemp(Ity_I32); + assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); - df = cins & 0x00000003; - i10 = (cins & 0x03FF0000) >> 16; + 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))))); - 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)); + putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClo32), True)); 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 + } 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))))); 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 0x24: /* Count Leading Zeros in Doubleword - DCLZ; MIPS64 */ + 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; - 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; - } + case 0x25: /* Count Leading Ones in Doubleword - DCLO; MIPS64 */ + 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; default: return -1; @@ -25783,7536 +18852,6177 @@ static Int msa_MI10_store(UInt cins, UChar wd, UChar ws) { /* MI10 (0x24) */ 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); +static UInt disInstr_MIPS_WRK_Special3(UInt cins, const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, DisResult* dres, + IRStmt** bstmt, IRExpr** lastn, + Bool(*resteerOkFn) (/*opaque */void *, + Addr), + void* callback_opaque) - case 0x0D: - return msa_3R_0D(cins, wd, ws); +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6; + UInt rs, rt, rd, sa, function, imm, instr_index, msb, lsb, size; + /* Additional variables for instruction fields in DSP ASE insructions */ - case 0x0E: - return msa_3R_0E(cins, wd, ws); + imm = get_imm(cins); + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + instr_index = get_instr_index(cins); + function = get_function(cins); + IRType ty = mode64 ? Ity_I64 : Ity_I32; - case 0x0F: - return msa_3R_0F(cins, wd, ws); + switch (function) { + case 0x01: { /* Doubleword Extract Bit Field - DEXTM; MIPS64r2 */ + msb = get_msb(cins); + lsb = get_lsb(cins); + size = msb + 1; + UInt srcPos = lsb; + UInt dstSz = msb + 33; + t1 = newTemp(Ity_I64); + DIP("dextm r%u, r%u, %u, %u", rt, rs, lsb, msb + 1); - case 0x10: - return msa_3R_10(cins, wd, ws); + UChar lsAmt = 64 - (srcPos + dstSz); /* left shift amount; */ + UChar rsAmt = 64 - dstSz; /* right shift amount; */ - case 0x11: - return msa_3R_11(cins, wd, ws); + assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt))); + putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt))); - case 0x12: - return msa_3R_12(cins, wd, ws); + break; + } - case 0x13: - return msa_3R_13(cins, wd, ws); + case 0x02: { /* Doubleword Extract Bit Field Upper - DEXTU; MIPS64r2 */ + msb = get_msb(cins); + lsb = get_lsb(cins); + size = msb + 1; + UInt srcPos = lsb + 32; + UInt dstSz = msb + 1; + DIP("dextu r%u, r%u, %u, %u", rt, rs, srcPos, dstSz); + t1 = newTemp(Ity_I64); - case 0x14: - return msa_3R_14(cins, wd, ws); + vassert(srcPos >= 32 && srcPos < 64); + vassert(dstSz > 0 && dstSz <= 32); + vassert((srcPos + dstSz) > 32 && (srcPos + dstSz) <= 64); - case 0x15: - return msa_3R_15(cins, wd, ws); + UChar lsAmt = 64 - (srcPos + dstSz); /* left shift amount; */ + UChar rsAmt = 64 - dstSz; /* right shift amount; */ - case 0x19: - return msa_ELM(cins, wd, ws); + assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt))); + putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt))); + break; + } - case 0x1A: - return msa_3R_1A(cins, wd, ws); + 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); - case 0x1B: - return msa_3R_1B(cins, wd, ws); + assign(tmpRs, getIReg(rs)); + assign(tmpRt, getIReg(rt)); + DIP("dinsm r%u, r%u, %u, %u", rt, rs, lsb, msb); - case 0x1C: - return msa_3R_1C(cins, wd, ws); + UChar lsAmt = dstPos + srcSz - 1; /* left shift amount; */ + UChar rsAmt = dstPos + srcSz - 1; /* right shift amount; */ - 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); + 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))); - case 0x20: - return msa_MI10_load(cins, wd, ws); + lsAmt = 63 - dstPos; /* left shift amount; */ + rsAmt = 63 - dstPos; /* right shift amount; */ - case 0x24: - return msa_MI10_store(cins, wd, ws); - } + 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))); - return -1; -} + /* extract size from src register */ + lsAmt = 64 - srcSz; /* left shift amount; */ + rsAmt = 64 - (lsb + srcSz); /* right shift amount; */ -/*------------------------------------------------------------*/ -/*--- Disassemble a single instruction ---*/ -/*------------------------------------------------------------*/ + assign(tmpT5, binop(Iop_Shl64, mkexpr(tmpRs), mkU8(lsAmt))); + assign(tmpT6, binop(Iop_Shr64, mkexpr(tmpT5), mkU8(rsAmt))); -/* 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. */ + assign(tmpT7, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT4))); + assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT6), mkexpr(tmpT7))); + putIReg(rt, mkexpr(tmpRd)); + break; + } -static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, - Addr), - Bool resteerCisOk, - void* callback_opaque, - Long delta64, - const VexArchInfo* archinfo, - const VexAbiInfo* abiinfo, - Bool sigill_diag ) -{ - IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7; + 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); - UInt opcode, cins, rs, rt, rd, sa, ft, fs, fd, fmt, tf, nd, function, - trap_code, imm, instr_index, p, msb, lsb, size, rot, sel; - /* Additional variables for instruction fields in DSP ASE insructions */ - UInt ac; + assign(tmpRs, getIReg(rs)); + assign(tmpRt, getIReg(rt)); + DIP("dinsu r%u, r%u, %u, %u", rt, rs, lsb, msb); - DisResult dres; + 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))); - static IRExpr *lastn = NULL; /* last jump addr */ - static IRStmt *bstmt = NULL; /* branch (Exit) stmt */ + 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))); - /* The running delta */ - Int delta = (Int) delta64; + 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))); - /* Holds eip at the start of the insn, so that we can print - consistent error messages for unimplemented insns. */ - Int delta_start = delta; + assign(tmpT7, binop(Iop_Shl64, mkexpr(tmpT6), mkU8(rsAmt))); + assign(tmpT8, binop(Iop_Shl64, mkexpr(tmpT7), mkU8(lsAmt))); - /* Are we in a delay slot ? */ - Bool delay_slot_branch, likely_delay_slot, delay_slot_jump; + assign(tmpT9, binop(Iop_Or64, mkexpr(tmpT8), mkexpr(tmpT4))); + assign(tmpRd, binop(Iop_Or64, mkexpr(tmpT2), mkexpr(tmpT9))); + putIReg(rt, mkexpr(tmpRd)); + break; + } - /* Set result defaults. */ - dres.whatNext = Dis_Continue; - dres.len = 0; - dres.continueAt = 0; - dres.jk_StopHere = Ijk_INVALID; - dres.hint = Dis_HintNone; + 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); - delay_slot_branch = likely_delay_slot = delay_slot_jump = False; + assign(tmpRs, getIReg(rs)); + assign(tmpRt, getIReg(rt)); - const UChar *code = guest_code + delta; - cins = getUInt(code); - DIP("\t0x%llx:\t0x%08x\t", (Addr64)guest_PC_curr_instr, cins); + 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; + } - if (delta != 0) { - if (branch_or_jump(guest_code + delta - 4)) { - if (lastn == NULL && bstmt == NULL) { - vassert(0); - } else { - dres.whatNext = Dis_StopHere; - if (lastn != NULL) { - delay_slot_jump = True; - } else if (bstmt != NULL) { - delay_slot_branch = True; + 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; } - } - } - if (branch_or_link_likely(guest_code + delta - 4)) { - likely_delay_slot = True; - } - } + 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; + } - /* 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 + 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 + } - ****mips64**** - dsll $0, $0, 3 - dsll $0, $0, 13 - dsll $0, $0, 29 - dsll $0, $0, 19 */ + break; + } - 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; + 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 + } - 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))); + break; - 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))); + default: + return -1;; + } - putPC(mkU32(guest_PC_curr_instr + 20)); - } - dres.whatNext = Dis_StopHere; - dres.jk_StopHere = Ijk_InvalICache; - dres.len = 20; - delta += 20; - goto decode_success; + 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 } - /* 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*/} - } + break; - opcode = get_opcode(cins); - imm = get_imm(cins); - rs = get_rs(cins); - rt = get_rt(cins); - rd = get_rd(cins); - sa = get_sa(cins); - fs = get_fs(cins); - fd = get_fd(cins); - ft = get_ft(cins); - tf = get_tf(cins); - nd = get_nd(cins); - sel = get_sel(cins); - fmt = get_fmt(cins); - instr_index = get_instr_index(cins); - trap_code = get_code(cins); - function = get_function(cins); - IRType ty = mode64 ? Ity_I64 : Ity_I32; - IRType tyF = fp_mode64 ? Ity_F64 : Ity_F32; + 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))); - ac = get_acNo(cins); + 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)); - switch (opcode) { + 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))); - 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 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 0x11: { /* 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)); + /* 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, unop(Iop_ReinterpF32asI32, - getFReg(fs | 1)), True)); + putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t1), + mkexpr(t5)), True)); } } else { - ILLEGAL_INSTRUCTON; + putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t1), + mkexpr(t3)), True)); } + 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)))); - } + + 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 { - ILLEGAL_INSTRUCTON; + putIReg(rt, mkWidenFrom32(ty, binop(Iop_Shr32, + mkNarrowTo32(ty, getIReg(rs)), + mkU8(32 - size)), True)); } + 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)))); + 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); - 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 - goto decode_failure; - } 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))); + UChar lsAmt = 63 - (lsb + msb); /* left shift amount; */ + UChar rsAmt = 63 - msb; /* right shift amount; */ - switch (df) { - case 0x00: { /* BNZ.B */ - DIP("BNZ.B w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2))); - break; - } + assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt))); + putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt))); - case 0x01: { /* BNZ.H */ - DIP("BNZ.H w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2))); - break; - } + break; - case 0x02: { /* BNZ.W */ - DIP("BNZ.W w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2))); - 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); - case 0x03: { /* BNZ.D */ - DIP("BNZ.D w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2))); - break; + 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; } - } - 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))); + break; - 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 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 0x01: { /* BZ.H */ - DIP("BZ.H w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2))); - break; - } + case 0x10: /* SEB */ + DIP("seb r%u, r%u", rd, rt); - case 0x02: { /* BZ.W */ - DIP("BZ.W w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2))); - break; - } + if (mode64) + putIReg(rd, unop(Iop_8Sto64, unop(Iop_64to8, getIReg(rt)))); + else + putIReg(rd, unop(Iop_8Sto32, unop(Iop_32to8, getIReg(rt)))); - case 0x03: { /* BZ.D */ - DIP("BZ.D w%u, %u", ft, imm); - assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2))); - break; + 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; + } - 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; + 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; } - } 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))); + /* 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; } - dis_branch(False, mkexpr(t1), imm, &bstmt); + + break; } else { - ILLEGAL_INSTRUCTON; + return -2; } - } 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 8: /* SAF */ - signaling = CMPSAFD; /* fallthrough */ - case 0: /* 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 9: /* SUN */ - signaling = CMPSAFD; /* fallthrough */ - case 1: /* 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 0xa: /* SEQ */ - signaling = CMPSAFD; /* fallthrough */ - case 2: /* 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 0xB: /* SUEQ */ - signaling = CMPSAFD; /* fallthrough */ - case 0x3: /* 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 0xC: /* SLT */ - signaling = CMPSAFD; /* fallthrough */ - case 0x4: /* 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 0xD: /* SULT */ - signaling = CMPSAFD; /* fallthrough */ - case 0x5: /* 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 0xE: /* SLE */ - signaling = CMPSAFD; /* fallthrough */ - case 0x6: /* 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 0xF: /* SULE */ - signaling = CMPSAFD; /* fallthrough */ - case 0x7: /* 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; + } + + 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; - default: - comparison = False; - } - if (comparison) { - if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { - ILLEGAL_INSTRUCTON; + } else { + return -2; } + 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 8: /* SAF */ - signaling = CMPSAFS; /* fallthrough */ - case 0: /* 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 9: /* SUN */ - signaling = CMPSAFS; /* fallthrough */ - case 1: /* 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 0xa: /* SEQ */ - signaling = CMPSAFS; /* fallthrough */ - case 2: /* 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 0xB: /* SUEQ */ - signaling = CMPSAFS; /* fallthrough */ - case 0x3: /* 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 0xC: /* SLT */ - signaling = CMPSAFS; /* fallthrough */ - case 0x4: /* 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 0xD: /* SULT */ - signaling = CMPSAFS; /* fallthrough */ - case 0x5: /* 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 0xE: /* SLE */ - signaling = CMPSAFS; /* fallthrough */ - case 0x6: /* 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 0xF: /* SULE */ - signaling = CMPSAFS; /* fallthrough */ - case 0x7: /* 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))))); + default: { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + + if (0 != retVal ) { + return -2; + } + break; - default: - comparison = False; - } - if (comparison) { - if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { - ILLEGAL_INSTRUCTON; + } else { + return -2; } + break; } } - switch (function) { - case 0x4: { /* 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: - goto decode_failure; + 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; - case 0x5: /* 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: - goto decode_failure; - } - break; /* case 0x5 */ - - 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: - goto decode_failure; - } - 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: - goto decode_failure; - } - 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: { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + + if (0 != retVal ) { + return -2; } - default: - goto decode_failure; - } - 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: - goto decode_failure; - } - break; /* MOV.fmt */ - - case 0x7: /* 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: - goto decode_failure; + + break; + } else { + return -2; } - break; /* case 0x7 */ - 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); + break; + } + } - assign(t0, binop(Iop_F32toI64S, mkU32(0x0), - getLoFromF64(Ity_F64, getFReg(fs)))); + break; + } - 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: - goto decode_failure; + 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 ); - } - 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: - goto decode_failure; - } - 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; + if (0 != retVal ) { + return -2; } - default: - goto decode_failure; + break; + } else { + return -2; } - break; /* case 0x15 */ - - 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))); + break; + } - 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); + default: { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (mode64) - assign(t1, binop(Iop_CmpNE64, mkU64(0), getIReg(rt))); - else - assign(t1, binop(Iop_CmpNE32, mkU32(0), getIReg(rt))); + if (0 != retVal ) { + return -2; + } - putDReg(fd, IRExpr_ITE(mkexpr(t1), getDReg(fs), getDReg(fd))); break; - default: - goto decode_failure; + } else { + return -2; } - 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); + break; + } + } - if (mode64) - assign(t1, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt))); - else - assign(t1, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt))); + break; + } - 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); + 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 (mode64) - assign(t1, binop(Iop_CmpEQ64, mkU64(0), getIReg(rt))); - else - assign(t1, binop(Iop_CmpEQ32, mkU32(0), getIReg(rt))); + if (0 != retVal ) { + return -2; + } - putDReg(fd, IRExpr_ITE(mkexpr(t1), getDReg(fs), getDReg(fd))); break; - default: - goto decode_failure; + } else { + return -2; } - 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)); + break; + } - putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t7))); - } else - putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(), - mkexpr(t4))); - break; - default: - goto decode_failure; - } - } 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))); - } + default: { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - 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: - goto decode_failure; + if (0 != retVal ) { + return -2; } - } - break; /* MOVT.fmt */ - - case 0x0: /* 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; + } else { + return -2; } - case 0x4: /* 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))); + break; + } + } - putFReg(fs, mkWidenFromF32(tyF, mkexpr(t1))); - } else - putFReg(fs, unop(Iop_ReinterpI32asF32, - mkNarrowTo32(ty, getIReg(rt)))); - break; + break; + } - case 0x5: /* 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 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 ); - case 0x0: /* 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; + if (0 != retVal ) { + return -2; + } - case 0x1: /* Doubleword Move from Floating Point DMFC1; - MIPS64 */ - DIP("dmfc1 r%u, f%u", rt, fs); - putIReg(rt, unop(Iop_ReinterpF64asI64, getDReg(fs))); break; + } else { + return -2; + } - case 0x6: /* 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 0x2: /* 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: { + if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); + + if (0 != retVal ) { + return -2; } + break; - default: - goto decode_failure; + } else { + return -2; } - 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))); + break; + } + } - assign(t1, unop(Iop_64to32, mkexpr(t0))); + break; + } - assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1))); + case 0x18: /* ADDUH.QB/MUL.PH */ + case 0x31: { /* APPEND */ + if (VEX_MIPS_PROC_DSP2(archinfo->hwcaps)) { + UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - putFReg(fd, unop(Iop_F32toF64, mkexpr(t3))); - } else - putDReg(fd, unop(Iop_F32toF64, getFReg(fs))); - break; + if (0 != retVal ) { + return -2; + } - case 0x14: - 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))); + break; + } else { + return -2; + } + } - 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 0x35: { /* PREF r6*/ + DIP("pref"); + 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))); + 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; + } - putFReg(fd, binop(Iop_I64StoF64, - get_IR_roundingmode(), mkexpr(t0))); - break; - } else - goto decode_failure; - } - default: - goto decode_failure; - } - 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 0x26: { /* SC */ + imm = extend_s_9to16((instr_index >> 7) & 0x1ff); + DIP("sc r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; - 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; + 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)); - 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))); + mips_next_insn_if(mkexpr(t2)); - putFReg(fd, mkWidenFromF32(tyF, binop(Iop_I64StoF32, - get_IR_roundingmode(), mkexpr(t0)))); - } else { - ILLEGAL_INSTRUCTON; - } - break; + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); - default: - goto decode_failure; - } - 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; + assign(t5, mkNarrowTo32(ty, getLLdata())); - case 0x11: - 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; + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); - default: - goto decode_failure; + putIReg(rt, unop(mode64 ? Iop_1Uto64 : Iop_1Uto32, + binop(Iop_CmpEQ32, mkexpr(t4), mkexpr(t5)))); + break; + } - } - 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; - 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); + t2 = newTemp(Ity_I64); + assign(t2, load(Ity_I64, mkexpr(t1))); + putLLaddr(mkexpr(t1)); + putLLdata(mkexpr(t2)); + putIReg(rt, mkexpr(t2)); + break; + } - assign(t0, binop(Iop_F32toI64S, get_IR_roundingmode(), - getLoFromF64(tyF, getFReg(fs)))); + case 0x27: { /* SCD */ + imm = extend_s_9to16((instr_index >> 7) & 0x1ff); + DIP("sdc r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; - putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0))); - } else { - ILLEGAL_INSTRUCTON; - } - break; + 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)); - 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; - } + mips_next_insn_if(mkexpr(t2)); - default: - goto decode_failure; - } - break; + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); - 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(t5, getLLdata()); - assign(t0, binop(Iop_F32toI64S, mkU32(0x1), - getLoFromF64(tyF, getFReg(fs)))); + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); - putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0))); - } else { - ILLEGAL_INSTRUCTON; - } - break; + putIReg(rt, unop(Iop_1Uto64, + binop(Iop_CmpEQ64, mkexpr(t4), mkexpr(t5)))); + 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: - goto decode_failure; - } - break; + default: + return -1; + } - 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; + return 0; +} - 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); +static UInt disInstr_MIPS_WRK_00(UInt cins, const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, DisResult* dres, + IRStmt** bstmt, IRExpr** lastn, + Bool(*resteerOkFn) (/*opaque */void *, + Addr), + void* callback_opaque) +{ + IRTemp t0; + UInt opcode, rs, rt, trap_code, imm, instr_index, p; + /* Additional variables for instruction fields in DSP ASE insructions */ - assign(t0, binop(Iop_F64toI32S, mkU32(0x0), - getDReg(fs))); + 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; - putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0))); - } - break; - default: - goto decode_failure; + switch (opcode & 0x0F) { + case 0x00: /* Special */ + return disInstr_MIPS_WRK_Special(cins, archinfo, abiinfo, dres, bstmt, lastn, + resteerOkFn, callback_opaque); - } - break; /* ROUND.W.fmt */ + case 0x01: /* Regimm */ + switch (rt) { + case 0x00: /* BLTZ */ + DIP("bltz r%u, %u", rs, imm); - 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; + if (mode64) { + if (!dis_instr_branch(cins, dres, resteerOkFn, + callback_opaque, bstmt)) + return -1; + } else + dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), + mkU32(0x80000000)), mkU32(0x80000000)), imm, bstmt); - 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); + break; - assign(t0, binop(Iop_F64toI32S, mkU32(0x1), - getDReg(fs))); + case 0x01: /* BGEZ */ + DIP("bgez r%u, %u", rs, imm); - putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0))); - break; - } - default: - goto decode_failure; + if (mode64) { + if (!dis_instr_branch(cins, dres, resteerOkFn, + callback_opaque, bstmt)) + return -1; + } else + dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), + mkU32(0x80000000)), mkU32(0x0)), imm, bstmt); - } - break; /* FLOOR.W.fmt */ + break; - 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); + 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; - assign(t0, binop(Iop_F64toI32S, mkU32(0x3), - getFReg(fs))); + 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; - putFReg(fd, mkWidenFromF32(tyF, - unop(Iop_ReinterpI32asF32, mkexpr(t0)))); - } else { - t0 = newTemp(Ity_I32); + 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 + } - assign(t0, binop(Iop_F64toI32S, mkU32(0x3), - getDReg(fs))); + break; + } - putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0))); - } - break; - default: - goto decode_failure; + 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 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; + break; - default: - goto decode_failure; + 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: /* 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); + break; + } - assign(t0, binop(Iop_F32toI64S, mkU32(0x2), - getLoFromF64(tyF, getFReg(fs)))); + case 0x0A: { /* TLTI */ + DIP("tlti r%u, %u %u", rs, imm, trap_code); - putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0))); - } else { - ILLEGAL_INSTRUCTON; - } - break; + 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)); + } - 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; + break; + } - default: - goto decode_failure; + 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 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: - goto decode_failure; + 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 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; - } + 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; - } + case 0x0E: { /* TNEI */ + DIP("tnei r%u, %u %u", rs, imm, trap_code); - default: - goto decode_failure; - } + 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 { - ILLEGAL_INSTRUCTON; + 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 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: /* BLTZAL */ + DIP("bltzal r%u, %u", rs, imm); - 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; - } + if (mode64) { + if (!dis_instr_branch(cins, dres, resteerOkFn, + callback_opaque, bstmt)) + return -1; + } else + dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), + mkU32(0x80000000)), mkU32(0x80000000)), imm, bstmt); - default: - goto decode_failure; - } - } else { - ILLEGAL_INSTRUCTON; - } + break; + + case 0x11: /* BGEZAL */ + DIP("bgezal r%u, %u", rs, imm); + + if (mode64) { + if (!dis_instr_branch(cins, dres, resteerOkFn, + callback_opaque, bstmt)) + return -1; + } else + dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), + mkU32(0x80000000)), mkU32(0x0)), imm, bstmt); 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 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 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; - } + case 0x13: /* BGEZALL */ + DIP("bgezall r%u, %u", rs, imm); - default: - goto decode_failure; - } + 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 { - ILLEGAL_INSTRUCTON; + 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: /* 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 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 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: - goto decode_failure; - } + 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; + 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 0x1F: /* SYNCI */ + /* Just ignore it */ + 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; + } - default: - goto decode_failure; - } - /* missing in documentation */ - } else { - ILLEGAL_INSTRUCTON; - } - break; + 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 0x02: /* J */ + DIP("j 0x%x", instr_index); + t0 = newTemp(ty); - 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; - } + 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))); - default: - goto decode_failure; - } - } else { - ILLEGAL_INSTRUCTON; - } - break; + *lastn = mkexpr(t0); + 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 0x03: /* JAL */ + DIP("jal 0x%x", instr_index); - 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; - } + 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))); + } - default: - goto decode_failure; - } + *lastn = mkexpr(t0); + break; - } - break; + case 0x04: /* BEQ */ + DIP("beq r%u, r%u, %u", rs, rt, imm); - 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; - } + 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 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: - goto decode_failure; - } - break; + case 0x05: /* BNE */ + DIP("bne r%u, r%u, %u", rs, rt, imm); - 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; - } + 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); - 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; - } + break; - default: - goto decode_failure; - } - } else { - ILLEGAL_INSTRUCTON; - } - break; + case 0x06: /* BLEZ, BLEZALC, BGEZALC, BGEUC */ + if (rt == 0) { /* BLEZ */ + DIP("blez r%u, %u", rs, imm); - 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; - } + 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); - 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; - } + 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); - default: - goto decode_failure; - } + 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 { - ILLEGAL_INSTRUCTON; + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + getIReg(rt), mkU32(0x0))), + imm, dres); } - break; + } else if (rs == rt) { /* BLTZALC */ + DIP("bltzalc r%u, %u", rt, imm); - 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: - goto decode_failure; - } + if (mode64) { + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + mkU64(0x0), getIReg(rt))), + imm, dres); } else { - ILLEGAL_INSTRUCTON; + dis_branch_compact(True, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkU32(0x0), getIReg(rt))), + imm, dres); } - break; + } 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; + } - default: - if (dis_instr_CCondFmt(cins)) - break; - goto decode_failure; +#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6)) + + case 0x08: { /* BEQZALC, BEQC, BOVC */ + 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! */ } - break; /* COP1 */ - case 0x31: /* 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 0x39: /* 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 0x33: /* PREF */ - DIP("pref"); - break; - - case 0x35: - /* 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 0x3D: - /* 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 0x23: /* 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 0x20: /* 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; +#endif - case 0x24: /* 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 0x09: /* ADDIU */ + DIP("addiu r%u, r%u, %u", rt, rs, imm); - case 0x21: /* 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; + 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)))); - case 0x25: /* 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; + break; + + case 0x0A: /* SLTI */ + DIP("slti r%u, r%u, %u", rt, rs, imm); - 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))); + putIReg(rt, unop(Iop_1Uto64, binop(Iop_CmpLT64S, getIReg(rs), + mkU64(extend_s_16to64(imm))))); else - putIReg(rt, mkU32(p)); + putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs), + mkU32(extend_s_16to32(imm))))); + 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; - case 0x13: /* 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))); + case 0x0B: /* SLTIU */ + DIP("sltiu r%u, r%u, %u", rt, rs, imm); - assign(t4, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32, - mkexpr(t3)), True)); + 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))))); - 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 0x0C: /* ANDI */ + DIP("andi r%u, r%u, %u", rt, rs, imm); - 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))); + if (mode64) { + ALUI_PATTERN64(Iop_And64); } else { - ILLEGAL_INSTRUCTON; + ALUI_PATTERN(Iop_And32); } - 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: - goto decode_failure; - } - break; - - case 0x22: /* 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 + case 0x0D: /* ORI */ + DIP("ori r%u, r%u, %u", rt, rs, imm); - /* t2 = word addr */ - /* t4 = addr mod 4 */ - LWX_SWX_PATTERN; + if (mode64) { + ALUI_PATTERN64(Iop_Or64); + } else { + ALUI_PATTERN(Iop_Or32); + } - /* 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))))); + break; - /* 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)))))); + case 0x0E: /* XORI */ + DIP("xori r%u, r%u, %u", rt, rs, imm); - putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3))); - } - break; + if (mode64) { + ALUI_PATTERN64(Iop_Xor64); + } else { + ALUI_PATTERN(Iop_Xor32); + } - case 0x26: /* 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; + break; - /* 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))))); + case 0x0F: /* LUI */ + if (rs == 0) { + p = (imm << 16); + DIP("lui r%u, imm: 0x%x", rt, imm); - /* 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))))))); + if (mode64) + putIReg(rt, mkU64(extend_s_32to64(p))); + else + putIReg(rt, mkU32(p)); - putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32, mkexpr(t5), - mkexpr(t3)), True)); + break; + } else if (VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { /* AUI */ + DIP("aui r%u, imm: 0x%x", rt, imm); - } 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 + 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))); + } - /* t2 = word addr */ - /* t4 = addr mod 4 */ - LWX_SWX_PATTERN; + } else { + ILLEGAL_INSTRUCTON + } - /* 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))))); + break; - /* 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))))))); + default: + return -1; + } - putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3))); - } - break; + return 0; +} - case 0x2B: /* SW */ - DIP("sw r%u, %u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; - store(mkexpr(t1), mkNarrowTo32(ty, getIReg(rt))); - break; +static UInt disInstr_MIPS_WRK_10(UInt cins, const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, DisResult* dres, + IRStmt** bstmt, IRExpr** lastn, + Bool(*resteerOkFn) (/*opaque */void *, + Addr), + void* callback_opaque) +{ + 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 */ - case 0x2C: { /* 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))); + 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; -#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)); + switch (opcode & 0x0F) { + case 0x01: { /* COP1 */ + if (fmt == 0x3 && fd == 0 && function == 0) { /* MFHC1 */ + DIP("mfhc1 r%u, f%u", rt, fs); -#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 + 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; - } + break; + } else if (fmt == 0x7 && fd == 0 && function == 0) { /* MTHC1 */ + DIP("mthc1 r%u, f%u", rt, fs); - case 0x2D: { - /* 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 (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; + } -#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)); + 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); -#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; - } + 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))); - case 0x28: /* SB */ - DIP("sb r%u, %u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; - store(mkexpr(t1), narrowTo(Ity_I8, getIReg(rt))); - break; - - case 0x29: /* SH */ - DIP("sh r%u, %u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; - store(mkexpr(t1), narrowTo(Ity_I16, getIReg(rt))); - break; - - case 0x2A: /* 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); + switch (df) { + case 0x00: { /* BNZ.B */ + DIP("BNZ.B w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2))); + break; + } - /* 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)); + case 0x01: { /* BNZ.H */ + DIP("BNZ.H w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2))); + break; + } - /* t1 = addr */ - t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm)))); + case 0x02: { /* BNZ.W */ + DIP("BNZ.W w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2))); + break; + } - /* t2 = word addr */ - t2 = newTemp(Ity_I64); - assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL))); + case 0x03: { /* BNZ.D */ + DIP("BNZ.D w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2))); + break; + } + } - /* t3 = addr mod 4 */ - t3 = newTemp(Ity_I64); - assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x3))); + 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))); -#if defined (_MIPSEL) - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)), - mkU64(0x0), - mkU64(0x1))); + switch (df) { + case 0x00: { /* BZ.B */ + DIP("BZ.B w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ8x16, mkexpr(t1), mkexpr(t2))); + break; + } - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)), - mkU64(0x1), - mkU64(0x0))); + case 0x01: { /* BZ.H */ + DIP("BZ.H w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ16x8, mkexpr(t1), mkexpr(t2))); + break; + } - /* 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)); + case 0x02: { /* BZ.W */ + DIP("BZ.W w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ32x4, mkexpr(t1), mkexpr(t2))); + break; + } -#else /* _MIPSEB */ - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)), - mkU64(0x0), - mkU64(0x1))); + case 0x03: { /* BZ.D */ + DIP("BZ.D w%u, %u", ft, imm); + assign(t3, binop(Iop_CmpEQ64x2, mkexpr(t1), mkexpr(t2))); + break; + } + } - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)), - mkU64(0x2), - mkU64(0x3))); + 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); - 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)); + 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))); + } -#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); + 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); - /* 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)); + 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))); + } - /* t1 = addr */ - t1 = newTemp(Ity_I32); - assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm)))); + 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); - /* t2 = word addr */ - t2 = newTemp(Ity_I32); - assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFCULL))); + /* 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; - /* t3 = addr mod 4 */ - t3 = newTemp(Ity_I32); - assign(t3, binop(Iop_And32, mkexpr(t1), mkU32(0x3))); + case 0x0F: /* SULE */ + signaling = CMPSAFD; /* fallthrough */ -#if defined (_MIPSEL) - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)), - mkU32(0x0), - mkU32(0x1))); + 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; - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)), - mkU32(0x1), - mkU32(0x0))); + default: + comparison = False; + } - /* 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)); + if (comparison) { + if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } -#else /* _MIPSEB */ - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)), - mkU32(0x0), - mkU32(0x1))); + break; + } - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)), - mkU32(0x2), - mkU32(0x3))); + } 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); - 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)); + /* Conditions starting with S should signal exception on QNaN inputs. */ + switch (function) { + case 0x08: /* SAF */ + signaling = CMPSAFS; /* fallthrough */ -#endif - } - break; + 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 0x2E: /* 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); + case 0x09: /* SUN */ + signaling = CMPSAFS; /* fallthrough */ - /* 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)); + 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; - /* t1 = addr */ - t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm)))); + case 0x1B: /* SNEQ */ + signaling = CMPSAFS; /* fallthrough */ - /* t2 = word addr */ - t2 = newTemp(Ity_I64); - assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFFCULL))); + 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; - /* t3 = addr mod 4 */ - t3 = newTemp(Ity_I64); - assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x3))); + case 0x0C: /* SLT */ + signaling = CMPSAFS; /* fallthrough */ -#if defined (_MIPSEL) - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)), - mkU64(0x2), - mkU64(0x3))); + 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; - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)), - mkU64(0x0), - mkU64(0x1))); + case 0x0E: /* SLE */ + signaling = CMPSAFS; /* fallthrough */ - /* 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)); + 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; -#else /* _MIPSEB */ - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x3)), - mkU64(0x1), - mkU64(0x0))); + case 0x0F: /* SULE */ + signaling = CMPSAFS; /* fallthrough */ - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)), - mkU64(0x0), - mkU64(0x1))); + 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; - /* 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); + default: + comparison = False; + } - /* 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)); + if (comparison) { + if (!VEX_MIPS_CPU_HAS_MIPSR6(archinfo->hwcaps)) { + ILLEGAL_INSTRUCTON + } - /* t1 = addr */ - t1 = newTemp(Ity_I32); - assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm)))); + break; + } + } - /* t2 = word addr */ - t2 = newTemp(Ity_I32); - assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFCULL))); + 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; + } - /* t3 = addr mod 4 */ - t3 = newTemp(Ity_I32); - assign(t3, binop(Iop_And32, mkexpr(t1), mkU32(0x3))); + case 0x11: { /* D */ + IRExpr *rm = get_IR_roundingmode(); + putDReg(fd, binop(Iop_SqrtF64, rm, getDReg(fs))); + break; + } -#if defined (_MIPSEL) - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)), - mkU32(0x2), - mkU32(0x3))); + default: + return -1; + } + } + break; /* SQRT.fmt */ - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)), - mkU32(0x0), - mkU32(0x1))); + 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; - /* 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)); + case 0x11: /* D */ + DIP("abs.d f%u, f%u", fd, fs); + putDReg(fd, unop(Iop_AbsF64, getDReg(fs))); + break; -#else /* _MIPSEB */ - /* Calculate X_byte position. */ - assign(F_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x3)), - mkU32(0x1), - mkU32(0x0))); + default: + return -1; + } - assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ32, mkexpr(t3), mkU32(0x0)), - mkU32(0x0), - mkU32(0x1))); + break; /* ABS.fmt */ - /* 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; + 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 0x1C: /* Special2 */ - 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; - goto decode_failure; - } else { - goto decode_failure; - } - 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; + } - 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); + default: + return -1; + } - 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; - } + break; /* MUL.fmt */ - 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); + 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; + } - assign(t1, mkNarrowTo32(ty, getHI())); - assign(t2, mkNarrowTo32(ty, getLO())); + 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; + } - assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + default: + return -1; + } - assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); - assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); + break; /* DIV.fmt */ - 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 ) { - goto decode_failure_dsp; + 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; } - break; - } else { - goto decode_failure_dsp; + + 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; } - } 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()); + break; /* SUB.fmt */ - assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + case 0x06: /* MOV.fmt */ + switch (fmt) { + case 0x11: /* D */ + DIP("mov.d f%u, f%u", fd, fs); - assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32, - mkexpr(t3)))); + if (fp_mode64) { + putDReg(fd, getDReg(fs)); + } else { + putFReg(fd, getFReg(fs)); + putFReg(fd + 1, getFReg(fs + 1)); + } - assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4), - unop(Iop_64to32, mkexpr(t3))))); - assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1))); + break; - putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, - mkexpr(t3)))); - putLO(mkexpr(t4)); - break; - } - } - break; - } + case 0x10: /* S */ + DIP("mov.s f%u, f%u", fd, fs); + putFReg(fd, getFReg(fs)); + 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); + default: + return -1; + } - assign(t1, mkNarrowTo32(ty, getHI())); - assign(t2, mkNarrowTo32(ty, getLO())); + break; /* MOV.fmt */ - assign(t3, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + 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; - assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); - assign(t5, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); + case 0x11: /* D */ + DIP("neg.d f%u, f%u", fd, fs); + putDReg(fd, unop(Iop_NegF64, getDReg(fs))); + break; - 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 ) { - goto decode_failure_dsp; + default: + return -1; } - break; - } else { - goto decode_failure_dsp; - } - } 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()); + break; /* NEG.fmt */ - assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + case 0x08: /* ROUND.L.fmt */ + switch (fmt) { + case 0x10: /* S */ + DIP("round.l.s f%u, f%u", fd, fs); - 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))); + if (fp_mode64) { + calculateFCSR(fs, 0, ROUNDLS, True, 1); + t0 = newTemp(Ity_I64); - putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, - mkexpr(t3)))); - putLO(mkexpr(t4)); - break; - } - } - break; - } + assign(t0, binop(Iop_F32toI64S, mkU32(0x0), + getLoFromF64(Ity_F64, getFReg(fs)))); - 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); + putDReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0))); + } else { + ILLEGAL_INSTRUCTON + } - assign(t1, mkNarrowTo32(ty, getHI())); - assign(t2, mkNarrowTo32(ty, getLO())); + break; - assign(t3, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + case 0x11: /* D */ + DIP("round.l.d f%u, f%u", fd, fs); - assign(t4, binop(Iop_32HLto64, mkexpr(t1), mkexpr(t2))); - assign(t5, binop(Iop_Sub64, mkexpr(t4), mkexpr(t3))); + if (fp_mode64) { + calculateFCSR(fs, 0, ROUNDLD, False, 1); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + mkU32(0x0), + getDReg(fs)))); + } else { + ILLEGAL_INSTRUCTON + } - 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 ) { - goto decode_failure_dsp; - } - break; - } else { - goto decode_failure_dsp; - } - } 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); + break; - assign(t1, getHI()); - assign(t2, getLO()); + default: + return -1; - 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 ) { - goto decode_failure_dsp; + break; + + default: + return -1; } - break; - } else { - goto decode_failure_dsp; - } - } 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()); + break; /* TRUNC.L.fmt */ - assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); - assign(t4, unop(Iop_64to32, mkexpr(t3))); /* new lo */ + 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; + } - /* if lo= 32 && srcPos < 64); - vassert(dstSz > 0 && dstSz <= 32); - vassert((srcPos + dstSz) > 32 && (srcPos + dstSz) <= 64); + 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))); - UChar lsAmt = 64 - (srcPos + dstSz); /* left shift amount; */ - UChar rsAmt = 64 - dstSz; /* right shift amount; */ + break; - 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("daling 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; + default: + return -1; + } } - 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: - vex_printf("\nop6o10 = %u", lsb); - goto decode_failure;; - } - 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 - goto decode_failure; - } 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); + break; /* MOVT.fmt */ - vassert(lsb + size <= 32); - vassert(lsb + size > 0); + 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; + } - /* 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))); + 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; + } - 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)); + case 0x04: /* MTC1 (Move Word to Floating Point) */ + DIP("mtc1 r%u, f%u", rt, fs); - 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))); + if (fp_mode64) { + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_F32); + assign(t0, mkNarrowTo32(ty, getIReg(rt))); + assign(t1, unop(Iop_ReinterpI32asF32, mkexpr(t0))); - /* 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; + putFReg(fs, mkWidenFromF32(tyF, mkexpr(t1))); + } else + putFReg(fs, unop(Iop_ReinterpI32asF32, + mkNarrowTo32(ty, getIReg(rt)))); - 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))); + break; - 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 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 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); + case 0x00: /* MFC1 */ + DIP("mfc1 r%u, f%u", rt, fs); - UChar lsAmt = 63 - (lsb + msb); /* left shift amount; */ - UChar rsAmt = 63 - msb; /* right shift amount; */ + 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)); - assign(t1, binop(Iop_Shl64, getIReg(rs), mkU8(lsAmt))); - putIReg(rt, binop(Iop_Shr64, mkexpr(t1), mkU8(rsAmt))); + break; - 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 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; + 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 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; + 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 0x21: /* CVT.D */ + switch (fmt) { + case 0x10: /* S */ + DIP("cvt.d.s f%u, f%u", fd, fs); + calculateFCSR(fs, 0, CVTDS, True, 1); - 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; + 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))); - 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))))); + assign(t1, unop(Iop_64to32, mkexpr(t0))); + + assign(t3, unop(Iop_ReinterpI32asF32, mkexpr(t1))); + + putFReg(fd, unop(Iop_F32toF64, mkexpr(t3))); } 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)))); + 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 - putIReg(rd, getIReg(rt)); + return -1; } - } else { - ILLEGAL_INSTRUCTON; + + default: + return -1; } - break; - default: - goto decode_failure; + break; /* CVT.D */ - } - break; /* BSHFL */ + 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))); + } - /* --- 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; - goto decode_failure; - } - /* fallthrough */ - case 0xC: /* INSV */ - case 0x38: { /* EXTR.W */ - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; - } - break; - } else { - goto decode_failure_dsp; - } - 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 ) { - goto decode_failure_dsp; - } - break; - } else { - goto decode_failure_dsp; - } - break; - } - default: { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; - } - break; - } else { - goto decode_failure_dsp; - } - 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 ) { - goto decode_failure_dsp; - } - break; - } else { - goto decode_failure_dsp; - } - break; - } - default: { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; + 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; - } else { - goto decode_failure_dsp; - } - 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 ) { - goto decode_failure_dsp; + + 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; - } else { - goto decode_failure_dsp; - } - break; - } - default: { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; + + 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; - } else { - goto decode_failure_dsp; - } - 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 ) { - goto decode_failure_dsp; + + 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; - } else { - goto decode_failure_dsp; - } - break; - } - default: { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; + + 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; - } else { - goto decode_failure_dsp; - } - 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 ) { - goto decode_failure_dsp; + + 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; - } else { - goto decode_failure_dsp; - } - break; - } - default: { - if (VEX_MIPS_PROC_DSP(archinfo->hwcaps)) { - UInt retVal = disDSPInstr_MIPS_WRK ( cins ); - if (0 != retVal ) { - goto decode_failure_dsp; + + 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; - } else { - goto decode_failure_dsp; - } - 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 ) { - goto decode_failure_dsp; - } - break; - } else { - goto decode_failure_dsp; - } - } - 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)); + case 0x0A: /* CEIL.L.fmt */ + switch (fmt) { + case 0x10: /* S */ + DIP("ceil.l.s %u, %u", fd, fs); - mips_next_insn_if(mkexpr(t2)); + if (fp_mode64) { + calculateFCSR(fs, 0, CEILLS, True, 1); + t0 = newTemp(Ity_I64); - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); + assign(t0, binop(Iop_F32toI64S, mkU32(0x2), + getLoFromF64(tyF, getFReg(fs)))); - assign(t5, mkNarrowTo32(ty, getLLdata())); + putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t0))); + } else { + ILLEGAL_INSTRUCTON + } - stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ - MIPS_IEND, mkexpr(t1), /* addr */ - NULL, mkexpr(t5), /* expected value */ - NULL, mkexpr(t3) /* new value */))); + break; - 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; + case 0x11: /* D */ + DIP("ceil.l.d %u, %u", fd, fs); - 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; + if (fp_mode64) { + calculateFCSR(fs, 0, CEILLD, False, 1); + putDReg(fd, unop(Iop_ReinterpI64asF64, + binop(Iop_F64toI64S, + mkU32(0x2), + getDReg(fs)))); + } else { + ILLEGAL_INSTRUCTON + } - 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)); + 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; + } - mips_next_insn_if(mkexpr(t2)); + default: + return -1; - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); + } - assign(t5, getLLdata()); + break; - stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ - MIPS_IEND, mkexpr(t1), /* addr */ - NULL, mkexpr(t5), /* expected value */ - NULL, mkexpr(t3) /* new value */))); + 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; + } - putIReg(rt, unop(Iop_1Uto64, - binop(Iop_CmpEQ64, mkexpr(t4), mkexpr(t5)))); - break; - } - default: - goto decode_failure; + 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; + } - } - break; /* Special3 */ + default: + return -1; + } + } else { + ILLEGAL_INSTRUCTON; + } - case 0x3B: /* 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 { - goto decode_failure; - } + break; - 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 - goto decode_failure; - break; - } else { - goto decode_failure; - } + 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 0x00: /* Special */ + 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; + } - switch (function) { - case 0x1: { - 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); + default: + return -1; + } + } else { + ILLEGAL_INSTRUCTON; + } - 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); + break; - 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 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 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 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 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; + } - 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) { - goto decode_failure_dsp; + default: + return -1; } - break; } else { - goto decode_failure_dsp; - } - } 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)))))); + 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 { - putIReg(rd, unop(Iop_64HIto32, - binop(Iop_MullS32, - getIReg(rs), getIReg(rt)))); + ILLEGAL_INSTRUCTON; } - } 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) { - goto decode_failure_dsp; + 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; } - break; + } else { - goto decode_failure_dsp; - } - } 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)))); + 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; + } + } - 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)))); + + 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; + } + } - } 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)))); + + 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; } - } 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); + break; - assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); - assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt))); + 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))); + } - 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! */ + putDReg(fd, IRExpr_ITE( mkexpr(t1), + binop(Iop_I64StoF64, + get_IR_roundingmode(), mkU64(0)), + getDReg(fs))); + break; + } - 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)))); + 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; + } - 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)))); + default: + return -1; + } + } else { + ILLEGAL_INSTRUCTON; + } - 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)); + break; - putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True)); - 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))); + } - 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); + putDReg(fd, IRExpr_ITE( mkexpr(t1), + getDReg(fs), + binop(Iop_I64StoF64, + get_IR_roundingmode(), + mkU64(0)))); + break; + } - assign(t2, binop(Iop_DivModS32to32, - mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + 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; + } - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True)); - } else { - t1 = newTemp(Ity_I64); + default: + return -1; - 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))); + ILLEGAL_INSTRUCTON; } - } 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); + break; - assign(t1, binop(Iop_DivModU32to32, - mkNarrowTo32(ty, getIReg(rs)), - mkNarrowTo32(ty, getIReg(rt)))); + 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; + } - putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t1)), True)); - putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t1)), True)); - } else { - t1 = newTemp(Ity_I64); + 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; + } - 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))))); + default: + return -1; + } } else { - putIReg(rd, binop(Iop_DivU32, getIReg(rs), getIReg(rt))); + ILLEGAL_INSTRUCTON; } + 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; + default: + if (dis_instr_CCondFmt(cins)) + 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); + return -1; - 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; - } - /* Value for function in documentation is 111000 */ - 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; + } + break; /* COP1 */ - 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); + 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(t0, binop(Iop_MullU64, getIReg(rs), getIReg(rt))); + assign(t4, mkWidenFrom32(Ity_I64, unop(Iop_ReinterpF32asI32, + mkexpr(t3)), True)); - 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)))); + putFReg(fd, unop(Iop_ReinterpI64asF64, mkexpr(t4))); } else { - ILLEGAL_INSTRUCTON; + putFReg(fd, load(Ity_F32, mkexpr(t2))); } + 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)))); + } + + 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; + 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; + 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)); } - t1 = newTemp(Ity_I128); - assign(t1, binop(Iop_DivModS64to64, getIReg(rs), getIReg(rt))); + break; + } - putHI(unop(Iop_128HIto64, mkexpr(t1))); - putLO(unop(Iop_128to64, mkexpr(t1))); + 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 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)))); + } + + 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; + 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; - } + + 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 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); + 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; - assign(t1, binop(Iop_DivModU64to64, getIReg(rs), getIReg(rt))); + 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; - 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)))); + 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 { - ILLEGAL_INSTRUCTON; + dis_branch_compact(False, + binop(Iop_CmpLE32S, getIReg(rt), mkU32(0x0)), + imm, dres); } - 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 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 { - ILLEGAL_INSTRUCTON; + dis_branch_compact(False, + binop(Iop_CmpLE32S, mkU32(0x0), getIReg(rt)), + imm, dres); } - break; - } - break; + } else { /* BGEC */ + DIP("bgec r%u, r%u, %u", rs, rt, imm); - 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)); + dis_branch_compact(False, + binop(Iop_CmpLE64S, getIReg(rt), getIReg(rs)), + imm, dres); } 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)))); + dis_branch_compact(False, + binop(Iop_CmpLE32S, getIReg(rt), getIReg(rs)), + imm, dres); } - } 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 ) { - goto decode_failure; } - break; } else { - DIP("mfhi r%u", rd); - putIReg(rd, getHI()); - break; + ILLEGAL_INSTRUCTON } - } - 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); + 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) { - IRTemp tmpClo32 = newTemp(Ity_I32); - IRTemp tmpRs32 = newTemp(Ity_I32); - assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); + 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); - 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))))); + 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); - putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpClo32), True)); - break; + if (mode64) { + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE64S, + getIReg(rt), getIReg(rs))), + imm, dres); } 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))))); + dis_branch_compact(False, + unop(Iop_Not1, + binop(Iop_CmpLE32S, + getIReg(rt), getIReg(rs))), + imm, dres); } - } 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 ) { - goto decode_failure; } - break; } else { - DIP("mthi r%u", rs); - putHI(getIReg(rs)); - break; + 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; } - 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 ) { - goto decode_failure; - } - 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; +#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); } - break; - } - } + } else if (rs < rt) { /* BNEC */ + DIP("bnec r%u, %u", rt, imm); - 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 ) { - goto decode_failure; + 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); } - 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; + } 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; } + + 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); - } +#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 0x22: { /* SUB */ - DIP("sub r%u, r%u, r%u", rd, rs, rt); - IRTemp tmpRs32 = newTemp(Ity_I32); - IRTemp tmpRt32 = newTemp(Ity_I32); + 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; - 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! */ + /* 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))))); - 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)))); + /* rt content - adjusted */ + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I64); - 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)))); + assign(t5, binop(Iop_Mul64, mkexpr(t4), mkU64(0x8))); - 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)); + assign(t6, binop(Iop_Shr64, mkU64(0x00FFFFFFFFFFFFFFULL), + narrowTo(Ity_I8, mkexpr(t5)))); - putIReg(rd, mkWidenFrom32(ty, mkexpr(t0), True)); + assign(t7, binop(Iop_And64, getIReg(rt), mkexpr(t6))); + + putIReg(rt, binop(Iop_Or64, mkexpr(t7), mkexpr(t3))); break; } - case 0x23: /* SUBU */ - DIP("subu r%u, r%u, r%u", rd, rs, rt); - if (mode64) { - ALU_PATTERN64(Iop_Sub32); + + 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, + resteerOkFn, callback_opaque); + + 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 { - ALU_PATTERN(Iop_Sub32); + 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, + resteerOkFn, callback_opaque); + + 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 0x24: /* AND */ - DIP("and r%u, r%u, r%u", rd, rs, rt); - if (mode64) { - ALU_PATTERN(Iop_And64); - } else { - ALU_PATTERN(Iop_And32); - } + 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 0x25: /* OR */ - DIP("or r%u, r%u, r%u", rd, rs, rt); + case 0x02: /* LWL */ + DIP("lwl r%u, %u(r%u)", rt, imm, rs); + if (mode64) { - ALU_PATTERN(Iop_Or64); + /* 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 { - ALU_PATTERN(Iop_Or32); + /* 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 0x26: /* XOR */ - DIP("xor r%u, r%u, r%u", rd, rs, rt); - if (mode64) { - ALU_PATTERN(Iop_Xor64); - } else { - ALU_PATTERN(Iop_Xor32); - } + 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 0x27: /* NOR */ - DIP("nor r%u, r%u, r%u", rd, rs, rt); + case 0x04: /* LBU */ + DIP("lbu r%u, %u(r%u)", rt, imm, rs); + LOAD_STORE_PATTERN; + if (mode64) - putIReg(rd, unop(Iop_Not64, binop(Iop_Or64, getIReg(rs), - getIReg(rt)))); + putIReg(rt, unop(Iop_8Uto64, load(Ity_I8, mkexpr(t1)))); else - putIReg(rd, unop(Iop_Not32, binop(Iop_Or32, getIReg(rs), - getIReg(rt)))); + putIReg(rt, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t1)))); + break; - case 0x08: /* JR */ - DIP("jr r%u", rs); - t0 = newTemp(ty); - assign(t0, getIReg(rs)); - lastn = mkexpr(t0); + 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 0x09: /* JALR */ - DIP("jalr r%u r%u", rd, rs); + case 0x06: /* LWR */ + DIP("lwr r%u, %u(r%u)", rt, imm, rs); + if (mode64) { - putIReg(rd, mkU64(guest_PC_curr_instr + 8)); - t0 = newTemp(Ity_I64); - assign(t0, getIReg(rs)); - lastn = mkexpr(t0); + /* 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 { - putIReg(rd, mkU32(guest_PC_curr_instr + 8)); - t0 = newTemp(Ity_I32); - assign(t0, getIReg(rs)); - lastn = mkexpr(t0); + /* 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 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 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)))); + 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 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)))); + 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 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); + 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 0x04: { /* SLLV */ - DIP("sllv r%u, r%u, r%u", rd, rt, rs); + case 0x0A: /* SWL */ + DIP("swl r%u, %u(r%u)", rt, imm, 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)); + 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 { - SXXV_PATTERN(Iop_Shl32); + 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 0x03: /* SRA */ - DIP("sra r%u, r%u, %u", rd, rt, sa); - if (mode64) { - IRTemp tmpRt32 = newTemp(Ity_I32); - IRTemp tmpSh32 = newTemp(Ity_I32); + 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))); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); + assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x4)), + mkU64(0x4), + mkU64(0x0))); - assign(t1, binop(Iop_And64, getIReg(rt), /* hi */ - mkU64(0xFFFFFFFF00000000ULL))); + assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkexpr(t3), mkU64(0x3)), + mkU64(0x5), + mkU64(0x0))); - assign(t2, binop(Iop_Sar64, mkexpr(t1), mkU8(sa))); + assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x0)), + mkU64(0x6), + mkU64(0x7))); - assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt))); - assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkU8(sa))); + /* 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 - putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True)); - } else { - SXX_PATTERN(Iop_Sar32); - } 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); + 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); - t1 = newTemp(Ity_I64); - t2 = newTemp(Ity_I64); - t3 = newTemp(Ity_I64); - t4 = newTemp(Ity_I8); + /* 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)); - assign(t4, unop(Iop_32to8, binop(Iop_And32, - mkNarrowTo32(ty, getIReg(rs)), mkU32(0x0000001F)))); + /* t1 = addr */ + t1 = newTemp(Ity_I64); + assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm)))); - assign(t1, binop(Iop_And64, getIReg(rt), /* hi */ - mkU64(0xFFFFFFFF00000000ULL))); + /* t2 = word addr */ + t2 = newTemp(Ity_I64); + assign(t2, binop(Iop_And64, mkexpr(t1), mkU64(0xFFFFFFFFFFFFFFF8ULL))); - assign(t2, binop(Iop_Sar64, mkexpr(t1), mkexpr(t4))); + /* t3 = addr mod 7 */ + t3 = newTemp(Ity_I64); + assign(t3, binop(Iop_And64, mkexpr(t1), mkU64(0x7))); - assign(tmpRt32, mkNarrowTo32(ty, getIReg(rt))); - assign(tmpSh32, binop(Iop_Sar32, mkexpr(tmpRt32), mkexpr(t4))); +#if defined (_MIPSEL) + /* Calculate X_byte position. */ + assign(B_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x1), mkexpr(t3)), + mkU64(0x0), + mkU64(0x6))); - putIReg(rd, mkWidenFrom32(ty, mkexpr(tmpSh32), True)); - } else { - SXXV_PATTERN(Iop_Sar32); - } - break; + assign(C_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x2), mkexpr(t3)), + mkU64(0x0), + mkU64(0x5))); - 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(D_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x3), mkexpr(t3)), + mkU64(0x0), + mkU64(0x4))); - 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; - } + assign(E_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x4), mkexpr(t3)), + mkU64(0x0), + mkU64(0x3))); - case 0x06: { - 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 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; - } + assign(F_pos, IRExpr_ITE(binop(Iop_CmpLT64U, mkU64(0x5), mkexpr(t3)), + mkU64(0x0), + mkU64(0x2))); - } - 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; - } + assign(G_pos, IRExpr_ITE(binop(Iop_CmpEQ64, mkexpr(t3), mkU64(0x7)), + mkU64(0x0), + mkU64(0x1))); - 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; + /* 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)); - 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)); - } +#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 0x32: { /* TLT */ - DIP("tlt r%u, r%u %u", rs, rt, trap_code); + + case 0x0E: /* SWR */ + DIP("swr r%u, %u(r%u)", rt, imm, rs); + 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)); + 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 { - 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)); + 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; - } - 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)); + } + + 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 { - 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)); + t2 = newTemp(Ity_I32); + stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), NULL)); + putIReg(rt, mkWidenFrom32(ty, mkexpr(t2), True)); } + 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)); + + 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 { - 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)); + putFReg(ft, load(Ity_F32, mkexpr(t1))); } + 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))); + + 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 { - putIReg(rd, binop(Iop_And32, - unop(Iop_Not32, - unop(Iop_CmpwNEZ32, getIReg(rt))), - getIReg(rs))); + ILLEGAL_INSTRUCTON; + break; } } else { - ILLEGAL_INSTRUCTON; + return -1; } + 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)); - } + case 0x03: /* PREF */ + DIP("pref"); 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))); + + 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 { - putIReg(rd, binop(Iop_And32, - unop(Iop_CmpwNEZ32, getIReg(rt)), getIReg(rs))); + stmt(IRStmt_LLSC(MIPS_IEND, t2, mkexpr(t1), NULL)); } + + putIReg(rt, mkexpr(t2)); } else { - ILLEGAL_INSTRUCTON; + 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; - goto decode_failure; - case 0x0F: /* SYNC */ - DIP("sync 0x%x", sel); - /* Just ignore it. */ 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); + 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; - assign(tmpRs64, getIReg(rs)); - assign(tmpRt64, getIReg(rt)); + case 0x06: /* Branch on Bit Clear Plus 32 - BBIT032; Cavium OCTEON */ - 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! */ + /* 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); - 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)))); + 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))))); + } - 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)))); + 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); - 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)); + 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 + } - 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); + 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 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); + case 0x08: /* SC */ + DIP("sc r%u, %u(r%u)", rt, imm, rs); + t2 = newTemp(Ity_I1); + LOAD_STORE_PATTERN; - 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! */ + 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)); - 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)))); + mips_next_insn_if(mkexpr(t2)); - 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)))); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); - 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)); + 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))); + } - 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); + 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; - default: - goto decode_failure; - } - break; + case 0x0A: /* Branch on Bit Set - BBIT1; Cavium OCTEON */ - case 0x01: /* Regimm */ + /* 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; + } - switch (rt) { - case 0x00: /* BLTZ */ - DIP("bltz r%u, %u", rs, imm); - if (mode64) { - if (!dis_instr_branch(cins, &dres, resteerOkFn, - callback_opaque, &bstmt)) - goto decode_failure; - } 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); + 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) { - if (!dis_instr_branch(cins, &dres, resteerOkFn, - callback_opaque, &bstmt)) - goto decode_failure; - } else - dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), - mkU32(0x80000000)), mkU32(0x0)), imm, &bstmt); - break; + t2 = newTemp(Ity_I1); + LOAD_STORE_PATTERN; - 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; + 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)); - 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; + mips_next_insn_if(mkexpr(t2)); - case 0x10: /* BLTZAL */ - DIP("bltzal r%u, %u", rs, imm); - if (mode64) { - if (!dis_instr_branch(cins, &dres, resteerOkFn, - callback_opaque, &bstmt)) - goto decode_failure; - } else - dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), - mkU32(0x80000000)), mkU32(0x80000000)), imm, &bstmt); - break; + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); - 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; + assign(t5, getLLdata()); - case 0x11: /* BGEZAL */ - DIP("bgezal r%u, %u", rs, imm); - if (mode64) { - if (!dis_instr_branch(cins, &dres, resteerOkFn, - callback_opaque, &bstmt)) - goto decode_failure; - } else - dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs), - mkU32(0x80000000)), mkU32(0x0)), imm, &bstmt); - break; + stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ + MIPS_IEND, mkexpr(t1), /* addr */ + NULL, mkexpr(t5), /* expected value */ + NULL, mkexpr(t3) /* new value */))); - 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); + 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 { - 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); + 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 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); - } - case 0x1F: - /* SYNCI */ - /* Just ignore it */ + 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 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))); + 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 { - ILLEGAL_INSTRUCTON; + return -1; } + 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; - } + 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: - goto decode_failure; - } - break; + return -1; + } - case 0x04: - 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 0x14: - 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: - 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 0x15: - 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 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; + return 0; +} - case 0x17: /* 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; +static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, + Addr), + Bool resteerCisOk, + void* callback_opaque, + Long delta64, + const VexArchInfo* archinfo, + const VexAbiInfo* abiinfo, + Bool sigill_diag ) +{ - 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 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; + UInt opcode, cins, result; -#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 = newTemp(Ity_I32); - assign(tmpRs32, mkNarrowTo32(ty, getIReg(rs))); + DisResult dres; - 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! */ + static IRExpr *lastn = NULL; /* last jump addr */ + static IRStmt *bstmt = NULL; /* branch (Exit) stmt */ - 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)))); + /* The running delta */ + Int delta = (Int) delta64; - 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)))); + /* Holds eip at the start of the insn, so that we can print + consistent error messages for unimplemented insns. */ + Int delta_start = delta; - 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)); + /* Are we in a delay slot ? */ + Bool delay_slot_branch, likely_delay_slot, delay_slot_jump; - putIReg(rt, mkWidenFrom32(ty, mkexpr(t0), True)); - break; - } -#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6)) - case 0x08: { /* BEQZALC, BEQC, BOVC */ - 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)); + /* Set result defaults. */ + dres.whatNext = Dis_Continue; + dres.len = 0; + dres.continueAt = 0; + dres.jk_StopHere = Ijk_INVALID; + dres.hint = Dis_HintNone; - 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! */ + delay_slot_branch = likely_delay_slot = delay_slot_jump = False; - 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); + 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)) { + if (lastn == NULL && bstmt == NULL) { + vassert(0); + } else { + dres.whatNext = Dis_StopHere; + + if (lastn != NULL) { + delay_slot_jump = True; + } else if (bstmt != NULL) { + delay_slot_branch = True; + } } } - break; - /* In documentation for BEQC stands rs > rt and for BOVC stands rs >= rt! */ + + if (branch_or_link_likely(guest_code + delta - 4)) { + likely_delay_slot = True; + } } -#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 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 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 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 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; + /* 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 - 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; + ****mips64**** + dsll $0, $0, 3 + dsll $0, $0, 13 + dsll $0, $0, 29 + dsll $0, $0, 19 */ -#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev < 6)) - case 0x18: { /* Doubleword Add Immidiate - DADDI; MIPS64 */ - DIP("daddi r%u, r%u, %u", rt, rs, imm); - IRTemp tmpRs64 = newTemp(Ity_I64); - assign(tmpRs64, getIReg(rs)); + UInt word1 = mode64 ? 0xF8 : 0x342; + UInt word2 = mode64 ? 0x378 : 0x742; + UInt word3 = mode64 ? 0x778 : 0xC2; + UInt word4 = mode64 ? 0x4F8 : 0x4C2; - 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! */ + 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 )"); - 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)); + if (mode64) + putPC(mkU64(guest_PC_curr_instr + 20)); + else + putPC(mkU32(guest_PC_curr_instr + 20)); - putIReg(rt, mkexpr(t0)); - break; - } -#elif defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 6)) - case 0x18: { /* 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); + dres.jk_StopHere = Ijk_ClientReq; + dres.whatNext = Dis_StopHere; - 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! */ + 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; - 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 + 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"); - case 0x19: /* 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; + if (mode64) + putIReg(31, mkU64(guest_PC_curr_instr + 20)); + else + putIReg(31, mkU32(guest_PC_curr_instr + 20)); - case 0x1A: { - /* Load Doubleword Left - LDL; MIPS64 */ - vassert(mode64); - DIP("ldl r%u, %u(r%u)", rt, imm, rs); - /* t1 = addr */ + 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) - t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_Add64, getIReg(rs), mkU64(extend_s_16to64(imm)))); + vex_inject_ir(irsb, Iend_LE); #elif defined (_MIPSEB) - t1 = newTemp(Ity_I64); - assign(t1, binop(Iop_Xor64, mkU64(0x7), binop(Iop_Add64, getIReg(rs), - mkU64(extend_s_16to64(imm))))); + vex_inject_ir(irsb, Iend_BE); #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); + if (mode64) { + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_CMSTART), + mkU64(guest_PC_curr_instr))); + stmt(IRStmt_Put(offsetof(VexGuestMIPS64State, guest_CMLEN), + mkU64(20))); - assign(t5, binop(Iop_Mul64, mkexpr(t4), mkU64(0x8))); + 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))); - assign(t6, binop(Iop_Shr64, mkU64(0x00FFFFFFFFFFFFFFULL), - narrowTo(Ity_I8, mkexpr(t5)))); + putPC(mkU32(guest_PC_curr_instr + 20)); + } - assign(t7, binop(Iop_And64, getIReg(rt), mkexpr(t6))); + dres.whatNext = Dis_StopHere; + dres.jk_StopHere = Ijk_InvalICache; + dres.len = 20; + delta += 20; + goto decode_success; + } - putIReg(rt, binop(Iop_Or64, mkexpr(t7), mkexpr(t3))); - break; + /* 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*/ + } } - case 0x1B: { - /* 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; - } + switch (opcode & 0x30) { + case 0x00: + result = disInstr_MIPS_WRK_00(cins, archinfo, abiinfo, &dres, &bstmt, &lastn, + resteerOkFn, callback_opaque); - case 0x27: /* Load Word unsigned - LWU; MIPS64 */ - DIP("lwu r%u,%u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; + if (result == -1) goto decode_failure; - putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), False)); - break; + if (result == -2) goto decode_failure_dsp; - case 0x30: /* 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; + break; - case 0x34: /* 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 0x10: - case 0x38: /* 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)); + result = disInstr_MIPS_WRK_10(cins, archinfo, abiinfo, &dres, &bstmt, &lastn, + resteerOkFn, callback_opaque); - mips_next_insn_if(mkexpr(t2)); + if (result == -1) goto decode_failure; - t4 = newTemp(Ity_I32); - t5 = newTemp(Ity_I32); + if (result == -2) goto decode_failure_dsp; - assign(t5, mkNarrowTo32(ty, getLLdata())); + break; - stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ - MIPS_IEND, mkexpr(t1), /* addr */ - NULL, mkexpr(t5), /* expected value */ - NULL, mkexpr(t3) /* new value */))); + case 0x20: + result = disInstr_MIPS_WRK_20(cins); - 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; + if (result == -1) goto decode_failure; - case 0x3C: /* 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)); + if (result == -2) goto decode_failure_dsp; - mips_next_insn_if(mkexpr(t2)); + break; - t4 = newTemp(Ity_I64); - t5 = newTemp(Ity_I64); + case 0x30: + result = disInstr_MIPS_WRK_30(cins, archinfo, abiinfo, &dres, &bstmt); - assign(t5, getLLdata()); + if (result == -1) goto decode_failure; - stmt(IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t4, /* old_mem */ - MIPS_IEND, mkexpr(t1), /* addr */ - NULL, mkexpr(t5), /* expected value */ - NULL, mkexpr(t3) /* new value */))); + if (result == -2) goto decode_failure_dsp; - 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 0x37: /* 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 0x3F: /* Store Doubleword - SD; MIPS64 */ - DIP("sd r%u, %u(r%u)", rt, imm, rs); - LOAD_STORE_PATTERN; - store(mkexpr(t1), getIReg(rt)); - break; - - case 0x32: /* 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; - } - } else { - goto decode_failure; - } - break; - case 0x36: /* 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 0x3A: /* 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; + 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 { - ILLEGAL_INSTRUCTON; - } - } else { - goto decode_failure; - } - break; - case 0x3E: /* 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) goto decode_failure; - 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)); - } + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_PC), + mkU32(guest_PC_curr_instr))); + jmp_lit32(&dres, Ijk_NoDecode, guest_PC_curr_instr); } - } else { - goto decode_failure; - } - break; - - case 0x1D: /* 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 0x1E: /* 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"); - - default: - goto decode_failure; - - 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; + dres.whatNext = Dis_StopHere; + dres.len = 0; + return dres; } /* switch (opc) for the main (primary) opcode switch. */ /* All MIPS insn have 4 bytes */ @@ -33321,10 +25031,12 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, 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; } @@ -33335,6 +25047,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putPC(lastn); lastn = NULL; } + if (delay_slot_jump) { putPC(lastn); lastn = NULL; @@ -33342,7 +25055,8 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, Ijk_Call : Ijk_Boring; } - decode_success: +decode_success: + /* All decode successes end up here. */ switch (dres.whatNext) { case Dis_Continue: @@ -33350,16 +25064,21 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, putPC(mkU64(guest_PC_curr_instr + 4)); else putPC(mkU32(guest_PC_curr_instr + 4)); + break; + case Dis_ResteerU: case Dis_ResteerC: if (mode64) putPC(mkU64(dres.continueAt)); else putPC(mkU32(dres.continueAt)); + break; + case Dis_StopHere: break; + default: vassert(0); break; @@ -33368,7 +25087,7 @@ static DisResult disInstr_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *, /* 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)) + && (dres.whatNext != Dis_StopHere)) if (branch_or_jump(guest_code + delta + 4)) { dres.whatNext = Dis_StopHere; dres.jk_StopHere = Ijk_Boring; diff --git a/VEX/priv/guest_mipsdsp_toIR.c b/VEX/priv/guest_mipsdsp_toIR.c new file mode 100644 index 0000000000..430c6325cf --- /dev/null +++ b/VEX/priv/guest_mipsdsp_toIR.c @@ -0,0 +1,9688 @@ +#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" + + +/* Put value to DSPControl register. Expression e is written to DSPControl as + is. If only certain bits of DSPControl need to be changed, it should be done + before calling putDSPControl(). It could be done by reading DSPControl and + ORing it with appropriate mask. */ +static void putDSPControl(IRExpr * e) +{ + vassert(!mode64); + stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_DSPControl), e)); +} + +/* Put value to accumulator(helper function for MIPS32 DSP ASE instructions). */ +static void putAcc(UInt acNo, IRExpr * e) +{ + vassert(!mode64); + vassert(acNo <= 3); + vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64); + stmt(IRStmt_Put(accumulatorGuestRegOffset(acNo), e)); + + /* If acNo = 0, split value to HI and LO regs in order to maintain compatibility + between MIPS32 and MIPS DSP ASE insn sets. */ + if (0 == acNo) { + putLO(unop(Iop_64to32, e)); + putHI(unop(Iop_64HIto32, e)); + } +} +/*------------------------------------------------------------*/ +/*--- Disassemble a single DSP ASE instruction ---*/ +/*------------------------------------------------------------*/ + +static UInt disDSPInstr_MIPS_WRK_Special ( UInt cins ) +{ + IRTemp t1; + UInt rs, rt, rd, function, ac, ac_mfhilo; + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + function = get_function(cins); + ac = get_acNo(cins); + ac_mfhilo = get_acNo_mfhilo(cins); + + switch (function) { + case 0x10: { /* MFHI */ + DIP("mfhi ac%u r%u", ac_mfhilo, rd); + putIReg(rd, unop(Iop_64HIto32, getAcc(ac_mfhilo))); + break; + } + + case 0x11: { /* MTHI */ + DIP("mthi ac%u r%u", ac, rs); + t1 = newTemp(Ity_I32); + assign(t1, unop(Iop_64to32, getAcc(ac))); + putAcc(ac, binop(Iop_32HLto64, getIReg(rs), mkexpr(t1))); + break; + } + + case 0x12: { /* MFLO */ + DIP("mflo ac%u r%u", ac_mfhilo, rd); + putIReg(rd, unop(Iop_64to32, getAcc(ac_mfhilo))); + break; + } + + case 0x13: { /* MTLO */ + DIP("mtlo ac%u r%u", ac, rs); + t1 = newTemp(Ity_I32); + assign(t1, unop(Iop_64HIto32, getAcc(ac))); + putAcc(ac, binop(Iop_32HLto64, mkexpr(t1), getIReg(rs))); + break; + } + + case 0x18: { /* MULT */ + DIP("mult ac%u r%u, r%u", ac, rs, rt); + t1 = newTemp(Ity_I64); + assign(t1, binop(Iop_MullS32, mkNarrowTo32(Ity_I32, getIReg(rs)), + mkNarrowTo32(Ity_I32, getIReg(rt)))); + putAcc(ac, mkexpr(t1)); + break; + } + + case 0x19: { /* MULTU */ + DIP("multu ac%u r%u, r%u", ac, rs, rt); + t1 = newTemp(Ity_I64); + assign(t1, binop(Iop_MullU32, mkNarrowTo32(Ity_I32, getIReg(rs)), + mkNarrowTo32(Ity_I32, + getIReg(rt)))); + putAcc(ac, mkexpr(t1)); + break; + } + } + + return 0; +} + + +static UInt disDSPInstr_MIPS_WRK_Special2 ( UInt cins ) +{ + IRTemp t1 = 0, t2, t3; + UInt rs, rt, function, ac; + rs = get_rs(cins); + rt = get_rt(cins); + function = get_function(cins); + ac = get_acNo(cins); + + switch (function) { + case 0x00: { /* MADD */ + DIP("madd ac%u, r%u, r%u", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Add64, mkexpr(t1), mkexpr(t2))); + + putAcc(ac, mkexpr(t3)); + break; + } + + case 0x01: { /* MADDU */ + DIP("maddu ac%u r%u, r%u", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Add64, mkexpr(t2), mkexpr(t1))); + + putAcc(ac, mkexpr(t3)); + break; + } + + case 0x04: { /* MSUB */ + DIP("msub ac%u r%u, r%u", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullS32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2))); + + putAcc(ac, mkexpr(t3)); + break; + } + + case 0x05: { /* MSUBU */ + DIP("msubu ac%u r%u, r%u", ac, rs, rt); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t1, getAcc(ac)); + assign(t2, binop(Iop_MullU32, getIReg(rs), getIReg(rt))); + assign(t3, binop(Iop_Sub64, mkexpr(t1), mkexpr(t2))); + + putAcc(ac, mkexpr(t3)); + break; + } + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_ABSQ_SPH( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15, t16, t17; + UInt rt, rd, sa, dsp_imm; + + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + dsp_imm = get_dspImm(cins); + + switch (sa) { + case 0x1: { /* ABSQ_S.QB */ + DIP("absq_s.qb r%u, r%u", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I8); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I8); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I1); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I8); + t12 = newTemp(Ity_I8); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I1); + t15 = newTemp(Ity_I8); + t16 = newTemp(Ity_I32); + t17 = newTemp(Ity_I32); + + /* Absolute value of the rightmost byte (bits 7-0). */ + /* t0 - rightmost byte. */ + assign(t0, unop(Iop_16to8, unop(Iop_32to16, getIReg(rt)))); + /* t1 holds 1 if t0 is equal to 0x80, or 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t0)), + mkU32(0x00000080))); + /* t2 holds 1 if value in t0 is negative, 0 otherwise. */ + assign(t2, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00000080)), + mkU8(0x7)))); + /* t3 holds abs(t0). */ + assign(t3, IRExpr_ITE(mkexpr(t1), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t0)), + mkU8(0x1)), + mkexpr(t0)))); + + /* Absolute value of bits 15-8. */ + /* t4 - input byte. */ + assign(t4, + unop(Iop_16HIto8, unop(Iop_32to16, getIReg(rt)))); + /* t5 holds 1 if t4 is equal to 0x80, or 0 otherwise. */ + assign(t5, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t4)), + mkU32(0x00000080))); + /* t6 holds 1 if value in t4 is negative, 0 otherwise. */ + assign(t6, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15)))); + /* t3 holds abs(t4). */ + assign(t7, IRExpr_ITE(mkexpr(t5), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t4)), + mkU8(0x1)), + mkexpr(t4)))); + + /* Absolute value of bits 23-15. */ + /* t8 - input byte. */ + assign(t8, + unop(Iop_16to8, unop(Iop_32HIto16, getIReg(rt)))); + /* t9 holds 1 if t8 is equal to 0x80, or 0 otherwise. */ + assign(t9, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t8)), + mkU32(0x00000080))); + /* t6 holds 1 if value in t8 is negative, 0 otherwise. */ + assign(t10, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00800000)), + mkU8(23)))); + /* t3 holds abs(t8). */ + assign(t11, IRExpr_ITE(mkexpr(t9), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t10), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t8)), + mkU8(0x1)), + mkexpr(t8)))); + + /* Absolute value of bits 31-24. */ + /* t12 - input byte. */ + assign(t12, + unop(Iop_16HIto8, unop(Iop_32HIto16, getIReg(rt)))); + /* t13 holds 1 if t12 is equal to 0x80, or 0 otherwise. */ + assign(t13, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t12)), + mkU32(0x00000080))); + /* t14 holds 1 if value in t12 is negative, 0 otherwise. */ + assign(t14, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)))); + /* t15 holds abs(t12). */ + assign(t15, IRExpr_ITE(mkexpr(t13), + mkU8(0x7F), + IRExpr_ITE(mkexpr(t14), + binop(Iop_Add8, + unop(Iop_Not8, + mkexpr(t12)), + mkU8(0x1)), + mkexpr(t12)))); + + /* t16 holds !0 if any of input bytes is 0x80 or 0 + otherwise. */ + assign(t16, + binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t13)), + unop(Iop_1Sto32, mkexpr(t9))), + unop(Iop_1Sto32, mkexpr(t5))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t16), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + /* t17 = t15|t11|t7|t3 */ + assign(t17, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t15), mkexpr(t11)), + binop(Iop_8HLto16, mkexpr(t7), mkexpr(t3)))); + + putIReg(rd, mkexpr(t17)); + break; + } + + case 0x2: { /* REPL.QB */ + DIP("repl.qb r%u, %u", rd, dsp_imm); + vassert(!mode64); + + putIReg(rd, mkU32((dsp_imm << 24) | (dsp_imm << 16) | + (dsp_imm << 8) | (dsp_imm))); + break; + } + + case 0x3: { /* REPLV.QB */ + DIP("replv.qb r%u, r%u", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I8); + + assign(t0, unop(Iop_32to8, + binop(Iop_And32, getIReg(rt), mkU32(0xff)))); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)), + binop(Iop_8HLto16, mkexpr(t0), mkexpr(t0)))); + break; + } + + case 0x4: { /* PRECEQU.PH.QBL */ + DIP("precequ.ph.qbl r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(1)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + mkU8(9)))); + break; + } + + case 0x5: { /* PRECEQU.PH.QBR */ + DIP("precequ.ph.qbr r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(15)), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)), + mkU8(7)))); + break; + } + + case 0x6: { /* PRECEQU.PH.QBLA */ + DIP("precequ.ph.qbla r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(1)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(1)))); + break; + } + + case 0x7: { /* PRECEQU.PH.QBRA */ + DIP("precequ.ph.qbra r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + mkU8(7)), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)), + mkU8(7)))); + break; + } + + case 0x9: { /* ABSQ_S.PH */ + DIP("absq_s.ph r%u, r%u", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I16); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I16); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I16); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + /* t0 holds lower 16 bits of value in rt. */ + assign(t0, unop(Iop_32to16, getIReg(rt))); + /* t1 holds 1 if t0 is equal to 0x8000. */ + assign(t1, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, mkexpr(t0)), + mkU32(0x00008000))); + /* t2 holds 1 if value in t0 is negative, 0 otherwise. */ + assign(t2, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15)))); + /* t3 holds abs(t0). */ + assign(t3, IRExpr_ITE(mkexpr(t1), + mkU16(0x7FFF), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Add16, + unop(Iop_Not16, + mkexpr(t0)), + mkU16(0x1)), + mkexpr(t0)))); + + /* t4 holds lower 16 bits of value in rt. */ + assign(t4, unop(Iop_32HIto16, getIReg(rt))); + /* t5 holds 1 if t4 is equal to 0x8000. */ + assign(t5, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, mkexpr(t4)), + mkU32(0x00008000))); + /* t6 holds 1 if value in t4 is negative, 0 otherwise. */ + assign(t6, unop(Iop_32to1, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)))); + /* t7 holds abs(t4). */ + assign(t7, IRExpr_ITE(mkexpr(t5), + mkU16(0x7FFF), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Add16, + unop(Iop_Not16, + mkexpr(t4)), + mkU16(0x1)), + mkexpr(t4)))); + /* If any of the two input halfwords is equal 0x8000, + set bit 20 in DSPControl register. */ + assign(t8, binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t8), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + /* t9 = t7|t3 */ + assign(t9, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3))); + + putIReg(rd, mkexpr(t9)); + break; + } + + case 0xA: { /* REPL.PH */ + DIP("repl.ph r%u, %u", rd, dsp_imm); + vassert(!mode64); + UShort immediate = extend_s_10to16(dsp_imm); + + putIReg(rd, mkU32(immediate << 16 | immediate)); + break; + } + + case 0xB: { /* REPLV.PH */ + DIP("replv.ph r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, getIReg(rt)))); + break; + } + + case 0xC: { /* PRECEQ.W.PHL */ + DIP("preceq.w.phl r%u, r%u", rd, rt); + vassert(!mode64); + putIReg(rd, binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000))); + break; + } + + case 0xD: { /* PRECEQ.W.PHR */ + DIP("preceq.w.phr r%u, r%u", rd, rt); + vassert(!mode64); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + mkU16(0x0))); + break; + } + + case 0x11: { /* ABSQ_S.W */ + DIP("absq_s.w r%u, r%u", rd, rt); + vassert(!mode64); + t0 = newTemp(Ity_I1); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + + assign(t0, + binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000))); + + putDSPControl(IRExpr_ITE(mkexpr(t0), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + assign(t1, binop(Iop_CmpLT32S, getIReg(rt), mkU32(0x0))); + + assign(t2, IRExpr_ITE(mkexpr(t0), + mkU32(0x7FFFFFFF), + IRExpr_ITE(mkexpr(t1), + binop(Iop_Add32, + unop(Iop_Not32, + getIReg(rt)), + mkU32(0x1)), + getIReg(rt)))); + putIReg(rd, mkexpr(t2)); + break; + } + + case 0x1B: { /* BITREV */ + DIP("bitrev r%u, r%u", rd, rt); + vassert(!mode64); + /* 32bit reversal as seen on Bit Twiddling Hacks site + http://graphics.stanford.edu/~seander/bithacks.html + section ReverseParallel */ + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + assign(t1, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xaaaaaaaa)), + mkU8(0x1)), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x55555555)), + mkU8(0x1)))); + assign(t2, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0xcccccccc)), + mkU8(0x2)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x33333333)), + mkU8(0x2)))); + assign(t3, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0xf0f0f0f0)), + mkU8(0x4)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x0f0f0f0f)), + mkU8(0x4)))); + assign(t4, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff00ff00)), + mkU8(0x8)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x00ff00ff)), + mkU8(0x8)))); + assign(t5, binop(Iop_Or32, + binop(Iop_Shr32, + mkexpr(t4), + mkU8(0x10)), + binop(Iop_Shl32, + mkexpr(t4), + mkU8(0x10)))); + putIReg(rd, binop(Iop_Shr32, + mkexpr(t5), + mkU8(16))); + break; + } + + case 0x1C: { /* PRECEU.PH.QBL */ + DIP("preceu.ph.qbl r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(8)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + mkU8(16)))); + break; + } + + case 0x1E: { /* PRECEU.PH.QBLA */ + DIP("preceu.ph.qbla r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff000000)), + mkU8(8)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(8)))); + break; + } + + case 0x1D: { /* PRECEU.PH.QBR */ + DIP("preceu.ph.qbr r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x0000ff00)), + mkU8(8)), + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)))); + break; + } + + case 0x1F: { /* PRECEU.PH.QBRA */ + DIP("preceu.ph.qbra r%u, r%u", rd, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff0000)), + binop(Iop_And32, + getIReg(rt), + mkU32(0x000000ff)))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_EXTR_W( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15, t16, t17; + UInt rs, rt, rd, sa, ac, rddsp_mask, + wrdsp_mask, shift; + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + ac = get_acNo(cins); + rddsp_mask = get_rddspMask(cins); + wrdsp_mask = get_wrdspMask(cins); + shift = get_shift(cins); + + switch (sa) { + case 0x0: { /* EXTR.W */ + DIP("extr.w r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + + if (0 == rs) { + assign(t1, mkexpr(t0)); + } else { + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + } + + /* Check if bits 63..31 of the result in t1 aren't 0. */ + assign(t3, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0))); + /* Check if bits 63..31 of the result in t1 aren't + 0x1ffffffff. */ + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0x80000000))); + /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP + control register. */ + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t6))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + if (0 == rs) { + assign(t8, mkU64(0x0ULL)); + } else { + assign(t8, binop(Iop_And64, + binop(Iop_Shr64, + mkexpr(t0), + mkU8(rs - 1)), + mkU64(0x1ULL))); + } + + assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + + /* Repeat previous steps for the rounded value. */ + assign(t10, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0))); + assign(t11, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0))); + + assign(t12, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0xffffffff))); + assign(t13, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x80000000))); + + assign(t14, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t11))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t12)), + unop(Iop_1Sto32, mkexpr(t13))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + if (0 == rs) { + putIReg(rt, unop(Iop_64to32, mkexpr(t0))); + } else { + putIReg(rt, unop(Iop_64to32, mkexpr(t1))); + } + + break; + } + + case 0x1: { /* EXTRV.W */ + DIP("extrv.w r%u, ac%u, r%u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t15 = newTemp(Ity_I8); + + assign(t15, unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)))); + assign(t0, getAcc(ac)); + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkexpr(t15))); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + mkexpr(t15)), + mkU32(0)), + unop(Iop_64to32, mkexpr(t0)), + unop(Iop_64to32, mkexpr(t1)))); + + /* Check if bits 63..31 of the result in t1 aren't 0. */ + assign(t3, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0))); + /* Check if bits 63..31 of the result in t1 aren't + 0x1ffffffff. */ + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0x80000000))); + /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP + control register. */ + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t6))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + assign(t8, + IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + mkexpr(t15)), + mkU32(0)), + mkU64(0x0ULL), + binop(Iop_And64, + binop(Iop_Shr64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Sub32, + unop(Iop_8Uto32, + mkexpr(t15)), + mkU32(1)))), + mkU64(0x1ULL)))); + + assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + + /* Repeat previous steps for the rounded value. */ + assign(t10, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0))); + assign(t11, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0))); + + assign(t12, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0xffffffff))); + assign(t13, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x80000000))); + + assign(t14, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t11))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t12)), + unop(Iop_1Sto32, mkexpr(t13))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + break; + } + + case 0x2: { /* EXTP */ + DIP("extp r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) times.*/ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkU32(rs))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + mkU8(rs + 1))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + mkU8(rs + 1))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + mkU8(31 - rs)))); + + putIReg(rt, mkexpr(t7)); + break; + } + + case 0x3: { /* EXTPV */ + DIP("extpv r%u, ac%u, r%u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) + times. */ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkexpr(t8))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction. */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(31), + mkexpr(t8)))))); + + putIReg(rt, mkexpr(t7)); + break; + } + + case 0x4: { /* EXTR_R.W */ + DIP("extr_r.w r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t15 = newTemp(Ity_I64); + t16 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + assign(t16, binop(Iop_CmpEQ32, + mkU32(rs), + mkU32(0))); + assign(t1, IRExpr_ITE(mkexpr(t16), + mkexpr(t0), + binop(Iop_Sar64, + mkexpr(t0), + mkU8(rs)))); + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least significant bit of the shifted value + from acc. */ + assign(t15, binop(Iop_Shr64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Sub32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x1f)), + mkU32(1))))); + + assign(t8, + IRExpr_ITE(mkexpr(t16), + mkU64(0x0ULL), + binop(Iop_And64, + mkexpr(t15), + mkU64(0x0000000000000001ULL)))); + assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + putIReg(rt, unop(Iop_64to32, mkexpr(t9))); + + /* Check if bits 63..31 of the result in t1 aren't 0. */ + assign(t3, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0))); + + /* Check if bits 63..31 of the result in t1 aren't + 0x1ffffffff. */ + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0x80000000))); + /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP + control register. */ + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t6))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + /* Repeat previous steps for the rounded value. */ + assign(t10, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0))); + assign(t11, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0))); + + assign(t12, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0xffffffff))); + assign(t13, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x80000000))); + + assign(t14, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t11))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t12)), + unop(Iop_1Sto32, mkexpr(t13))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + break; + } + + case 0x5: { /* EXTRV_R.W */ + DIP("extrv_r.w r%u, ac%u, r%u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t15 = newTemp(Ity_I8); + + assign(t15, unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f)))); + assign(t0, getAcc(ac)); + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkexpr(t15))); + + /* Check if bits 63..31 of the result in t1 aren't 0. */ + assign(t3, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0))); + /* Check if bits 63..31 of the result in t1 aren't + 0x1ffffffff. */ + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0x80000000))); + /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP + control register. */ + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t6))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + assign(t8, + IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + mkexpr(t15)), + mkU32(0)), + mkU64(0x0ULL), + binop(Iop_And64, + binop(Iop_Shr64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Sub32, + unop(Iop_8Uto32, + mkexpr(t15)), + mkU32(1)))), + mkU64(0x1ULL)))); + + assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + /* Put rounded value in destination register. */ + putIReg(rt, unop(Iop_64to32, mkexpr(t9))); + + /* Repeat previous steps for the rounded value. */ + assign(t10, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0))); + assign(t11, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0))); + + assign(t12, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0xffffffff))); + assign(t13, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x80000000))); + + assign(t14, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t11))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t12)), + unop(Iop_1Sto32, mkexpr(t13))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + break; + } + + case 0x6: { /* EXTR_RS.W */ + DIP("extr_rs.w r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t16 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + + if (0 == rs) { + assign(t1, mkexpr(t0)); + } else { + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + } + + /* Check if bits 63..31 of the result in t1 aren't 0. */ + assign(t3, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0))); + /* Check if bits 63..31 of the result in t1 aren't + 0x1ffffffff. */ + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0x80000000))); + /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP + control register. */ + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t6))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + if (0 == rs) { + assign(t8, mkU64(0x0ULL)); + } else { + assign(t8, binop(Iop_And64, + binop(Iop_Shr64, + mkexpr(t0), + mkU8(rs - 1)), + mkU64(0x1ULL))); + } + + assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + + /* Repeat previous steps for the rounded value. */ + assign(t10, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0))); + assign(t11, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0))); + + assign(t12, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0xffffffff))); + assign(t13, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x80000000))); + + assign(t14, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t11))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t12)), + unop(Iop_1Sto32, mkexpr(t13))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + assign(t16, binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000))); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t16), + mkU32(0)), + mkU32(0x7fffffff), + mkU32(0x80000000)), + unop(Iop_64to32, mkexpr(t9)))); + break; + } + + case 0x7: { /* EXTRV_RS.W */ + DIP("extrv_rs.w r%u, ac%u, r%u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I32); + t15 = newTemp(Ity_I32); + t16 = newTemp(Ity_I32); + t17 = newTemp(Ity_I1); + + assign(t15, binop(Iop_And32, + getIReg(rs), + mkU32(0x1f))); + assign(t17, binop(Iop_CmpEQ32, + mkexpr(t15), + mkU32(0))); + assign(t0, getAcc(ac)); + assign(t1, IRExpr_ITE(mkexpr(t17), + mkexpr(t0), + binop(Iop_Sar64, + mkexpr(t0), + unop(Iop_32to8, + mkexpr(t15))))); + + /* Check if bits 63..31 of the result in t1 aren't 0. */ + assign(t3, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0))); + /* Check if bits 63..31 of the result in t1 aren't + 0x1ffffffff. */ + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t1)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000)), + mkU32(0x80000000))); + /* If bits 63..31 aren't 0 nor 0x1ffffffff, set DSP + control register. */ + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t5)), + unop(Iop_1Sto32, mkexpr(t6))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t7), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + /* If the last discarded bit is 1, there would be carry + when rounding, otherwise there wouldn't. We use that + fact and just add the value of the last discarded bit + to the least sifgnificant bit of the shifted value + from acc. */ + assign(t8, + IRExpr_ITE(mkexpr(t17), + mkU64(0x0ULL), + binop(Iop_And64, + binop(Iop_Shr64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t15), + mkU32(1)))), + mkU64(0x1ULL)))); + + assign(t9, binop(Iop_Add64, mkexpr(t1), mkexpr(t8))); + + /* Repeat previous steps for the rounded value. */ + assign(t10, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0))); + assign(t11, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0))); + + assign(t12, binop(Iop_CmpNE32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0xffffffff))); + assign(t13, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x80000000))); + + assign(t14, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t11))), + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t12)), + unop(Iop_1Sto32, mkexpr(t13))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + + assign(t16, binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000))); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t14), + mkU32(0)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t16), + mkU32(0)), + mkU32(0x7fffffff), + mkU32(0x80000000)), + unop(Iop_64to32, mkexpr(t9)))); + break; + } + + case 0xA: { /* EXTPDP */ + DIP("extpdp r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkU32(rs))); + + assign(t8, binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfc0)), + binop(Iop_And32, + binop(Iop_Sub32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x3f)), + mkU32(rs + 1)), + mkU32(0x3f)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + mkexpr(t8))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) times. + */ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkU32(rs))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction. */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + mkU8(rs + 1))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + mkU8(rs + 1))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + mkU8(31 - rs)))); + + putIReg(rt, mkexpr(t7)); + break; + } + + case 0xB: { /* EXTPDPV */ + DIP("extpdpv r%u, ac%u, r%u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + assign(t8, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t0, getAcc(ac)); + /* Extract pos field of DSPControl register. */ + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + + /* Check if (pos - size) >= 0 [size <= pos] + if (pos < size) + put 1 to EFI field of DSPControl register + else + extract bits from acc and put 0 to EFI field of + DSPCtrl */ + assign(t2, binop(Iop_CmpLT32U, mkexpr(t1), mkexpr(t8))); + + assign(t9, binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfc0)), + binop(Iop_And32, + binop(Iop_Sub32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x3f)), + binop(Iop_Add32, + mkexpr(t8), + mkU32(0x1))), + mkU32(0x3f)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffbfff)), + mkU32(0x4000)), + mkexpr(t9))); + + /* If pos <= 31, shift right the value from the acc + (pos-size) times and take (size+1) bits from the least + significant positions. Otherwise, shift left the value + (63-pos) times, take (size+1) bits from the most + significant positions and shift right (31-size) times. + */ + assign(t3, binop(Iop_CmpLE32U, mkexpr(t1), mkU32(31))); + + assign(t4, + IRExpr_ITE(mkexpr(t3), + unop(Iop_32to8, + binop(Iop_Sub32, + mkexpr(t1), mkexpr(t8))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(63), mkexpr(t1))))); + + assign(t5, IRExpr_ITE(mkexpr(t3), + binop(Iop_Shr64, + mkexpr(t0), mkexpr(t4)), + binop(Iop_Shl64, + mkexpr(t0), mkexpr(t4)))); + + /* t6 holds a mask for bit extraction. */ + assign(t6, + IRExpr_ITE(mkexpr(t3), + unop(Iop_Not64, + binop(Iop_Shl64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))), + unop(Iop_Not64, + binop(Iop_Shr64, + mkU64(0xffffffffffffffffULL), + unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t8), + mkU32(1))))))); + + assign(t7, IRExpr_ITE(mkexpr(t3), + unop(Iop_64to32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + binop(Iop_Shr32, + unop(Iop_64HIto32, + binop(Iop_And64, + mkexpr(t5), + mkexpr(t6))), + unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(31), + mkexpr(t8)))))); + + putIReg(rt, mkexpr(t7)); + break; + } + + case 0xE: { /* EXTR_S.H */ + DIP("extr_s.h r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Sar64, mkexpr(t0), mkU8(rs))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + assign(t9, binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t0)), + mkU32(0x80000000))), + mkexpr(t2), + getDSPControl())); + + /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0) + 1. subtract 0x7fff from t1 + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0. */ + assign(t3, binop(Iop_Sub64, + mkexpr(t1), + mkU64(0x0000000000007fffULL))); + assign(t4, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x7fffffff)))), + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + unop(Iop_64to32, + mkexpr(t3))))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x80000000)), + mkU32(0))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t4)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + /* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0 + 1. subtract t1 from 0xffffffffffff8000 + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0 */ + assign(t6, binop(Iop_Sub64, + mkU64(0xffffffffffff8000ULL), + mkexpr(t1))); + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x7fffffff)))), + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + unop(Iop_64to32, + mkexpr(t6))))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000)), + mkU32(0))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t7)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t4)), + mkU32(0x00007fff), + IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t7)), + mkU32(0xffff8000), + unop(Iop_64to32, + mkexpr(t1))))); + break; + } + + case 0xF: { /* EXTRV_S.H */ + DIP("extrv_s.h r%u, ac%u, %u", rt, ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Sar64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1f))))); + + assign(t2, binop(Iop_Or32, + getDSPControl(), mkU32(0x00800000))); + + assign(t9, binop(Iop_And32, + unop(Iop_64to32, + mkexpr(t1)), + mkU32(0x80000000))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t0)), + mkU32(0x80000000))), + mkexpr(t2), + getDSPControl())); + + /* Check if t1 > 0x7fff ((t1 - 0x7fff) > 0) + 1. subtract 0x7fff from t1 + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0. */ + assign(t3, binop(Iop_Sub64, + mkexpr(t1), + mkU64(0x0000000000007fffULL))); + assign(t4, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x7fffffff)))), + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + unop(Iop_64to32, + mkexpr(t3))))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t3)), + mkU32(0x80000000)), + mkU32(0))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t4)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + /* Check if t1<0xffffffffffff8000 (0xffffffffffff8000-t1)>0 + 1. subtract t1 from 0xffffffffffff8000 + 2. if the resulting number is positive (sign bit = 0) + and any of the other bits is 1, the value is > 0 */ + assign(t6, binop(Iop_Sub64, + mkU64(0xffffffffffff8000ULL), + mkexpr(t1))); + assign(t7, binop(Iop_And32, + binop(Iop_Or32, + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x7fffffff)))), + unop(Iop_1Sto32, + binop(Iop_CmpNE32, + mkU32(0), + unop(Iop_64to32, + mkexpr(t6))))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x80000000)), + mkU32(0))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t7)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00800000)), + getDSPControl())); + putIReg(rt, IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t4)), + mkU32(0x00007fff), + IRExpr_ITE(binop(Iop_CmpNE32, + mkU32(0), + mkexpr(t7)), + mkU32(0xffff8000), + unop(Iop_64to32, + mkexpr(t1))))); + break; + } + + case 0x12: { /* RDDSP*/ + DIP("rddsp r%u, mask 0x%x", rd, rddsp_mask); + vassert(!mode64); + + putIReg(rd, mkU32(0x0)); + + if ((rddsp_mask & 0x1) == 0x1) { + /* Read pos field (bits 5-0) of DSPControl register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x0000003F)))); + } + + if ((rddsp_mask & 0x2) == 0x2) { + /* Read scount field (bits 12-7) of DSPControl + register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00001F80)))); + } + + if ((rddsp_mask & 0x4) == 0x4) { + /* Read C field (bit 13) of DSPControl register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00002000)))); + } + + if ((rddsp_mask & 0x8) == 0x8) { + /* Read outflag field (bit s 23-16) of DSPControl + register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00FF0000)))); + } + + if ((rddsp_mask & 0x10) == 0x10) { + /* Read ccond field (bits 31-24) of DSPControl + register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0xFF000000)))); + } + + if ((rddsp_mask & 0x20) == 0x20) { + /* Read EFI field (bit 14) of DSPControl register. */ + putIReg(rd, binop(Iop_Or32, + getIReg(rd), + binop(Iop_And32, + getDSPControl(), + mkU32(0x00004000)))); + } + + if ((rddsp_mask & 0x3f) == 0x3f) { + /* Read all fields of DSPControl register. */ + putIReg(rd, getDSPControl()); + } + + break; + } + + case 0x13: { /* WRDSP */ + DIP("wrdsp r%u, mask 0x%x", rs, wrdsp_mask); + vassert(!mode64); + + if ((wrdsp_mask & 0x3f) == 0x3f) { + /* If mips64 put all fields of rs, except bit 15 and bit + 6, to DSPControl register, otherwise put all except + bits 15, 6 and bits 31..28. */ + putDSPControl(mode64 ? + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff7fbf)) : + binop(Iop_And32, + getIReg(rs), + mkU32(0x0fff7fbf))); + } else { + if ((wrdsp_mask & 0x1) == 0x1) { + /* Put bits 5-0 of rs to DSPControl register pos + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFF7F40)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x0000003F)))); + } + + if ((wrdsp_mask & 0x2) == 0x2) { + /* Put bits 12-7 of rs to DSPControl scount field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFFE03F)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00001F80)))); + } + + if ((wrdsp_mask & 0x4) == 0x4) { + /* Put bit 13 of rs to DSPControl register C + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFF5FBF)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00002000)))); + } + + if ((wrdsp_mask & 0x8) == 0x8) { + /* Put bits 23-16 of rs to DSPControl reg outflag + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFF007FBF)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00FF0000)))); + } + + if ((wrdsp_mask & 0x10) == 0x10) { + /* Put bits 31-24 of rs to DSPControl reg ccond + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x00FF7FBF)), + binop(Iop_And32, + getIReg(rs), + mode64 ? mkU32(0xFF000000) + : mkU32(0x0F000000)) + ) + ); + } + + if ((wrdsp_mask & 0x20) == 0x20) { + /* Put bit 14 of rs to DSPControl register EFI + field. */ + putDSPControl(binop(Iop_Or32, + binop(Iop_And32, + getDSPControl(), + mkU32(0xFFFF3FBF)), + binop(Iop_And32, + getIReg(rs), + mkU32(0x00004000)))); + } + } + + break; + } + + case 0x1A: { /* SHILO */ + DIP("shilo ac%u, %u", ac, shift); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + putAcc(ac, mkexpr(t0)); + + if (0x20 == (shift & 0x3f)) { + putAcc(ac, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x0))); + } else if (0x20 == (shift & 0x20)) { + assign(t1, binop(Iop_Shl64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Add32, + unop(Iop_Not32, + mkU32(shift)), + mkU32(0x1))))); + + putAcc(ac, mkexpr(t1)); + } else { + assign(t1, binop(Iop_Shr64, mkexpr(t0), mkU8(shift))); + + putAcc(ac, mkexpr(t1)); + } + + break; + } + + case 0x1B: { /* SHILOV */ + DIP("shilov ac%u, r%u", ac, rs); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + assign(t1, binop(Iop_And32, getIReg(rs), mkU32(0x3f))); + assign(t2, binop(Iop_CmpEQ32, mkexpr(t1), mkU32(0x20))); + assign(t3, binop(Iop_Shl64, + mkexpr(t0), + unop(Iop_32to8, + binop(Iop_Add32, + unop(Iop_Not32, + mkexpr(t1)), + mkU32(0x1))))); + assign(t4, binop(Iop_Shr64, + mkexpr(t0), + unop(Iop_32to8, + mkexpr(t1)))); + + putAcc(ac, + IRExpr_ITE(mkexpr(t2), + binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x20)), + mkU32(0x20)), + mkexpr(t3), + mkexpr(t4)))); + break; + } + + case 0x1F: { /* MTHLIP */ + DIP("mthlip r%u, ac%u", rs, ac); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + putAcc(ac, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t0)), + getIReg(rs))); + assign(t1, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpLE32U, + mkU32(32), + mkexpr(t1)), + binop(Iop_Or32, + binop(Iop_Sub32, + mkexpr(t1), + mkU32(32)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffffc0))), + binop(Iop_Or32, + binop(Iop_Add32, + mkexpr(t1), + mkU32(32)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffffc0))))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_LX( UInt cins ) +{ + IRTemp t0; + UInt rs, rt, rd, sa; + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x0: { /* LWX */ + DIP("lwx r%u, r%u(r%u)", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + + putIReg(rd, load(Ity_I32, mkexpr(t0))); + break; + } + + case 0x4: { /* LHX */ + DIP("lhx r%u, r%u(r%u)", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + + putIReg(rd, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t0)))); + break; + } + + case 0x6: { /* LBUX */ + DIP("lbux r%u, r%u(r%u)", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add32, getIReg(rt), getIReg(rs))); + + putIReg(rd, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t0)))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_INSV( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t6, t7, t8; + UInt rs, rt, sa; + + rs = get_rs(cins); + rt = get_rt(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x0: { /* INSV */ + DIP("insv r%u, r%u", rt, rs); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + /* t0 <- pos field of DSPControl register. */ + assign(t0, binop(Iop_And32, getDSPControl(), mkU32(0x3f))); + /* t1 <- scount field of DSPControl register. */ + assign(t1, binop(Iop_Shr32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x1f80)), + mkU8(7))); + + assign(t2, unop(Iop_32to8, + binop(Iop_Add32, + mkexpr(t1), + mkexpr(t0)))); + + /* 32-(pos+size) most significant bits of rt. */ + assign(t6, binop(Iop_Shl32, + binop(Iop_Shr32, + getIReg(rt), + mkexpr(t2)), + mkexpr(t2))); + + assign(t3, unop(Iop_32to8, + binop(Iop_Sub32, + mkU32(32), + mkexpr(t0)))); + /* Pos least significant bits of rt. */ + assign(t7, binop(Iop_Shr32, + binop(Iop_Shl32, + getIReg(rt), + mkexpr(t3)), + mkexpr(t3))); + + /* Size least significant bits of rs, + shifted to appropriate position. */ + assign(t8, binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + unop(Iop_Not32, + binop(Iop_Shl32, + mkU32(0xffffffff), + unop(Iop_32to8, + mkexpr(t1))))), + unop(Iop_32to8, + mkexpr(t0)))); + + putIReg(rt, IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), + mkU32(0)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t1), + mkU32(32)), + getIReg(rs), + binop(Iop_Or32, + mkexpr(t6), + mkexpr(t8))), + IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + mkexpr(t2)), + mkU32(32)), + binop(Iop_Or32, + mkexpr(t7), + mkexpr(t8)), + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t6), + mkexpr(t7)), + mkexpr(t8))))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_ADDU_QB( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12; + UInt rs, rt, rd, sa; + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x00: { /* ADDU.QB */ + DIP("addu.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I32); + + /* Add rightmost bytes of rs and rt. */ + assign(t0, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + /* t1 will be 1 if there is overflow, 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Add bits 15-8 of rs and rt. */ + assign(t2, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* t3 will be 1 if there is overflow, 0 otherwise. */ + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Add bits 15-8 of rs and rt. */ + assign(t4, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t5 will be 1 if there is overflow, 0 otherwise. */ + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Add bits 15-8 of rs and rt. */ + assign(t6, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t7 will be 1 if there is overflow, 0 otherwise. */ + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + + assign(t8, + binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t5))), + unop(Iop_1Sto32, mkexpr(t3))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t8), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t6)), + unop(Iop_32to8, mkexpr(t4))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t2)), + unop(Iop_32to8, mkexpr(t0))))); + break; + } + + case 0x1: { /* SUBU.QB */ + DIP("subu.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I32); + + /* Subtract rightmost bytes of rs and rt. */ + assign(t0, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + /* t1 will be 1 if there is overflow, 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Subtract bits 15-8 of rs and rt. */ + assign(t2, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* t3 will be 1 if there is overflow, 0 otherwise. */ + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Subtract bits 15-8 of rs and rt. */ + assign(t4, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t5 will be 1 if there is overflow, 0 otherwise. */ + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000100)), + mkU32(0x00000100))); + + /* Subtract bits 15-8 of rs and rt. */ + assign(t6, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t7 will be 1 if there is overflow, 0 otherwise. */ + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + + assign(t8, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t5))), + unop(Iop_1Sto32, mkexpr(t3))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t8), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t6)), + unop(Iop_32to8, mkexpr(t4))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t2)), + unop(Iop_32to8, mkexpr(t0))))); + break; + } + + case 0x04: { /* ADDU_S.QB */ + DIP("addu_s.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I8); + t12 = newTemp(Ity_I32); + + /* Add rightmost bytes of rs and rt. */ + assign(t0, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + /* t1 will be 1 if there is overflow, 0 otherwise. */ + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t2, IRExpr_ITE(mkexpr(t1), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t0)))); + + /* Add bits 15-8 of rs and rt. */ + assign(t3, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* t4 will be 1 if there is overflow, 0 otherwise. */ + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t5, IRExpr_ITE(mkexpr(t4), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t3)))); + + /* Add bits 15-8 of rs and rt. */ + assign(t6, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t7 will be 1 if there is overflow, 0 otherwise. */ + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t8, IRExpr_ITE(mkexpr(t7), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t6)))); + + /* Add bits 15-8 of rs and rt. */ + assign(t9, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + /* t10 will be 1 if there is overflow, 0 otherwise. */ + assign(t10, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t9), + mkU32(0x00000100)), + mkU32(0x00000100))); + /* Saturate if necessary. */ + assign(t11, IRExpr_ITE(mkexpr(t10), + mkU8(0xff), + unop(Iop_32to8, mkexpr(t9)))); + + assign(t12, + binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + unop(Iop_1Sto32, mkexpr(t10)), + unop(Iop_1Sto32, mkexpr(t7))), + unop(Iop_1Sto32, mkexpr(t4))), + unop(Iop_1Sto32, mkexpr(t1)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t12), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)))); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t11), mkexpr(t8)), + binop(Iop_8HLto16, mkexpr(t5), mkexpr(t2)))); + break; + } + + case 0x05: { /* SUBU_S.QB */ + DIP("subu_s.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + /* Use C function to easily calculate the result + and write it in the register more conveniently + Underflow is checked using step by step subtraction. */ + assign(t1, binop(Iop_QSub8Ux4, getIReg(rs), getIReg(rt))); + + /* Subtract each byte of rs and rt. */ + assign(t6, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t7, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t8, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t9, + binop(Iop_Sub32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + + /* Put 1 to bit 20 in DSPControl if there is underflow + in either byte. */ + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + assign(t3, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + assign(t4, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t8), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t9), + mkU32(0x00000100)), + mkU32(0x00000100))); + putDSPControl(IRExpr_ITE(mkexpr(t5), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + putIReg(rd, mkexpr(t1)); + break; + } + + case 0x6: { /* MULEU_S.PH.QBL */ + DIP("muleu_s.ph.qbl r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + + assign(t0, + unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt)))))); + + assign(t2, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x03ff0000)))); + assign(t3, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t1), + mkU32(0x03ff0000)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + getDSPControl()))); + putIReg(rd, + binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t2), + mkU16(0xffff), + unop(Iop_32to16, mkexpr(t0))), + IRExpr_ITE(mkexpr(t3), + mkU16(0xffff), + unop(Iop_32to16, mkexpr(t1))))); + break; + } + + case 0x7: { /* MULEU_S.PH.QBR */ + DIP("muleu_s.ph.qbr r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + + assign(t0, unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t1, unop(Iop_64to32, + binop(Iop_MullU32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt)))))); + + assign(t2, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x03ff0000)))); + assign(t3, binop(Iop_CmpNE32, + mkU32(0x0), + binop(Iop_And32, + mkexpr(t1), + mkU32(0x03ff0000)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)), + getDSPControl()))); + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t2), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t0))), + IRExpr_ITE(mkexpr(t3), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t1))))); + break; + } + + case 0x08: { /* ADDU.PH */ + DIP("addu.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t0))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t2))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + + case 0x9: { /* SUBU.PH */ + DIP("subu.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Substract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + + case 0xA: { /* ADDQ.PH */ + DIP("addq.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + + case 0xB: { /* SUBQ.PH */ + DIP("subq.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Subtract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Compare the signs of input value and the result. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Compare the signs of input value and the result. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t2)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + + case 0xC: { /* ADDU_S.PH */ + DIP("addu_s.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t0))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect overflow. */ + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_16Uto32, + unop(Iop_32to16, mkexpr(t2))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t3), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t2))), + IRExpr_ITE(mkexpr(t1), + mkU16(0xffff), + unop(Iop_32to16, + mkexpr(t0))))); + break; + } + + case 0xD: { /* SUBU_S.PH */ + DIP("subu_s.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + + /* Subtract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Detect underflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t2), mkU32(0x00010000)), + mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, + binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t3), + mkU16(0x0000), + unop(Iop_32to16, mkexpr(t2))), + IRExpr_ITE(mkexpr(t1), + mkU16(0x0000), + unop(Iop_32to16, mkexpr(t0))))); + break; + } + + case 0xE: { /* ADDQ_S.PH */ + DIP("addq_s.ph r%u r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I16); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Add lower halves. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t4, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t6), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t0)))); + + /* Add higher halves. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Detect overflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t5, IRExpr_ITE(mkexpr(t3), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t2)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4))); + break; + } + + case 0xF: { /* SUBQ_S.PH */ + DIP("subq_s.ph r%u r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I16); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + + /* Subtract lower halves. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t6, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t0))), + mkU32(0x1))); + /* Detect overflow or underflow. */ + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x8000)), + mkU8(15)), + mkexpr(t6))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t4, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t6), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t0)))); + + /* Subtract higher halves. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Bit 16 of the result. */ + assign(t7, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x1))); + /* Detect overflow or underflow. */ + assign(t3, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)), + mkexpr(t7))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + /* Saturate if needed. */ + assign(t5, IRExpr_ITE(mkexpr(t3), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x0)), + mkU16(0x7fff), + mkU16(0x8000)), + unop(Iop_32to16, mkexpr(t2)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t5), mkexpr(t4))); + break; + } + + case 0x10: { /* ADDSC */ + DIP("addsc r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + + /* The carry bit result out of the addition operation is + written to bit 13(the c field) of the DSPControl reg. */ + assign(t0, binop(Iop_Add64, + unop(Iop_32Uto64, getIReg(rs)), + unop(Iop_32Uto64, getIReg(rt)))); + + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1)), + mkU32(0x1))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x2000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xffffdfff)))); + + putIReg(rd, unop(Iop_64to32, mkexpr(t0))); + break; + } + + case 0x11: { /* ADDWC */ + DIP("addwc r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + + /* Get carry bit from DSPControl register. */ + assign(t0, binop(Iop_Shr32, + binop(Iop_And32, + getDSPControl(), + mkU32(0x2000)), + mkU8(0xd))); + assign(t1, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, + binop(Iop_Add32, + getIReg(rt), + mkexpr(t0))))); + + /* Extract bits 32 and 31. */ + assign(t2, binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t1)), + mkU32(0x1))); + assign(t3, binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t1)), + mkU32(0x80000000)), + mkU8(31))); + assign(t4, binop(Iop_CmpNE32, mkexpr(t2), mkexpr(t3))); + + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + putIReg(rd, unop(Iop_64to32, mkexpr(t1))); + break; + } + + case 0x12: { /* MODSUB */ + DIP("modsub r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + + /* decr_7..0 */ + assign(t0, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + + /* lastindex_15..0 */ + assign(t1, + unop(Iop_16Uto32, + binop(Iop_8HLto16, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + /* temp_15..0 */ + assign(t2, + IRExpr_ITE(binop(Iop_CmpEQ32, + getIReg(rs), + mkU32(0x00000000)), + mkexpr(t1), + binop(Iop_Sub32, + getIReg(rs), mkexpr(t0)))); + putIReg(rd, mkexpr(t2)); + break; + } + + case 0x14: { /* RADDU.W.QB */ + DIP("raddu.w.qb r%u, r%u", rd, rs); + vassert(!mode64); + putIReg(rd, binop(Iop_Add32, + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs))))), + binop(Iop_Add32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs))))))); + break; + } + + case 0x16: { /* ADDQ_S.W */ + DIP("addq_s.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + + assign(t3, binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x80000000)), + mkU8(31)), + mkexpr(t3))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000)), + unop(Iop_64to32, mkexpr(t0)))); + break; + } + + case 0x17: { /* SUBQ_S.W */ + DIP("subq_s.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Sub64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + + assign(t3, binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t0)), + mkU32(0x80000000)), + mkU8(31)), + mkexpr(t3))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00100000)), + getDSPControl())); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000)), + unop(Iop_64to32, mkexpr(t0)))); + break; + } + + case 0x1C: { /* MULEQ_S.W.PHL */ + DIP("muleq_s.w.phl r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I32); + + assign(t0, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs)))), + mkU8(0x1))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000)), + mkU32(0x80000000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff0000)), + mkU32(0x80000000))); + assign(t3, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + getDSPControl()), + getDSPControl())); + putDSPControl(mkexpr(t3)); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + mkexpr(t0)), + mkexpr(t0))); + break; + } + + case 0x1D: { /* MULEQ_S.W.PHR */ + DIP("muleq_s.w.phr r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t0, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs)))), + mkU8(0x1))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff)), + mkU32(0x8000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff)), + mkU32(0x8000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + mkexpr(t0)), + mkexpr(t0))); + break; + } + + case 0x1E: { /* MULQ_S.PH */ + DIP("mulq_s.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I16); + t3 = newTemp(Ity_I16); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t5, + unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rs)))); + assign(t6, + unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt)))); + + assign(t7, + unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rs)))); + assign(t8, + unop(Iop_16Sto32, unop(Iop_32HIto16, getIReg(rt)))); + + assign(t0, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t5), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0xffff)), + mkU32(0x8000))))); + assign(t1, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t8), + mkU32(0xffff)), + mkU32(0x8000))))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_Or32, + mkexpr(t0), + mkexpr(t1)), + mkU32(0x0)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x200000)))); + + assign(t2, unop(Iop_32HIto16, + binop(Iop_Shl32, + unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t7), + mkexpr(t8))), + mkU8(0x1)))); + assign(t3, unop(Iop_32HIto16, + binop(Iop_Shl32, + unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t5), + mkexpr(t6))), + mkU8(0x1)))); + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t1), + mkU32(0x0)), + mkexpr(t2), + mkU16(0x7fff)), + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t0), + mkU32(0x0)), + mkexpr(t3), + mkU16(0x7fff)))); + break; + } + + case 0x1F: { /* MULQ_RS.PH */ + DIP("mulq_rs.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I16); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I16); + + /* Multiply and round lower halfwords. */ + assign(t0, binop(Iop_Add32, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs)))), + mkU8(0x1)), + mkU32(0x00008000))); + assign(t1, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), mkU32(0xffff)), + mkU32(0x8000))); + assign(t2, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), mkU32(0xffff)), + mkU32(0x8000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + assign(t3, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU16(0x7fff), + unop(Iop_32HIto16, + mkexpr(t0))), + unop(Iop_32HIto16, mkexpr(t0)))); + + /* Multiply and round higher halfwords. */ + assign(t4, binop(Iop_Add32, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs)))), + mkU8(0x1)), + mkU32(0x00008000))); + assign(t5, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xffff0000)), + mkU32(0x80000000))); + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rs), + mkU32(0xffff0000)), + mkU32(0x80000000))); + putDSPControl(IRExpr_ITE(mkexpr(t5), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + getDSPControl()), + getDSPControl())); + assign(t7, IRExpr_ITE(mkexpr(t5), + IRExpr_ITE(mkexpr(t6), + mkU16(0x7fff), + unop(Iop_32HIto16, + mkexpr(t4))), + unop(Iop_32HIto16, mkexpr(t4)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t7), mkexpr(t3))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_CMPU_EQ_QB( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15; + UInt rs, rt, rd, sa; + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x0: { /* CMPU.EQ.QB */ + DIP("cmpu.eq.qb r%u, r%u", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + + assign(t1, + binop(Iop_CmpEQ32, + binop(Iop_And32, getIReg(rs), mkU32(0xff)), + binop(Iop_And32, getIReg(rt), mkU32(0xff)))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + break; + } + + case 0x1: { /* CMPU.LT.QB */ + DIP("cmpu.lt.qb r%u, r%u", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + break; + } + + case 0x2: { /* CMPU.LE.QB */ + DIP("cmpu.le.qb r%u, r%u", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + break; + } + + case 0x3: { /* PICK.QB */ + DIP("pick.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I8); + + assign(t0, getDSPControl()); + assign(t1, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x01000000)), + mkU32(0x0)), + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt))))); + assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x02000000)), + mkU32(0x0)), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt))))); + assign(t3, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x04000000)), + mkU32(0x0)), + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt))))); + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x08000000)), + mkU32(0x0)), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt))))); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t4), mkexpr(t3)), + binop(Iop_8HLto16, mkexpr(t2), mkexpr(t1)))); + break; + } + + case 0x4: { /* CMPGU.EQ.QB */ + DIP("cmpgu.eq.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + + assign(t4, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + + case 0x5: { /* CMPGU.LT.QB */ + DIP("cmpgu.lt.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + + assign(t2, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + + assign(t4, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + + case 0x6: { /* CMPGU.LE.QB */ + DIP("cmpgu.le.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + + assign(t2, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + + assign(t3, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + + assign(t4, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + + case 0x8: { /* CMP.EQ.PH */ + DIP("cmp.eq.ph r%u, r%u", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpEQ16, + unop(Iop_32to16, getIReg(rs)), + unop(Iop_32to16, getIReg(rt)))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + assign(t2, binop(Iop_CmpEQ16, + unop(Iop_32HIto16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + break; + } + + case 0x9: { /* CMP.LT.PH */ + DIP("cmp.lt.ph r%u, r%u", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLT32S, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLT32S, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + break; + } + + case 0xA: { /* CMP.LE.PH */ + DIP("cmp.le.ph r%u, r%u", rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t1, binop(Iop_CmpLE32S, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLE32S, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + break; + } + + case 0xB: { /* PICK.PH */ + DIP("pick.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I16); + + assign(t0, getDSPControl()); + + assign(t1, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x01000000)), + mkU32(0x0)), + unop(Iop_32to16, getIReg(rs)), + unop(Iop_32to16, getIReg(rt)))); + + assign(t2, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x02000000)), + mkU32(0x0)), + unop(Iop_32HIto16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t2), mkexpr(t1))); + break; + } + + case 0xC: { /* PRECRQ.QB.PH */ + DIP("precrq.qb.ph r%u, r%u, %u", rd, rs, rt); + vassert(!mode64); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + binop(Iop_8HLto16, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + break; + } + + case 0xD: { /* PRECR.QB.PH */ + DIP("precr.qb.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + binop(Iop_8HLto16, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + break; + } + + case 0xF: { /* PRECRQU_S.QB.PH */ + DIP("precrqu_s.qb.ph r%u, r%u, %u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I8); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I8); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I8); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I8); + t11 = newTemp(Ity_I1); + t12 = newTemp(Ity_I32); + t13 = newTemp(Ity_I8); + t14 = newTemp(Ity_I1); + t15 = newTemp(Ity_I32); + + assign(t4, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32to16, + binop(Iop_Shl32, + getIReg(rs), + mkU8(1)))))); + assign(t0, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t4), + mkU8(0x0))); + assign(t5, binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x00008000))); + assign(t6, binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x7fff)))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t5), + mkU32(0x0)), + IRExpr_ITE(mkexpr(t6), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000) + ), + getDSPControl()), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + assign(t7, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + binop(Iop_Shl32, + getIReg(rs), + mkU8(1)))))); + assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t7), + mkU8(0x0))); + assign(t8, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x00008000)), + mkU32(0x0))); + assign(t9, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x7fff))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(mkexpr(t8), + mkexpr(t9), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + assign(t10, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32to16, + binop(Iop_Shl32, + getIReg(rt), + mkU8(1)))))); + assign(t2, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t10), + mkU8(0x0))); + assign(t11, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0))); + assign(t12, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x7fff))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(mkexpr(t11), + mkexpr(t12), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + assign(t13, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x7fff))), + mkU8(0xff), + unop(Iop_16HIto8, + unop(Iop_32HIto16, + binop(Iop_Shl32, + getIReg(rt), + mkU8(1)))))); + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0)), + mkexpr(t13), + mkU8(0x0))); + assign(t14, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x00008000)), + mkU32(0x0))); + assign(t15, IRExpr_ITE(binop(Iop_CmpLT32U, + mkU32(0x7f80), + binop(Iop_And32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x7fff))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(mkexpr(t14), + mkexpr(t15), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00400000)))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t1), mkexpr(t0)), + binop(Iop_8HLto16, + mkexpr(t3), mkexpr(t2)))); + break; + } + + case 0x14: { /* PRECRQ.PH.W */ + DIP("precrq.ph.w r%u, r%u, %u", rd, rs, rt); + vassert(!mode64); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32HIto16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + break; + } + + case 0x15: { /* PRECRQ_RS.PH.W */ + DIP("precrq_rs.ph.w r%u, r%u, %u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + + assign(t0, binop(Iop_Add64, + binop(Iop_32HLto64, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x80000000)), + mkU8(31)), + getIReg(rs)), + mkU64(0x0000000000008000ULL))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t0)), + mkU32(0x1)), + binop(Iop_And32, + binop(Iop_Shr32, + unop(Iop_64to32, mkexpr(t0)), + mkU8(31)), + mkU32(0x1)))); + assign(t2, IRExpr_ITE(mkexpr(t1), + mkU32(0x7fffffff), + unop(Iop_64to32, mkexpr(t0)))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + assign(t3, binop(Iop_Add64, + binop(Iop_32HLto64, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + getIReg(rt)), + mkU64(0x0000000000008000ULL))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t3)), + mkU32(0x1)), + binop(Iop_And32, + binop(Iop_Shr32, + unop(Iop_64to32, mkexpr(t3)), + mkU8(31)), + mkU32(0x1)))); + assign(t5, IRExpr_ITE(mkexpr(t4), + mkU32(0x7fffffff), + unop(Iop_64to32, mkexpr(t3)))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32HIto16, mkexpr(t2)), + unop(Iop_32HIto16, mkexpr(t5)))); + break; + } + + case 0x1E: { /* PRECR_SRA.PH.W */ + DIP("precr_sra.ph.w r%u, r%u, %u", rt, rs, rd); + vassert(!mode64); + + if (0 == rd) { + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, getIReg(rs)))); + } else { + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, binop(Iop_Sar32, + getIReg(rt), + mkU8(rd))), + unop(Iop_32to16, binop(Iop_Sar32, + getIReg(rs), + mkU8(rd))))); + } + + break; + } + + case 0x1F: { /* PRECR_SRA_R.PH.W */ + DIP("precr_sra_r.ph.w r%u, r%u, %u", rt, rs, rd); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + + if (0 == rd) { + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, getIReg(rs)))); + } else { + assign(t0, binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rt), + mkU8(rd - 1)), + mkU32(0x1)), + mkU8(0x1))); + assign(t1, binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rs), + mkU8(rd - 1)), + mkU32(0x1)), + mkU8(0x1))); + putIReg(rt, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t0)), + unop(Iop_32to16, mkexpr(t1)))); + }; + + break; + } + + case 0xE: { /* PACKRL.PH */ + DIP("packrl.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, getIReg(rs)), + unop(Iop_32HIto16, getIReg(rt)))); + break; + } + + case 0x18: { /* CMPGDU.EQ.QB */ + DIP("cmpgdu.eq.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, + binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpEQ32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + + case 0x19: { /* CMPGDU.LT.QB */ + DIP("cmpgdu.lt.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLT32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + + case 0x1A: { /* CMPGDU.LE.QB */ + DIP("cmpgdu.le.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + assign(t1, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t5, IRExpr_ITE(mkexpr(t1), + mkU32(0x00000001), + mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x01000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfeffffff)))); + + assign(t2, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))))); + assign(t6, IRExpr_ITE(mkexpr(t2), + mkU32(0x00000002), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x02000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfdffffff)))); + + assign(t3, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t7, IRExpr_ITE(mkexpr(t3), + mkU32(0x00000004), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x04000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xfbffffff)))); + + assign(t4, binop(Iop_CmpLE32U, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))))); + assign(t8, IRExpr_ITE(mkexpr(t4), + mkU32(0x00000008), mkU32(0))); + putDSPControl(IRExpr_ITE(mkexpr(t4), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x08000000)), + binop(Iop_And32, + getDSPControl(), + mkU32(0xf7ffffff)))); + + putIReg(rd, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_Or32, + mkexpr(t5), mkexpr(t6)), + mkexpr(t7)), + mkexpr(t8))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_SHLL_QB( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, + t15, t16, t17; + UInt rs, rt, rd, sa; + + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x0: { /* SHLL.QB */ + DIP("shll.qb r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I1); + t10 = newTemp(Ity_I1); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* Shift bits 7..0 and 23..16. */ + assign(t0, binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff00ff)), + mkU8(rs))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xff000000)), + mkU32(0x00000000))); + assign(t2, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xff000000)), + mkU32(0xff000000))); + assign(t7, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0000ff00)), + mkU32(0x00000000))); + assign(t8, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0000ff00)), + mkU32(0x000ff00))); + /* Shift bits 15..8 and 31..24. */ + assign(t3, binop(Iop_Shl32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff00ff00)), + mkU8(8)), + mkU8(rs))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff000000)), + mkU32(0x00000000))); + assign(t5, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff000000)), + mkU32(0xff000000))); + assign(t9, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x0000ff00)), + mkU32(0x00000000))); + assign(t10, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x0000ff00)), + mkU32(0x0000ff00))); + + assign(t6, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t1)), + unop(Iop_1Uto32, + mkexpr(t2))), + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t7)), + unop(Iop_1Uto32, + mkexpr(t8)))), + binop(Iop_Or32, + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t4)), + unop(Iop_1Uto32, + mkexpr(t5))), + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t9)), + unop(Iop_1Uto32, + mkexpr(t10)))))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t6), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putIReg(rd, binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x00ff00ff)), + mkU8(8)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00ff00ff)))); + } + + break; + } + + case 0x3: { /* SHRL.QB */ + DIP("shrl.qb r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + + assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7))); + assign(t0, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t0), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t2, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t3, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t2), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t4, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t4), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t6, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t7, unop(Iop_32to8, + binop(Iop_Shr32, + mkexpr(t6), + unop(Iop_32to8, mkexpr(t9))))); + putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t9), + mkU32(0x0)), + getIReg(rt), + binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t7), + mkexpr(t5)), + binop(Iop_8HLto16, + mkexpr(t3), + mkexpr(t1))))); + break; + } + + case 0x2: { /* SHLLV.QB */ + DIP("shllv.qb r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I1); + t10 = newTemp(Ity_I1); + t11 = newTemp(Ity_I8); + + assign(t11, unop(Iop_32to8, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7)))); + /* Shift bits 7..0 and 23..16. */ + assign(t0, binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00ff00ff)), + mkexpr(t11))); + assign(t1, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xff000000)), + mkU32(0x00000000))); + assign(t2, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xff000000)), + mkU32(0xff000000))); + assign(t7, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0000ff00)), + mkU32(0x00000000))); + assign(t8, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0000ff00)), + mkU32(0x000ff00))); + /* Shift bits 15..8 and 31..24. */ + assign(t3, binop(Iop_Shl32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0xff00ff00)), + mkU8(8)), + mkexpr(t11))); + assign(t4, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff000000)), + mkU32(0x00000000))); + assign(t5, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff000000)), + mkU32(0xff000000))); + assign(t9, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x0000ff00)), + mkU32(0x00000000))); + assign(t10, binop(Iop_CmpNE32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0x0000ff00)), + mkU32(0x0000ff00))); + + assign(t6, binop(Iop_Or32, + binop(Iop_Or32, + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t1)), + unop(Iop_1Uto32, + mkexpr(t2))), + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t7)), + unop(Iop_1Uto32, + mkexpr(t8)))), + binop(Iop_Or32, + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t4)), + unop(Iop_1Uto32, + mkexpr(t5))), + binop(Iop_And32, + unop(Iop_1Uto32, + mkexpr(t9)), + unop(Iop_1Uto32, + mkexpr(t10)))))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t6), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_8Uto32, mkexpr(t11)), + mkU32(0)), + getIReg(rt), + binop(Iop_Or32, + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t3), + mkU32(0xff00ff)), + mkU8(8)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00ff00ff))))); + break; + } + + case 0x1: { /* SHRLV.QB */ + DIP("shrlv.qb r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I8); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I8); + + assign(t0, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_32to8, getIReg(rt))), + mkU8(rs)))); + assign(t1, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(rs)))); + assign(t2, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(rs)))); + assign(t3, unop(Iop_32to8, + binop(Iop_Shr32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(rs)))); + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, mkexpr(t3), mkexpr(t2)), + binop(Iop_8HLto16, mkexpr(t1), mkexpr(t0)))); + break; + } + + case 0x4: { /* SHRA.QB */ + DIP("shra.qb r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + 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); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + /* ========== GPR[rt]_31..24 ========== */ + assign(t1, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t2, + binop(Iop_Shr32, mkexpr(t1), mkU8(rs))); + /* tempD_7..0 */ + assign(t0, + binop(Iop_Or32, + mkexpr(t2), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + /* ========== GPR[rt]_23..16 ========== */ + assign(t4, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, binop(Iop_Shr32, mkexpr(t4), mkU8(rs))); + /* tempC_7..0 */ + assign(t3, + binop(Iop_Or32, + mkexpr(t5), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + /* ========== GPR[rt]_15..8 ========== */ + assign(t7, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t8, binop(Iop_Shr32, mkexpr(t7), mkU8(rs))); + /* tempB_7..0 */ + assign(t6, + binop(Iop_Or32, + mkexpr(t8), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + /* ========== GPR[rt]_7..0 ========== */ + assign(t10, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t11, binop(Iop_Shr32, mkexpr(t10), mkU8(rs))); + /* tempB_7..0 */ + assign(t9, + binop(Iop_Or32, + mkexpr(t11), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t10), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, mkU8(0x8), mkU8(rs))))); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t0)), + unop(Iop_32to8, mkexpr(t3))), + binop(Iop_8HLto16, + unop(Iop_32to8, mkexpr(t6)), + unop(Iop_32to8, mkexpr(t9))))); + break; + } + + case 0x5: { /* SHRA_R.QB */ + DIP("shra_r.qb r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I8); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + assign(t0, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t0), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs)))); + + assign(t2, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t3, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t2), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs)))); + + assign(t4, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t4), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs)))); + + assign(t6, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t7, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t6), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs)))); + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t7), mkexpr(t5)), + binop(Iop_8HLto16, + mkexpr(t3), mkexpr(t1)))); + } + + break; + } + + case 0x6: { /* SHRAV.QB */ + DIP("shrav.qb r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + + 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); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + + /* ========== GPR[rt]_31..24 ========== */ + assign(t1, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t2, + binop(Iop_Shr32, + mkexpr(t1), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempD_7..0 */ + assign(t0, + binop(Iop_Or32, + mkexpr(t2), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + /* ========== GPR[rt]_23..16 ========== */ + assign(t4, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, + binop(Iop_Shr32, + mkexpr(t4), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempC_7..0 */ + assign(t3, + binop(Iop_Or32, + mkexpr(t5), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + /* ========== GPR[rt]_15..8 ========== */ + assign(t7, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t8, + binop(Iop_Shr32, + mkexpr(t7), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempB_7..0 */ + assign(t6, + binop(Iop_Or32, + mkexpr(t8), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t7), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + /* ========== GPR[rt]_7..0 ========== */ + assign(t10, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t11, + binop(Iop_Shr32, + mkexpr(t10), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))))); + /* tempB_7..0 */ + assign(t9, + binop(Iop_Or32, + mkexpr(t11), + binop(Iop_Shl32, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t10), + mkU32(0x00000080) + ), + mkU32(0x00000080)), + mkU32(0xFFFFFFFF), + mkU32(0x00000000)), + binop(Iop_Sub8, + mkU8(0x8), + unop(Iop_32to8, binop(Iop_And32, + getIReg(rs), + mkU32(0x7))) + )))); + + putIReg(rd, + binop(Iop_16HLto32, + binop(Iop_8HLto16, + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t1), + mkexpr(t0))), + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t2), + mkexpr(t3)))), + binop(Iop_8HLto16, + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t5), + mkexpr(t6))), + unop(Iop_32to8, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + mkU32(rs), + mkU32(0x7) + ), + mkU32(0x0)), + mkexpr(t8), + mkexpr(t9)))))); + break; + } + + case 0x7: { /* SHRAV_R.QB */ + DIP("shrav_r.qb r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I8); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I8); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I8); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + + assign(t9, binop(Iop_And32, getIReg(rs), mkU32(0x7))); + assign(t8, unop(Iop_32to8, + binop(Iop_Sub32, mkexpr(t9), mkU32(0x1)))); + assign(t0, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t0), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, + mkexpr(t9))))); + + assign(t2, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t3, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t2), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t4, unop(Iop_8Sto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t5, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t4), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, mkexpr(t9))))); + + assign(t6, unop(Iop_8Sto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t7, unop(Iop_32to8, + binop(Iop_Sar32, + binop(Iop_Add32, + mkexpr(t6), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t8))), + unop(Iop_32to8, mkexpr(t9))))); + putIReg(rd, IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t9), + mkU32(0x0)), + getIReg(rt), + binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t7), + mkexpr(t5)), + binop(Iop_8HLto16, + mkexpr(t3), + mkexpr(t1))))); + break; + } + + case 0x8: { /* SHLL.PH */ + DIP("shll.ph r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + 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); + t7 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* Shift lower 16 bits. */ + assign(t0, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + + assign(t1, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t0), + mkU8(16)), + mkU32(0)))); + assign(t2, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t0), + mkU8(16)), + mkU32(0xffffffff)))); + assign(t3, binop(Iop_And32, + mkexpr(t1), + mkexpr(t2))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x1)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00008000)) + ), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + /* Shift higher 16 bits. */ + assign(t4, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + + assign(t5, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t4), + mkU8(16)), + mkU32(0)))); + assign(t6, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t4), + mkU8(16)), + mkU32(0xffffffff)))); + assign(t7, binop(Iop_And32, + mkexpr(t5), + mkexpr(t6))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x1)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x1)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00008000)), + mkU8(16)) + ), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t4)), + unop(Iop_32to16, mkexpr(t0)))); + } + + break; + } + + case 0x9: { /* SHRA.PH */ + DIP("shra.ph r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + assign(t0, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + assign(t1, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + } + + break; + } + + case 0xA: { /* SHLLV.PH */ + DIP("shllv.ph r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + + /* Shift lower 16 bits. */ + assign(t2, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t3, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x00000000))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0xffffffff))); + assign(t10, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4)))); + assign(t5, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15))); + assign(t12, binop(Iop_CmpEQ32, + mkexpr(t5), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t10), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t12), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + /* Shift higher 16 bits. */ + assign(t6, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t7, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0x00000000))); + assign(t8, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0xffffffff))); + assign(t11, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t8)))); + + assign(t9, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31))); + assign(t13, binop(Iop_CmpEQ32, + mkexpr(t9), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t11), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t13), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t6)), + unop(Iop_32to16, mkexpr(t2)))); + break; + } + + case 0xB: { /* SHRAV.PH */ + DIP("shrav.ph r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + assign(t2, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + assign(t3, binop(Iop_Sar32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + putIReg(rd, + binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t1), + unop(Iop_32HIto16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t3))), + IRExpr_ITE(mkexpr(t1), + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t2))))); + break; + } + + case 0xC: { /* SHLL_S.PH */ + DIP("shll_s.ph r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + 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); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + t12 = newTemp(Ity_I32); + t13 = newTemp(Ity_I32); + t14 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* Shift lower 16 bits. */ + assign(t0, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + + assign(t1, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t0), + mkU8(16)), + mkU32(0)))); + assign(t2, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t0), + mkU8(16)), + mkU32(0xffffffff)))); + assign(t3, binop(Iop_And32, + mkexpr(t1), + mkexpr(t2))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x1)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00008000)) + ), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + assign(t8, + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t3), + mkU32(0x1)), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x8000)), + mkU32(0)), + mkU32(0x00007fff), + mkU32(0x00008000)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0000ffff)))); + assign(t10, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + binop(Iop_And32, + mkexpr(t0), + mkU32(0x00008000))), + mkexpr(t8), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x8000)), + mkU32(0)), + mkU32(0x00007fff), + mkU32(0x00008000)))); + /* Shift higher 16 bits. */ + assign(t4, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + + assign(t5, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t4), + mkU8(16)), + mkU32(0)))); + assign(t6, unop(Iop_1Uto32, + binop(Iop_CmpNE32, + binop(Iop_Sar32, + mkexpr(t4), + mkU8(16)), + mkU32(0xffffffff)))); + assign(t7, binop(Iop_And32, + mkexpr(t5), + mkexpr(t6))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x1)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x1)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + assign(t12, binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x8000)), + mkU8(16))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkexpr(t12)), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + assign(t13, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU32(0)), + mkU32(0x7fff0000), + mkU32(0x80000000))); + assign(t9, + IRExpr_ITE(binop(Iop_CmpEQ32, + mkexpr(t7), + mkU32(0x1)), + mkexpr(t13), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x0000ffff)), + mkU8(16)))); + assign(t14, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU32(0)), + mkU32(0x7fff0000), + mkU32(0x80000000))); + assign(t11, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + binop(Iop_Shl32, + binop(Iop_And32, + mkexpr(t4), + mkU32(0x00008000)), + mkU8(16))), + mkexpr(t9), + mkexpr(t14))); + putIReg(rd, binop(Iop_Or32, + mkexpr(t10), + mkexpr(t11))); + } + + break; + } + + case 0xD: { /* SHRA_R.PH */ + DIP("shra.ph r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + assign(t0, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs))); + assign(t1, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + } + + break; + } + + case 0xE: { /* SHLLV_S.PH */ + DIP("shllv_s.ph r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I32); + t12 = newTemp(Ity_I1); + t13 = newTemp(Ity_I1); + t14 = newTemp(Ity_I16); + t15 = newTemp(Ity_I16); + t16 = newTemp(Ity_I16); + t17 = newTemp(Ity_I16); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + + /* Shift lower 16 bits. */ + assign(t2, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t3, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0x00000000))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t2))), + mkU32(0xffffffff))); + assign(t10, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t3)), + unop(Iop_1Sto32, mkexpr(t4)))); + assign(t5, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x00008000)), + mkU8(15))); + assign(t12, binop(Iop_CmpEQ32, + mkexpr(t5), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t10), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t12), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + assign(t14, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t5), + mkU32(0x0)), + mkU16(0x8000), + mkU16(0x7fff))); + assign(t15, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t10), + mkU32(0x0)), + mkexpr(t14), + IRExpr_ITE(mkexpr(t12), + unop(Iop_32to16, + mkexpr(t2)), + mkexpr(t14)))); + /* Shift higher 16 bits. */ + assign(t6, binop(Iop_Shl32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t7, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0x00000000))); + assign(t8, binop(Iop_CmpNE32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, mkexpr(t6))), + mkU32(0xffffffff))); + assign(t11, binop(Iop_And32, + unop(Iop_1Sto32, mkexpr(t7)), + unop(Iop_1Sto32, mkexpr(t8)))); + + assign(t9, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31))); + assign(t13, binop(Iop_CmpEQ32, + mkexpr(t9), + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t6), + mkU32(0x00008000)), + mkU8(15)))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t11), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t13), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + + assign(t16, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + mkU32(0x0)), + mkU16(0x8000), + mkU16(0x7fff))); + assign(t17, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t11), + mkU32(0x0)), + mkexpr(t16), + IRExpr_ITE(mkexpr(t13), + unop(Iop_32to16, + mkexpr(t6)), + mkexpr(t16)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t17), mkexpr(t15))); + break; + } + + case 0xF: { /* SHRAV_R.PH */ + DIP("shrav_r.ph r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + assign(t2, unop(Iop_32to8, + binop(Iop_Sub32, mkexpr(t0), mkU32(1)))); + + assign(t3, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t2))), + unop(Iop_32to8, mkexpr(t0)))); + assign(t4, binop(Iop_Sar32, + binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt))), + binop(Iop_Shl32, + mkU32(0x1), + mkexpr(t2))), + unop(Iop_32to8, mkexpr(t0)))); + + putIReg(rd, binop(Iop_16HLto32, + IRExpr_ITE(mkexpr(t1), + unop(Iop_32HIto16, + getIReg(rt)), + unop(Iop_32to16, + mkexpr(t4))), + IRExpr_ITE(mkexpr(t1), + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, + mkexpr(t3))))); + break; + } + + case 0x14: { /* SHLL_S.W */ + DIP("shll_s.w r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + /* t0-bits that will be discarded, sign extended to + 32bits. */ + assign(t0, binop(Iop_Sar32, + binop(Iop_And32, + getIReg(rt), + binop(Iop_Sar32, + mkU32(0x80000000), + mkU8(rs - 1))), + mkU8(32 - rs))); + + assign(t1, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU32(0x0)), + mkU32(0x7fffffff), + mkU32(0x80000000))); + + assign(t2, binop(Iop_Shl32, getIReg(rt), mkU8(rs))); + assign(t3, IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + binop(Iop_And32, + mkexpr(t2), + mkU32(0x80000000))), + mkexpr(t2), + mkexpr(t1))); + + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0xffffffff) + ), + mkexpr(t1), + mkexpr(t3)), + mkexpr(t3))); + assign(t5, IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0xffffffff)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t0), + mkU32(0x0)), + mkexpr(t5), + getDSPControl())); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + binop(Iop_And32, + mkexpr(t2), + mkU32(0x80000000)) + ), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)))); + putIReg(rd, mkexpr(t4)); + } + + break; + } + + case 0x15: { /* SHRA_R.W */ + DIP("shra_r.w r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + + if (0 == rs) { + putIReg(rd, getIReg(rt)); + } else { + putIReg(rd, binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rt), mkU8(rs)), + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(rs - 1))), + mkU8(rs - 1)))); + } + + break; + } + + case 0x16: { /* SHLLV_S.W */ + DIP("shllv_s.w r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I64); + t4 = newTemp(Ity_I1); + t5 = newTemp(Ity_I1); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I32); + + /* Check if shift amount is zero. */ + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + + /* t2 = sign of the input value. */ + assign(t2, binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31))); + /* Shift left input value and check for overflow. */ + assign(t3, binop(Iop_Shl64, + unop(Iop_32Sto64, getIReg(rt)), + unop(Iop_32to8, mkexpr(t0)))); + assign(t4, binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t3)), + mkU32(0x00000000))); + assign(t5, binop(Iop_CmpNE32, + unop(Iop_64HIto32, mkexpr(t3)), + mkU32(0xffffffff))); + assign(t6, binop(Iop_And32, + unop(Iop_1Uto32, mkexpr(t4)), + unop(Iop_1Uto32, mkexpr(t5)))); + assign(t7, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + getIReg(rt), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t3)), + mkU32(0x80000000)), + mkU8(31)))); + + putDSPControl(IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000)), + IRExpr_ITE(mkexpr(t7), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x400000))) + )); + + assign(t8, IRExpr_ITE(unop(Iop_32to1, + mkexpr(t2)), + mkU32(0x80000000), + mkU32(0x7fffffff))); + putIReg(rd, IRExpr_ITE(unop(Iop_32to1, mkexpr(t6)), + IRExpr_ITE(unop(Iop_32to1, + mkexpr(t2)), + mkU32(0x80000000), + mkU32(0x7fffffff)), + IRExpr_ITE(mkexpr(t7), + unop(Iop_64to32, + mkexpr(t3)), + mkexpr(t8)))); + break; + } + + case 0x17: { /* SHRAV_R.W */ + DIP("shrav_r.w r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x1f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + assign(t2, unop(Iop_32to8, + binop(Iop_Sub32, mkexpr(t0), mkU32(1)))); + + putIReg(rd, IRExpr_ITE(mkexpr(t1), + getIReg(rt), + binop(Iop_Sar32, + binop(Iop_Add32, + binop(Iop_Sar32, + getIReg(rt), + mkexpr(t2)), + mkU32(0x1)), + mkU8(1)))); + break; + } + + case 0x19: { /* SHRL.PH */ + DIP("shrl.ph r%u, r%u, %u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + assign(t0, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU8(rs))); + assign(t1, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU8(rs))); + putIReg(rd, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t0)))); + break; + } + + case 0x1B: { /* SHRLV.PH */ + DIP("shrlv.ph r%u, r%u, r%u", rd, rt, rs); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I16); + t5 = newTemp(Ity_I16); + + /* Get shift amount from lower 5 bits of rs + and check if it is zero. */ + assign(t0, binop(Iop_And32, getIReg(rs), mkU32(0x0f))); + assign(t1, binop(Iop_CmpEQ32, mkexpr(t0), mkU32(0x0))); + + assign(t2, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + assign(t3, binop(Iop_Shr32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_32to8, mkexpr(t0)))); + + assign(t4, IRExpr_ITE(mkexpr(t1), + unop(Iop_32HIto16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t3)))); + assign(t5, IRExpr_ITE(mkexpr(t1), + unop(Iop_32to16, getIReg(rt)), + unop(Iop_32to16, mkexpr(t2)))); + putIReg(rd, binop(Iop_16HLto32, mkexpr(t4), mkexpr(t5))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_ADDUH_QB( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12; + UInt rs, rt, rd, sa; + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x00: { /* ADDUH.QB */ + DIP("adduh.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_HAdd8Ux4, getIReg(rs), getIReg(rt))); + + putIReg(rd, mkexpr(t0)); + break; + } + + case 0x1: { /* SUBUH.QB */ + DIP("subuh.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + + assign(t0, binop(Iop_HSub8Ux4, getIReg(rs), getIReg(rt))); + + putIReg(rd, mkexpr(t0)); + break; + } + + case 0x02: { /* ADDUH_R.QB */ + DIP("adduh_r.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I8); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I8); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I8); + t9 = newTemp(Ity_I32); + t10 = newTemp(Ity_I32); + t11 = newTemp(Ity_I8); + + /* Extract input bytes, add values, add 1 and half the + result. */ + assign(t0, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs))))); + assign(t1, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t2, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t0), + mkexpr(t1)), + mkU32(0x00000001)), + mkU8(0x01))))); + + assign(t3, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs))))); + assign(t4, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t5, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t3), + mkexpr(t4)), + mkU32(0x00000001)), + mkU8(0x01))))); + + assign(t6, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t7, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t8, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t7), + mkexpr(t6)), + mkU32(0x00000001)), + mkU8(0x01))))); + + assign(t9, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t10, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t11, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Add32, + mkexpr(t9), + mkexpr(t10)), + mkU32(0x00000001)), + mkU8(0x01))))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t11), mkexpr(t8)), + binop(Iop_8HLto16, + mkexpr(t5), mkexpr(t2)))); + break; + } + + case 0x3: { /* SUBUH_R.QB */ + DIP("subuh_r.qb r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I32); + t6 = newTemp(Ity_I32); + t7 = newTemp(Ity_I32); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I8); + t10 = newTemp(Ity_I8); + t11 = newTemp(Ity_I8); + t12 = newTemp(Ity_I8); + + /* Extract each byte of rs and rt. */ + assign(t1, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs))))); + assign(t2, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs))))); + assign(t3, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t4, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs))))); + + assign(t5, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt))))); + assign(t6, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt))))); + assign(t7, unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t8, unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt))))); + + /* Add 1 to each resulting byte and half the results. */ + assign(t9, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t1), + mkexpr(t5)), + mkU32(0x00000001)), + mkU8(0x01))))); + assign(t10, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t2), + mkexpr(t6)), + mkU32(0x00000001)), + mkU8(0x01))))); + assign(t11, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t3), + mkexpr(t7)), + mkU32(0x00000001)), + mkU8(0x01))))); + assign(t12, unop(Iop_16to8, + unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_Add32, + binop(Iop_Sub32, + mkexpr(t4), + mkexpr(t8)), + mkU32(0x00000001)), + mkU8(0x01))))); + + putIReg(rd, binop(Iop_16HLto32, + binop(Iop_8HLto16, + mkexpr(t12), mkexpr(t11)), + binop(Iop_8HLto16, + mkexpr(t10), mkexpr(t9)))); + break; + } + + case 0x8: { /* ADDQH.PH */ + DIP("addqh.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I16); + + /* Add lower halfs of rs and rt + and right shift the result by 1. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0x0001fffe)), + mkU8(0x1)))); + /* Add higher halfs of rs and rt + and right shift the result by 1. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t3, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + mkexpr(t2), + mkU32(0x0001fffe)), + mkU8(0x1)))); + putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); + break; + } + + case 0x9: { /* SUBQH.PH */ + DIP("subqh.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + + putIReg(rd, binop(Iop_HSub16Sx2, + getIReg(rs), getIReg(rt))); + break; + } + + case 0xA: {/* ADDQH_R.PH */ + DIP("addqh_r.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I16); + + /* Add lower halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t0, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t0), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + /* Add higher halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t2, binop(Iop_Add32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t3, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t2), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); + break; + } + + case 0xB: { /* SUBQH_R.PH */ + DIP("subqh_r.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I16); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I16); + + /* Sub lower halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t0, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + assign(t1, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t0), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + /* Sub higher halfs of rs and rt, add 1 + and right shift the result by 1. */ + assign(t2, binop(Iop_Sub32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + assign(t3, unop(Iop_32to16, + binop(Iop_Shr32, + binop(Iop_And32, + binop(Iop_Add32, + mkexpr(t2), + mkU32(0x1)), + mkU32(0x0001fffe)), + mkU8(0x1)))); + + putIReg(rd, binop(Iop_16HLto32, mkexpr(t3), mkexpr(t1))); + break; + } + + case 0xC: { /* MUL.PH */ + DIP("mul.ph r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t0), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t0), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + assign(t1, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t1), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t1), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + assign(t2, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t0)), + unop(Iop_32to16, mkexpr(t1)))); + putIReg(rd, mkexpr(t2)); + break; + } + + case 0xE: { /* MUL_S.PH */ + DIP("mul_s.ph r%u r%u, r%u", rd, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + t4 = newTemp(Ity_I32); + + /* t0 - signed intermediate result. */ + assign(t0, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))))); + + assign(t1, + IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t0), + mkU32(0x7FFF))), + mkU32(0x00007FFF), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t0), + mkU32(0xFFFF8000)), + mkU32(0xFFFF8000), + mkexpr(t0)))); + + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t0), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t0), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + /* t2 - signed intermediate result. */ + assign(t2, binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))))); + + assign(t3, IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t2), + mkU32(0x7FFF))), + mkU32(0x00007FFF), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t2), + mkU32(0xFFFF8000)), + mkU32(0xFFFF8000), + mkexpr(t2)))); + + /* DSP Control flag. */ + putDSPControl(IRExpr_ITE(unop(Iop_Not1, + binop(Iop_CmpLE32S, + mkexpr(t2), + mkU32(0x7FFF))), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000)), + IRExpr_ITE(binop(Iop_CmpLT32S, + mkexpr(t2), + mkU32(0xFFFF8000) + ), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()))); + + assign(t4, binop(Iop_16HLto32, + unop(Iop_32to16, mkexpr(t1)), + unop(Iop_32to16, mkexpr(t3)))); + putIReg(rd, mkexpr(t4)); + break; + } + + case 0x10: { /* ADDQH.W */ + DIP("addqh.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_And64, + mkexpr(t0), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t1), mkU8(0x1)))); + break; + } + + case 0x11: { /* SUBQH.W */ + DIP("subqh.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Sub64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_And64, + mkexpr(t0), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t1), mkU8(0x1)))); + break; + } + + case 0x12: { /* ADDQH_R.W */ + DIP("addqh_r.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Add64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_Add64, + mkexpr(t0), + mkU64(0x0000000000000001ULL))); + assign(t2, binop(Iop_And64, + mkexpr(t1), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t2), mkU8(0x1)))); + break; + } + + case 0x13: { /* SUBQH_R.W */ + DIP("subqh_r.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, binop(Iop_Sub64, + unop(Iop_32Sto64, getIReg(rs)), + unop(Iop_32Sto64, getIReg(rt)))); + assign(t1, binop(Iop_Add64, + mkexpr(t0), + mkU64(0x0000000000000001ULL))); + assign(t2, binop(Iop_And64, + mkexpr(t1), + mkU64(0x00000001fffffffeULL))); + putIReg(rd, unop(Iop_64to32, + binop(Iop_Shr64, mkexpr(t2), mkU8(0x1)))); + break; + } + + case 0x16: { /* MULQ_S.W */ + DIP("mulq_s.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t0, binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rt), getIReg(rs)), + mkU8(0x1))); + assign(t1, binop(Iop_CmpEQ32, + getIReg(rt), mkU32(0x80000000))); + assign(t2, binop(Iop_CmpEQ32, + getIReg(rs), mkU32(0x80000000))); + + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + unop(Iop_64HIto32, + mkexpr(t0))), + unop(Iop_64HIto32, mkexpr(t0)))); + break; + } + + case 0x17: { /* MULQ_RS.W */ + DIP("mulq_rs.w r%u, r%u, r%u", rd, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I1); + t2 = newTemp(Ity_I1); + + assign(t0, binop(Iop_Add64, + binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rt), + getIReg(rs)), + mkU8(0x1)), + mkU64(0x0000000080000000ULL))); + assign(t1, + binop(Iop_CmpEQ32, getIReg(rt), mkU32(0x80000000))); + assign(t2, + binop(Iop_CmpEQ32, getIReg(rs), mkU32(0x80000000))); + putDSPControl(IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + binop(Iop_Or32, + getDSPControl(), + mkU32(0x00200000) + ), + getDSPControl()), + getDSPControl())); + putIReg(rd, IRExpr_ITE(mkexpr(t1), + IRExpr_ITE(mkexpr(t2), + mkU32(0x7fffffff), + unop(Iop_64HIto32, + mkexpr(t0))), + unop(Iop_64HIto32, mkexpr(t0)))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_DPAW_PH( UInt cins ) +{ + IRTemp t0, t1 = 0, t2, t3, t4, t5, t6, t7, t8, t9, t10; + UInt rs, rt, sa, ac; + + rs = get_rs(cins); + rt = get_rt(cins); + sa = get_sa(cins); + ac = get_acNo(cins); + + switch (sa) { + case 0x0: { /* DPA.W.PH */ + DIP("dpa.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, + binop(Iop_Add64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + + case 0x1: { /* DPS.W.PH */ + DIP("dps.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, + binop(Iop_Sub64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + + case 0x2: { /* MULSA.W.PH */ + DIP("mulsa.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + + assign(t4, getAcc(ac)); + assign(t0, binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))))); + assign(t1, binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))))); + assign(t2, binop(Iop_Sub32, mkexpr(t1), mkexpr(t0))); + putAcc(ac, binop(Iop_Add64, + mkexpr(t4), + unop(Iop_32Sto64, mkexpr(t2)))); + break; + } + + case 0x3: { /* DPAU.H.QBL */ + DIP("dpau.h.qbl ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + unop(Iop_32Uto64, + binop(Iop_Add32, + mkexpr(t0), + mkexpr(t1)))); + assign(t3, + binop(Iop_Add64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + break; + } + + case 0x4: { /* DPAQ_S.W.PH */ + DIP("dpaq_s.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt))) + ), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, binop(Iop_Add64, + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)), + mkexpr(t0))); + putAcc(ac, mkexpr(t9)); + break; + } + + case 0x5: { /* DPSQ_S.W.PH */ + DIP("dpsq_s.w.ph ac%u r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, + binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, + binop(Iop_Sub64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)))); + putAcc(ac, mkexpr(t9)); + break; + } + + case 0x6: { /* MULSAQ_S.W.PH */ + DIP("mulsaq_s.w.ph ac%u r%u, r%u", ac, rs, rt); + vassert(!mode64); + + 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_I64); + t7 = newTemp(Ity_I64); + t8 = newTemp(Ity_I32); + t9 = newTemp(Ity_I32); + + assign(t0, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs)))); + assign(t1, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))); + + assign(t8, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rs))), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, + getIReg(rt))), + mkU32(0x8000))))); + /* DSPControl_outflag:16+acc <- 1 */ + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t8), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x00010000), + mkU8(ac))), + getDSPControl())); + + /* tempB_31..0 */ + assign(t2, + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t8), mkU32(0x0)), + mkU32(0x7FFFFFFF), + binop(Iop_Shl32, + binop(Iop_Mul32, + mkexpr(t0), mkexpr(t1)), + mkU8(1)))); + + assign(t3, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs)))); + assign(t4, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))); + + assign(t9, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rs))), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, + getIReg(rt))), + mkU32(0x8000))))); + /* DSPControl_outflag:16+acc <- 1 */ + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + mkU32(0x0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x00010000), + mkU8(ac))), + getDSPControl())); + /* tempA_31..0 */ + assign(t5, + IRExpr_ITE(binop(Iop_CmpNE32, + mkexpr(t9), + mkU32(0x0)), + mkU32(0x7FFFFFFF), + binop(Iop_Shl32, + binop(Iop_Mul32, + mkexpr(t3), + mkexpr(t4)), + mkU8(1)))); + /* dotp_63..0 */ + assign(t6, + binop(Iop_Sub64, + unop(Iop_32Sto64, mkexpr(t2)), + unop(Iop_32Sto64, mkexpr(t5)))); + /* tempC_63..0 */ + assign(t7, binop(Iop_Add64, getAcc(ac), mkexpr(t6))); + + putAcc(ac, mkexpr(t7)); + break; + } + + case 0x7: { /* DPAU.H.QBR */ + DIP("dpau.h.qbr ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, unop(Iop_32Uto64, + binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); + assign(t3, binop(Iop_Add64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + break; + } + + case 0x8: { /* DPAX.W.PH */ + DIP("dpax.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + binop(Iop_Add64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + + case 0x9: { /* DPSX.W.PH */ + DIP("dpsx.w.ph ac%u r%u, r%u", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I64); + + assign(t0, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + unop(Iop_32Sto64, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + binop(Iop_Sub64, + getAcc(ac), + binop(Iop_Add64, mkexpr(t0), mkexpr(t1)))); + putAcc(ac, mkexpr(t2)); + break; + } + + case 0xB: { /* DPSU.H.QBL */ + DIP("dpsu.h.qbl ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32HIto16, getIReg(rt)))))); + assign(t2, + unop(Iop_32Uto64, + binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); + assign(t3, + binop(Iop_Sub64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + break; + } + + case 0xC: { /* DPAQ_SA.L.W */ + DIP("dpaq_sa.l.w ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I64); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rs), getIReg(rt)), + mkU8(0x1))); + + assign(t2, binop(Iop_CmpEQ32, + getIReg(rs), + mkU32(0x80000000))); + assign(t3, binop(Iop_CmpEQ32, + getIReg(rt), + mkU32(0x80000000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x7fffffffffffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Add64, + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t0))), + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t4))))); + assign(t6, + binop(Iop_Add64, + binop(Iop_Add64, + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t0))), + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t4)))), + unop(Iop_32Uto64, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t5)), + mkU32(0x1))))); + assign(t7, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t6)), + unop(Iop_64to32, mkexpr(t5)))); + assign(t8, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x00000001)))); + assign(t9, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t6)), + mkU32(0x00000001)), + mkU32(0x1))); + putDSPControl(IRExpr_ITE(mkexpr(t8), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + putAcc(ac, + IRExpr_ITE(mkexpr(t8), + mkexpr(t7), + IRExpr_ITE(mkexpr(t9), + mkU64(0x8000000000000000ULL), + mkU64(0x7fffffffffffffffULL))) + ); + break; + } + + case 0xD: { /* DPSQ_SA.L.W */ + DIP("dpsq_sa.l.w ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I64); + t7 = newTemp(Ity_I64); + t8 = newTemp(Ity_I1); + t9 = newTemp(Ity_I1); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + getIReg(rs), getIReg(rt)), + mkU8(0x1))); + + assign(t2, binop(Iop_CmpEQ32, + getIReg(rs), + mkU32(0x80000000))); + assign(t3, binop(Iop_CmpEQ32, + getIReg(rt), + mkU32(0x80000000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x7fffffffffffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Sub64, + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t0))), + unop(Iop_32Uto64, + unop(Iop_64to32, mkexpr(t4))))); + assign(t6, binop(Iop_Sub64, + binop(Iop_Add64, + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t0)) + ), + unop(Iop_32Sto64, + unop(Iop_1Sto32, + binop(Iop_CmpLT32U, + unop(Iop_64to32, + mkexpr(t0)), + unop(Iop_64to32, + mkexpr(t4)))))), + unop(Iop_32Sto64, + unop(Iop_64HIto32, mkexpr(t4))))); + assign(t7, binop(Iop_32HLto64, + unop(Iop_64to32, mkexpr(t6)), + unop(Iop_64to32, mkexpr(t5)))); + assign(t8, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t6)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x00000001)))); + assign(t9, binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t6)), + mkU32(0x00000001)), + mkU32(0x1))); + putDSPControl(IRExpr_ITE(mkexpr(t8), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + putAcc(ac, + IRExpr_ITE(mkexpr(t8), + mkexpr(t7), + IRExpr_ITE(mkexpr(t9), + mkU64(0x8000000000000000ULL), + mkU64(0x7fffffffffffffffULL))) + ); + break; + } + + case 0xF: { /* DPSU.H.QBR */ + DIP("dpsu.h.qbr ac%u r%u, r%u", ac, rs, rt); + vassert(!mode64); + + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I64); + t3 = newTemp(Ity_I64); + + assign(t0, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16HIto8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t1, + binop(Iop_Mul32, + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rs)))), + unop(Iop_8Uto32, + unop(Iop_16to8, + unop(Iop_32to16, getIReg(rt)))))); + assign(t2, unop(Iop_32Uto64, + binop(Iop_Add32, mkexpr(t0), mkexpr(t1)))); + assign(t3, binop(Iop_Sub64, getAcc(ac), mkexpr(t2))); + putAcc(ac, mkexpr(t3)); + + break; + } + + case 0x10: { /* MAQ_SA.W.PHL */ + DIP("maq_sa.w.phl ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl register. + */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Add intermediate product and value in the + accumulator. */ + assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4))); + + /* Compare bits 31 and 32 of the value in t5. */ + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t5)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t5)), + mkU32(1)))); + putDSPControl(IRExpr_ITE(mkexpr(t6), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + assign(t7, + IRExpr_ITE(mkexpr(t6), + mkexpr(t5), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t5)), + mkU32(1)), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkU64(0xffffffff80000000ULL))) + ); + putAcc(ac, mkexpr(t7)); + break; + } + + case 0x12: { /* MAQ_SA.W.PHR */ + DIP("maq_sa.w.phr ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + /* Add intermediate product and value in the + accumulator. */ + assign(t5, binop(Iop_Add64, mkexpr(t0), mkexpr(t4))); + + /* Compare bits 31 and 32 of the value in t5. */ + assign(t6, binop(Iop_CmpEQ32, + binop(Iop_Shr32, + binop(Iop_And32, + unop(Iop_64to32, mkexpr(t5)), + mkU32(0x80000000)), + mkU8(31)), + binop(Iop_And32, + unop(Iop_64HIto32, mkexpr(t5)), + mkU32(1)))); + putDSPControl(IRExpr_ITE(mkexpr(t6), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + assign(t7, + IRExpr_ITE(mkexpr(t6), + mkexpr(t5), + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t5)), + mkU32(1)), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkU64(0xffffffff80000000ULL))) + ); + putAcc(ac, mkexpr(t7)); + break; + } + + case 0x14: { /* MAQ_S.W.PHL */ + DIP("maq_s.w.phl ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + + assign(t5, getAcc(ac)); + + assign(t0, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rs)))); + assign(t1, unop(Iop_16Sto32, + unop(Iop_32HIto16, getIReg(rt)))); + + assign(t2, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0xffff)), + mkU32(0x8000))))); + + assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + + assign(t4, unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t0), mkexpr(t1)))); + putAcc(ac, IRExpr_ITE(mkexpr(t3), + binop(Iop_Add64, + unop(Iop_32Sto64, + binop(Iop_Shl32, + mkexpr(t4), + mkU8(0x1))), + mkexpr(t5)), + binop(Iop_Add64, + mkexpr(t5), + unop(Iop_32Sto64, + mkU32(0x7fffffff))))); + break; + } + + case 0x16: { /* MAQ_S.W.PHR */ + DIP("maq_s.w.phr ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I32); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I32); + t5 = newTemp(Ity_I64); + + assign(t5, getAcc(ac)); + + assign(t0, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rs)))); + assign(t1, unop(Iop_16Sto32, + unop(Iop_32to16, getIReg(rt)))); + + assign(t2, binop(Iop_And32, + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t0), + mkU32(0xffff)), + mkU32(0x8000))), + unop(Iop_1Sto32, + binop(Iop_CmpEQ32, + binop(Iop_And32, + mkexpr(t1), + mkU32(0xffff)), + mkU32(0x8000))))); + + assign(t3, binop(Iop_CmpEQ32, mkexpr(t2), mkU32(0x0))); + + putDSPControl(IRExpr_ITE(mkexpr(t3), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + + assign(t4, unop(Iop_64to32, + binop(Iop_MullS32, + mkexpr(t0), mkexpr(t1)))); + putAcc(ac, IRExpr_ITE(mkexpr(t3), + binop(Iop_Add64, + unop(Iop_32Sto64, + binop(Iop_Shl32, + mkexpr(t4), + mkU8(0x1))), + mkexpr(t5)), + binop(Iop_Add64, + mkexpr(t5), + unop(Iop_32Sto64, + mkU32(0x7fffffff))))); + break; + } + + case 0x18: { /* DPAQX_S.W.PH */ + DIP("dpaqx_s.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, binop(Iop_Add64, + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)), + mkexpr(t0))); + putAcc(ac, mkexpr(t9)); + break; + } + + case 0x19: { /* DPSQX_S.W.PH */ + DIP("dpsqx_s.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + + assign(t0, getAcc(ac)); + + assign(t1, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1))); + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + assign(t4, + IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + mkU64(0x000000007fffffffULL), + mkexpr(t1)), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(mkexpr(t2), + IRExpr_ITE(mkexpr(t3), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t5, binop(Iop_Shl64, + binop(Iop_MullS32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1))); + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + assign(t8, + IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + mkU64(0x000000007fffffffULL), + mkexpr(t5)), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(mkexpr(t6), + IRExpr_ITE(mkexpr(t7), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16) + ) + ), + getDSPControl()), + getDSPControl())); + + assign(t9, binop(Iop_Sub64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t4), mkexpr(t8)))); + putAcc(ac, mkexpr(t9)); + break; + } + + case 0x1A: { /* DPAQX_SA.W.PH */ + DIP("dpaqx_sa.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Calculate the first cross dot product and saturate if + needed. */ + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t2)), + unop(Iop_1Sto32, + mkexpr(t3))), + mkU32(0)), + mkU64(0x000000007fffffffULL), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t2)), + unop(Iop_1Sto32, + mkexpr(t3))), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))), + getDSPControl())); + /* Calculate second cross dot product and saturate if + needed. */ + assign(t5, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t8, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t6)), + unop(Iop_1Sto32, + mkexpr(t7))), + mkU32(0)), + mkU64(0x000000007fffffffULL), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t6)), + unop(Iop_1Sto32, + mkexpr(t7))), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))), + getDSPControl())); + /* Subtract intermediate products from value in the + accumulator. */ + assign(t9, + binop(Iop_Add64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t8), mkexpr(t4)))); + + putAcc(ac, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkexpr(t9)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0xffffffff)), + mkU64(0xffffffff80000000ULL), + mkexpr(t9)))); + assign(t10, IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_64to32, + mkexpr(t9)), + unop(Iop_64to32, + getAcc(ac))), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_64HIto32, + mkexpr(t9)), + unop(Iop_64HIto32, + getAcc(ac))), + mkexpr(t10), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + break; + } + + case 0x1B: { /* DPSQX_SA.W.PH */ + DIP("dpsqx_sa.w.ph ac%u, r%u, r%u", ac, rs, rt); + vassert(!mode64); + t0 = newTemp(Ity_I64); + t1 = newTemp(Ity_I64); + t2 = newTemp(Ity_I1); + t3 = newTemp(Ity_I1); + t4 = newTemp(Ity_I64); + t5 = newTemp(Ity_I64); + t6 = newTemp(Ity_I1); + t7 = newTemp(Ity_I1); + t8 = newTemp(Ity_I64); + t9 = newTemp(Ity_I64); + t10 = newTemp(Ity_I32); + + assign(t0, getAcc(ac)); + /* Calculate the first cross dot product and saturate if + needed. */ + assign(t1, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t2, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rs))), + mkU32(0x00008000))); + assign(t3, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t4, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t2)), + unop(Iop_1Sto32, + mkexpr(t3))), + mkU32(0)), + mkU64(0x000000007fffffffULL), + mkexpr(t1))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t2)), + unop(Iop_1Sto32, + mkexpr(t3))), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))), + getDSPControl())); + /* Calculate second cross dot product and saturate if + needed. */ + assign(t5, unop(Iop_32Sto64, + binop(Iop_Shl32, + binop(Iop_Mul32, + unop(Iop_16Sto32, + unop(Iop_32to16, + getIReg(rs))), + unop(Iop_16Sto32, + unop(Iop_32HIto16, + getIReg(rt)))), + mkU8(0x1)))); + + /* If both input arguments are equal 0x8000, saturate + intermediate product and write to DSPControl + register. */ + assign(t6, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32to16, getIReg(rs))), + mkU32(0x00008000))); + assign(t7, binop(Iop_CmpEQ32, + unop(Iop_16Uto32, + unop(Iop_32HIto16, getIReg(rt))), + mkU32(0x00008000))); + + assign(t8, IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t6)), + unop(Iop_1Sto32, + mkexpr(t7))), + mkU32(0)), + mkU64(0x000000007fffffffULL), + mkexpr(t5))); + + putDSPControl(IRExpr_ITE(binop(Iop_CmpNE32, + binop(Iop_And32, + unop(Iop_1Sto32, + mkexpr(t6)), + unop(Iop_1Sto32, + mkexpr(t7))), + mkU32(0)), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))), + getDSPControl())); + /* Subtract intermediate products from value in the + accumulator. */ + assign(t9, + binop(Iop_Sub64, + mkexpr(t0), + binop(Iop_Add64, mkexpr(t8), mkexpr(t4)))); + + putAcc(ac, + IRExpr_ITE(binop(Iop_CmpEQ32, + binop(Iop_And32, + unop(Iop_64HIto32, + mkexpr(t9)), + mkU32(0x80000000)), + mkU32(0x0)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0x0)), + mkU64(0x000000007fffffffULL), + mkexpr(t9)), + IRExpr_ITE(binop(Iop_CmpNE32, + unop(Iop_64HIto32, + binop(Iop_Shl64, + mkexpr(t9), + mkU8(1))), + mkU32(0xffffffff)), + mkU64(0xffffffff80000000ULL), + mkexpr(t9)))); + assign(t10, IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_64to32, + mkexpr(t9)), + unop(Iop_64to32, + getAcc(ac))), + getDSPControl(), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + putDSPControl(IRExpr_ITE(binop(Iop_CmpEQ32, + unop(Iop_64HIto32, + mkexpr(t9)), + unop(Iop_64HIto32, + getAcc(ac))), + mkexpr(t10), + binop(Iop_Or32, + getDSPControl(), + binop(Iop_Shl32, + mkU32(0x1), + mkU8(ac + 16))))); + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3_APPEND( UInt cins ) +{ + IRTemp t1 = 0, t2, t3; + UInt rs, rt, rd, sa; + + rs = get_rs(cins); + rt = get_rt(cins); + rd = get_rd(cins); + sa = get_sa(cins); + + switch (sa) { + case 0x0: { /* APPEND */ + DIP("append r%u, r%u, %u", rt, rs, rd); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + assign(t1, binop(Iop_Shl32, getIReg(rt), mkU8(rd))); + + if (31 == rd) { + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_And32, + getIReg(rs), + mkU32(0x7fffffff)))); + } else if (1 == rd) { + putIReg(rt, + binop(Iop_Or32, + mkexpr(t1), + binop(Iop_And32, + getIReg(rs), mkU32(0x1)))); + } else { + assign(t2, + unop(Iop_Not32, + binop(Iop_Shl32, + mkU32(0xffffffff), mkU8(rd)))); + + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_And32, + getIReg(rs), mkexpr(t2)))); + } + + break; + } + + case 0x1: { /* PREPEND */ + DIP("prepend r%u, r%u, %u", rt, rs, rd); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + if (0 != rd) { + assign(t1, binop(Iop_Shr32, getIReg(rt), mkU8(rd))); + + if (31 == rd) { + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x7fffffff)), + mkU8(1)))); + } else if (1 == rd) { + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + mkU32(0x1)), + mkU8(31)))); + } else { + assign(t2, binop(Iop_Add32, mkU32(rd), mkU32(0x1))); + + assign(t3, unop(Iop_Not32, + binop(Iop_Shl32, + mkU32(0xffffffff), + unop(Iop_32to8, mkexpr(t2))))); + + putIReg(rt, binop(Iop_Or32, + mkexpr(t1), + binop(Iop_Shl32, + binop(Iop_And32, + getIReg(rs), + mkexpr(t3)), + mkU8(32 - rd)))); + } + } + + break; + } + + case 0x10: { /* BALIGN */ + DIP("balign r%u, r%u, %u", rt, rs, rd); + vassert(!mode64); + t1 = newTemp(Ity_I32); + t2 = newTemp(Ity_I32); + t3 = newTemp(Ity_I32); + + if ((2 != rd) && (0 != rd)) { + assign(t1, binop(Iop_Shl32, + binop(Iop_And32, + mkU32(rd), mkU32(0x3)), + mkU8(0x3))); + assign(t2, binop(Iop_Shl32, + getIReg(rt), + unop(Iop_32to8, mkexpr(t1)))); + assign(t3, binop(Iop_Shr32, + getIReg(rs), + unop(Iop_32to8, + binop(Iop_Shl32, + binop(Iop_Sub32, + mkU32(0x4), + binop(Iop_And32, + mkU32(rd), + mkU32(0x3))), + mkU8(0x3))))); + putIReg(rt, binop(Iop_Or32, mkexpr(t2), mkexpr(t3))); + } + + break; + } + + default: + return -1; + } + + return 0; +} + +static UInt disDSPInstr_MIPS_WRK_Special3( UInt cins ) +{ + switch (get_function(cins)) { + case 0x12: { /* ABSQ_S.PH */ + return disDSPInstr_MIPS_WRK_Special3_ABSQ_SPH(cins); + } + + case 0x38: { /* EXTR.W */ + return disDSPInstr_MIPS_WRK_Special3_EXTR_W(cins); + } + + case 0xA: { /* LX */ + return disDSPInstr_MIPS_WRK_Special3_LX(cins); + } + + case 0xC: { /* INSV */ + return disDSPInstr_MIPS_WRK_Special3_INSV(cins); + } + + case 0x10: { /* ADDU.QB */ + return disDSPInstr_MIPS_WRK_Special3_ADDU_QB(cins); + } + + case 0x11: { /* CMPU.EQ.QB */ + return disDSPInstr_MIPS_WRK_Special3_CMPU_EQ_QB(cins); + } + + case 0x13: { /* SHLL.QB */ + return disDSPInstr_MIPS_WRK_Special3_SHLL_QB(cins); + } + + case 0x18: { /* ADDUH.QB/MUL.PH */ + return disDSPInstr_MIPS_WRK_Special3_ADDUH_QB(cins); + } + + case 0x30: { /* DPA.W.PH */ + return disDSPInstr_MIPS_WRK_Special3_DPAW_PH(cins); + } + + case 0x31: { /* APPEND */ + return disDSPInstr_MIPS_WRK_Special3_APPEND(cins); + } + + default: + return -1; + } +} + +UInt disDSPInstr_MIPS_WRK ( UInt cins ) +{ + UInt opcode = get_opcode(cins); + + switch (opcode) { + case 0x00: { /* Special */ + return disDSPInstr_MIPS_WRK_Special(cins); + } + + case 0x1C: { /* Special2 */ + return disDSPInstr_MIPS_WRK_Special2(cins); + } + + case 0x1F: { /* Special3 */ + return disDSPInstr_MIPS_WRK_Special3(cins); + } + + default: + return -1; + } +} diff --git a/VEX/priv/mips_defs.h b/VEX/priv/mips_defs.h new file mode 100644 index 0000000000..fed46ac34c --- /dev/null +++ b/VEX/priv/mips_defs.h @@ -0,0 +1,421 @@ + +/*---------------------------------------------------------------*/ +/*--- begin mips_defs.h ---*/ +/*---------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2017-2019 RT-RK + mips-valgrind@rt-rk.com + + 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, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ +#ifndef __VEX_MIPS_DEFS_H +#define __VEX_MIPS_DEFS_H + +#include "libvex_basictypes.h" +#include "libvex_ir.h" +#include "libvex.h" + +/* MOD: The IRSB* into which we're generating code. */ +extern IRSB *irsb; + +/* Is our guest binary 32 or 64bit? Set at each call to + disInstr_MIPS below. */ +extern Bool mode64; + +/* Pointer to the guest code area. */ +extern const UChar *guest_code; + +/*------------------------------------------------------------*/ +/*--- DSP to IR function ---*/ +/*------------------------------------------------------------*/ + +UInt disDSPInstr_MIPS_WRK ( UInt ); + +/*------------------------------------------------------------*/ +/*--- Debugging output ---*/ +/*------------------------------------------------------------*/ + +#define DIP(format, args...) \ + if (vex_traceflags & VEX_TRACE_FE) \ + vex_printf(format, ## args) + +/* ------------ MIPS32 DSP ASE(r2) accumulators ------------- */ + +extern UInt accumulatorGuestRegOffset( UInt ); + +/*------------------------------------------------------------*/ +/*--- Helper bits and pieces for creating IR fragments. ---*/ +/*------------------------------------------------------------*/ + +static inline IRExpr *mkU8(UInt i) +{ + vassert(i < 256); + return IRExpr_Const(IRConst_U8((UChar) i)); +} + +/* Create an expression node for a 16-bit integer constant. */ +static inline IRExpr *mkU16(UInt i) +{ + return IRExpr_Const(IRConst_U16(i)); +} + +/* Create an expression node for a 32-bit integer constant. */ +static inline IRExpr *mkU32(UInt i) +{ + return IRExpr_Const(IRConst_U32(i)); +} + +/* Create an expression node for a 64-bit integer constant. */ +static inline IRExpr *mkU64(ULong i) +{ + return IRExpr_Const(IRConst_U64(i)); +} + +static inline IRExpr *mkexpr(IRTemp tmp) +{ + return IRExpr_RdTmp(tmp); +} + +static inline IRExpr *unop(IROp op, IRExpr * a) +{ + return IRExpr_Unop(op, a); +} + +static inline IRExpr *binop(IROp op, IRExpr * a1, IRExpr * a2) +{ + return IRExpr_Binop(op, a1, a2); +} + +static inline IRExpr *triop(IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3) +{ + return IRExpr_Triop(op, a1, a2, a3); +} + +static inline IRExpr *qop ( IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3, + IRExpr * a4 ) +{ + return IRExpr_Qop(op, a1, a2, a3, a4); +} + +static inline IRExpr *load(IRType ty, IRExpr * addr) +{ + IRExpr *load1 = NULL; +#if defined (_MIPSEL) + load1 = IRExpr_Load(Iend_LE, ty, addr); +#elif defined (_MIPSEB) + load1 = IRExpr_Load(Iend_BE, ty, addr); +#endif + return load1; +} + +/* Add a statement to the list held by "irsb". */ +static inline void stmt(IRStmt * st) +{ + addStmtToIRSB(irsb, st); +} + +static inline void assign(IRTemp dst, IRExpr * e) +{ + stmt(IRStmt_WrTmp(dst, e)); +} + +static inline void store(IRExpr * addr, IRExpr * data) +{ +#if defined (_MIPSEL) + stmt(IRStmt_Store(Iend_LE, addr, data)); +#elif defined (_MIPSEB) + stmt(IRStmt_Store(Iend_BE, addr, data)); +#endif +} + +/* Generate a new temporary of the given type. */ +static inline IRTemp newTemp(IRType ty) +{ + vassert(isPlausibleIRType(ty)); + return newIRTemp(irsb->tyenv, ty); +} + +static inline UShort extend_s_9to16(UInt x) +{ + return (UShort) ((((Int) x) << 23) >> 23); +} + +static inline UShort extend_s_10to16(UInt x) +{ + return (UShort) ((((Int) x) << 22) >> 22); +} + +static inline UInt extend_s_10to32(UInt x) +{ + return (UInt)((((Int) x) << 22) >> 22); +} + +static inline ULong extend_s_10to64(UInt x) +{ + return (ULong)((((Long) x) << 54) >> 54); +} + +static inline UInt extend_s_16to32(UInt x) +{ + return (UInt) ((((Int) x) << 16) >> 16); +} + +static inline UInt extend_s_18to32(UInt x) +{ + return (UInt) ((((Int) x) << 14) >> 14); +} + +static inline UInt extend_s_19to32(UInt x) +{ + return (UInt) ((((Int) x) << 13) >> 13); +} + +static inline UInt extend_s_23to32(UInt x) +{ + return (UInt) ((((Int) x) << 9) >> 9); +} + +static inline UInt extend_s_26to32(UInt x) +{ + return (UInt) ((((Int) x) << 6) >> 6); +} + +static inline ULong extend_s_16to64 ( UInt x ) +{ + return (ULong) ((((Long) x) << 48) >> 48); +} + +static inline ULong extend_s_18to64 ( UInt x ) +{ + return (ULong) ((((Long) x) << 46) >> 46); +} + +static inline ULong extend_s_19to64(UInt x) +{ + return (ULong) ((((Long) x) << 45) >> 45); +} + +static inline ULong extend_s_23to64(UInt x) +{ + return (ULong) ((((Long) x) << 41) >> 41); +} + +static inline ULong extend_s_26to64(UInt x) +{ + return (ULong) ((((Long) x) << 38) >> 38); +} + +static inline ULong extend_s_32to64 ( UInt x ) +{ + return (ULong) ((((Long) x) << 32) >> 32); +} + +extern IRExpr *getIReg(UInt); + +extern void putIReg(UInt, IRExpr *); + +/* 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. */ +extern IRExpr *getAcc(UInt acNo); + +extern IRExpr *getDSPControl(void); + +extern IRExpr *mkNarrowTo32(IRType, IRExpr *); + +extern void putLO(IRExpr *); + +extern void putHI(IRExpr *); + +/*------------------------------------------------------------*/ +/*--- Field helpers ---*/ +/*------------------------------------------------------------*/ + +static inline UInt get_opcode(UInt mipsins) +{ + return (0xFC000000 & mipsins) >> 26; +} + +static inline UInt get_rs(UInt mipsins) +{ + return (0x03E00000 & mipsins) >> 21; +} + +static inline UInt get_rt(UInt mipsins) +{ + return (0x001F0000 & mipsins) >> 16; +} + +static inline UInt get_imm(UInt mipsins) +{ + return (0x0000FFFF & mipsins); +} + +static inline UInt get_instr_index(UInt mipsins) +{ + return (0x03FFFFFF & mipsins); +} + +static inline UInt get_rd(UInt mipsins) +{ + return (0x0000F800 & mipsins) >> 11; +} + +static inline UInt get_sa(UInt mipsins) +{ + return (0x000007C0 & mipsins) >> 6; +} + +static inline UInt get_function(UInt mipsins) +{ + return (0x0000003F & mipsins); +} + +static inline UInt get_ft(UInt mipsins) +{ + return (0x001F0000 & mipsins) >> 16; +} + +static inline UInt get_fs(UInt mipsins) +{ + return (0x0000F800 & mipsins) >> 11; +} + +static inline UInt get_fd(UInt mipsins) +{ + return (0x000007C0 & mipsins) >> 6; +} + +static inline UInt get_mov_cc(UInt mipsins) +{ + return (0x001C0000 & mipsins) >> 18; +} + +static inline UInt get_bc1_cc(UInt mipsins) +{ + return (0x001C0000 & mipsins) >> 18; +} + +static inline UInt get_fpc_cc(UInt mipsins) +{ + return (0x00000700 & mipsins) >> 8; +} + +static inline UInt get_tf(UInt mipsins) +{ + return (0x00010000 & mipsins) >> 16; +} + +static inline UInt get_nd(UInt mipsins) +{ + return (0x00020000 & mipsins) >> 17; +} + +static inline UInt get_fmt(UInt mipsins) +{ + return (0x03E00000 & mipsins) >> 21; +} + +static inline UInt get_FC(UInt mipsins) +{ + return (0x000000F0 & mipsins) >> 4; +} + +static inline UInt get_cond(UInt mipsins) +{ + return (0x0000000F & mipsins); +} + +/* for break & syscall */ +static inline UInt get_code(UInt mipsins) +{ + return (0xFFC0 & mipsins) >> 6; +} + +static inline UInt get_lsb(UInt mipsins) +{ + return (0x7C0 & mipsins) >> 6; +} + +static inline UInt get_msb(UInt mipsins) +{ + return (0x0000F800 & mipsins) >> 11; +} + +static inline UInt get_rot(UInt mipsins) +{ + return (0x00200000 & mipsins) >> 21; +} + +static inline UInt get_rotv(UInt mipsins) +{ + return (0x00000040 & mipsins) >> 6; +} + +static inline UInt get_sel(UInt mipsins) +{ + return (0x00000007 & mipsins); +} + +/* Get acc number for all MIPS32 DSP ASE(r2) instructions that use them, + except for MFHI and MFLO. */ +static inline UInt get_acNo(UInt mipsins) +{ + return (0x00001800 & mipsins) >> 11; +} + +/* Get accumulator number for MIPS32 DSP ASEr2 MFHI and MFLO instructions. */ +static inline UInt get_acNo_mfhilo(UInt mipsins) +{ + return (0x00600000 & mipsins) >> 21; +} + +/* Get mask field (helper function for wrdsp instruction). */ +static inline UInt get_wrdspMask(UInt mipsins) +{ + return (0x001ff800 & mipsins) >> 11; +} + +/* Get mask field (helper function for rddsp instruction). */ +static inline UInt get_rddspMask(UInt mipsins) +{ + return (0x03ff0000 & mipsins) >> 16; +} + +/* Get shift field (helper function for DSP ASE instructions). */ +static inline UInt get_shift(UInt mipsins) +{ + return (0x03f00000 & mipsins) >> 20; +} + +/* Get immediate field for DSP ASE instructions. */ +static inline UInt get_dspImm(UInt mipsins) +{ + return (0x03ff0000 & mipsins) >> 16; +} + + +#endif + +/*---------------------------------------------------------------*/ +/*--- end mips_defs.h ---*/ +/*---------------------------------------------------------------*/