From: Julian Seward Date: Thu, 12 Jun 2014 10:15:46 +0000 (+0000) Subject: Remove the old SIMD decoder entirely. X-Git-Tag: svn/VALGRIND_3_10_1^2~98 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ae246e30e49972c8c01658af8d295d5f0b7596af;p=thirdparty%2Fvalgrind.git Remove the old SIMD decoder entirely. git-svn-id: svn://svn.valgrind.org/vex/trunk@2873 --- diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index 91c1c86aed..cd83232bec 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -5011,7 +5011,6 @@ static Bool AdvSIMDExpandImm ( /*OUT*/ULong* res, return True; } - /* Help a bit for decoding laneage for vector operations that can be of the form 4x32, 2x64 or 2x32-and-zero-upper-half, as encoded by Q and SZ bits, typically for vector floating point. */ @@ -5050,34 +5049,6 @@ static Bool getLaneInfo_Q_SZ ( /*OUT*/IRType* tyI, /*OUT*/IRType* tyF, return False; } -/* Helper for decoding laneage for simple vector operations, - eg integer add. */ -static Bool getLaneInfo_SIMPLE ( /*OUT*/Bool* zeroUpper, - /*OUT*/const HChar** arrSpec, - Bool bitQ, UInt szBlg2 ) -{ - vassert(bitQ == True || bitQ == False); - vassert(szBlg2 < 4); - Bool zu = False; - const HChar* as = NULL; - switch ((szBlg2 << 1) | (bitQ ? 1 : 0)) { - case 0: zu = True; as = "8b"; break; - case 1: zu = False; as = "16b"; break; - case 2: zu = True; as = "4h"; break; - case 3: zu = False; as = "8h"; break; - case 4: zu = True; as = "2s"; break; - case 5: zu = False; as = "4s"; break; - case 6: return False; // impliedly 1x64 - case 7: zu = False; as = "2d"; break; - default: vassert(0); - } - vassert(as); - if (arrSpec) *arrSpec = as; - if (zeroUpper) *zeroUpper = zu; - return True; -} - - /* Helper for decoding laneage for shift-style vector operations that involve an immediate shift amount. */ static Bool getLaneInfo_IMMH_IMMB ( /*OUT*/UInt* shift, /*OUT*/UInt* szBlg2, @@ -5109,7 +5080,6 @@ static Bool getLaneInfo_IMMH_IMMB ( /*OUT*/UInt* shift, /*OUT*/UInt* szBlg2, return False; } - /* Generate IR to fold all lanes of the V128 value in 'src' as characterised by the operator 'op', and return the result in the bottom bits of a V128, with all other bits set to zero. */ @@ -5845,14 +5815,15 @@ Bool dis_AdvSIMD_modified_immediate(/*MB_OUT*/DisResult* dres, UInt insn) /* -------- {FMOV,MOVI} (vector, immediate) -------- */ /* Allowable op:cmode FMOV = 1:1111 - MOVI = 0:xx00, 1:0x00, 1:10x0, 1:110x, x:1110 + MOVI = 0:xx00, 0:0010, 1:0x00, 1:10x0, 1:110x, x:1110, */ ULong imm64lo = 0; UInt op_cmode = (bitOP << 4) | cmode; Bool ok = False; switch (op_cmode) { case BITS5(1,1,1,1,1): // 1:1111 - case BITS5(0,0,0,0,0): case BITS5(0,0,1,0,0): + case BITS5(0,0,0,0,0): case BITS5(0,0,1,0,0): // 0:0x00 + case BITS5(0,0,0,1,0): // 1:0010 case BITS5(0,1,0,0,0): case BITS5(0,1,1,0,0): // 0:xx00 case BITS5(1,0,0,0,0): case BITS5(1,0,1,0,0): // 1:0x00 case BITS5(1,1,0,0,0): case BITS5(1,1,0,1,0): // 1:10x0 @@ -5886,6 +5857,7 @@ Bool dis_AdvSIMD_scalar_copy(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_scalar_pairwise(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -5894,6 +5866,7 @@ Bool dis_AdvSIMD_scalar_pairwise(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_scalar_shift_by_imm(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -5914,6 +5887,19 @@ Bool dis_AdvSIMD_scalar_shift_by_imm(/*MB_OUT*/DisResult* dres, UInt insn) UInt dd = INSN(4,0); UInt immhb = (immh << 3) | immb; + if (bitU == 1 && (immh & 8) == 8 && opcode == BITS5(0,0,0,0,0)) { + /* -------- 1,1xxx,00000 SHR d_d_#imm -------- */ + UInt sh = 128 - immhb; + vassert(sh >= 1 && sh <= 64); + /* Don't generate an out of range IR shift */ + putQReg128(dd, sh == 64 + ? mkV128(0x0000) + : unop(Iop_ZeroHI64ofV128, + binop(Iop_ShrN64x2, getQReg128(nn), mkU8(sh)))); + DIP("shr d%u, d%u, #%u\n", dd, nn, sh); + return True; + } + if (bitU == 0 && (immh & 8) == 8 && opcode == BITS5(0,1,0,1,0)) { /* -------- 0,1xxx,01010 SHL d_d_#imm -------- */ UInt sh = immhb - 64; @@ -5929,6 +5915,7 @@ Bool dis_AdvSIMD_scalar_shift_by_imm(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_scalar_three_different(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6031,6 +6018,7 @@ Bool dis_AdvSIMD_scalar_two_reg_misc(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_scalar_x_indexed_element(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6039,6 +6027,7 @@ Bool dis_AdvSIMD_scalar_x_indexed_element(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_shift_by_immediate(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6205,6 +6194,7 @@ Bool dis_AdvSIMD_shift_by_immediate(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_three_different(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6848,6 +6838,7 @@ Bool dis_AdvSIMD_two_reg_misc(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_vector_x_indexed_elem(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6856,6 +6847,7 @@ Bool dis_AdvSIMD_vector_x_indexed_elem(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_crypto_aes(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6864,6 +6856,7 @@ Bool dis_AdvSIMD_crypto_aes(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_crypto_three_reg_sha(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6872,6 +6865,7 @@ Bool dis_AdvSIMD_crypto_three_reg_sha(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_crypto_two_reg_sha(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -6964,6 +6958,7 @@ Bool dis_AdvSIMD_fp_conditional_compare(/*MB_OUT*/DisResult* dres, UInt insn) # undef INSN } + static Bool dis_AdvSIMD_fp_conditional_select(/*MB_OUT*/DisResult* dres, UInt insn) { @@ -7602,1681 +7597,6 @@ Bool dis_ARM64_simd_and_fp(/*MB_OUT*/DisResult* dres, UInt insn) return False; } -static -Bool dis_ARM64_simd_and_fp_OLD(/*MB_OUT*/DisResult* dres, UInt insn) -{ -# define INSN(_bMax,_bMin) SLICE_UInt(insn, (_bMax), (_bMin)) - - /* -------------- FMOV (scalar, immediate) -------------- */ - /* 31 28 23 20 12 9 4 - 000 11110 00 1 imm8 100 00000 d FMOV Sd, #imm - 000 11110 01 1 imm8 100 00000 d FMOV Dd, #imm - */ - if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0) - && INSN(21,21) == 1 && INSN(12,5) == BITS8(1,0,0,0,0,0,0,0)) { - Bool isD = INSN(22,22) == 1; - UInt imm8 = INSN(20,13); - UInt dd = INSN(4,0); - ULong imm = VFPExpandImm(imm8, isD ? 64 : 32); - if (!isD) { - vassert(0 == (imm & 0xFFFFFFFF00000000ULL)); - } - putQReg128(dd, mkV128(0)); - putQRegLO(dd, isD ? mkU64(imm) : mkU32(imm & 0xFFFFFFFFULL)); - DIP("fmov %s, #0x%llx\n", - nameQRegLO(dd, isD ? Ity_F64 : Ity_F32), imm); - return True; - } - - /* -------------- {S,U}CVTF (scalar, integer) -------------- */ - /* 31 28 23 21 20 18 15 9 4 ix - 000 11110 00 1 00 010 000000 n d SCVTF Sd, Wn 0 - 000 11110 01 1 00 010 000000 n d SCVTF Dd, Wn 1 - 100 11110 00 1 00 010 000000 n d SCVTF Sd, Xn 2 - 100 11110 01 1 00 010 000000 n d SCVTF Dd, Xn 3 - - 000 11110 00 1 00 011 000000 n d UCVTF Sd, Wn 4 - 000 11110 01 1 00 011 000000 n d UCVTF Dd, Wn 5 - 100 11110 00 1 00 011 000000 n d UCVTF Sd, Xn 6 - 100 11110 01 1 00 011 000000 n d UCVTF Dd, Xn 7 - - These are signed/unsigned conversion from integer registers to - FP registers, all 4 32/64-bit combinations, rounded per FPCR. - */ - if (INSN(30,23) == BITS8(0,0,1,1,1,1,0,0) && INSN(21,17) == BITS5(1,0,0,0,1) - && INSN(15,10) == BITS6(0,0,0,0,0,0)) { - Bool isI64 = INSN(31,31) == 1; - Bool isF64 = INSN(22,22) == 1; - Bool isU = INSN(16,16) == 1; - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - UInt ix = (isU ? 4 : 0) | (isI64 ? 2 : 0) | (isF64 ? 1 : 0); - const IROp ops[8] - = { Iop_I32StoF32, Iop_I32StoF64, Iop_I64StoF32, Iop_I64StoF64, - Iop_I32UtoF32, Iop_I32UtoF64, Iop_I64UtoF32, Iop_I64UtoF64 }; - IRExpr* src = getIRegOrZR(isI64, nn); - IRExpr* res = (isF64 && !isI64) - ? unop(ops[ix], src) - : binop(ops[ix], mkexpr(mk_get_IR_rounding_mode()), src); - putQReg128(dd, mkV128(0)); - putQRegLO(dd, res); - DIP("%ccvtf %s, %s\n", - isU ? 'u' : 's', nameQRegLO(dd, isF64 ? Ity_F64 : Ity_F32), - nameIRegOrZR(isI64, nn)); - return True; - } - - /* ------------ F{ADD,SUB,MUL,DIV,NMUL} (scalar) ------------ */ - /* 31 23 20 15 11 9 4 - ---------------- 0000 ------ FMUL -------- - 000 11110 001 m 0001 10 n d FDIV Sd,Sn,Sm - 000 11110 011 m 0001 10 n d FDIV Dd,Dn,Dm - ---------------- 0010 ------ FADD -------- - ---------------- 0011 ------ FSUB -------- - ---------------- 1000 ------ FNMUL -------- - */ - if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0) - && INSN(21,21) == 1 && INSN(11,10) == BITS2(1,0)) { - Bool isD = INSN(22,22) == 1; - UInt mm = INSN(20,16); - UInt op = INSN(15,12); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IROp iop = Iop_INVALID; - IRType ty = isD ? Ity_F64 : Ity_F32; - Bool neg = False; - const HChar* nm = "???"; - switch (op) { - case BITS4(0,0,0,0): nm = "fmul"; iop = mkMULF(ty); break; - case BITS4(0,0,0,1): nm = "fdiv"; iop = mkDIVF(ty); break; - case BITS4(0,0,1,0): nm = "fadd"; iop = mkADDF(ty); break; - case BITS4(0,0,1,1): nm = "fsub"; iop = mkSUBF(ty); break; - case BITS4(1,0,0,0): nm = "fnmul"; iop = mkMULF(ty); - neg = True; break; - default: return False; - } - vassert(iop != Iop_INVALID); - IRExpr* resE = triop(iop, mkexpr(mk_get_IR_rounding_mode()), - getQRegLO(nn, ty), getQRegLO(mm, ty)); - IRTemp res = newTemp(ty); - assign(res, neg ? unop(mkNEGF(ty),resE) : resE); - putQReg128(dd, mkV128(0)); - putQRegLO(dd, mkexpr(res)); - DIP("%s %s, %s, %s\n", - nm, nameQRegLO(dd, ty), nameQRegLO(nn, ty), nameQRegLO(mm, ty)); - return True; - } - - /* ------------ F{MOV,ABS,NEG,SQRT} D/D or S/S ------------ */ - /* 31 23 21 16 14 9 4 - 000 11110 00 10000 00 10000 n d FMOV Sd, Sn - 000 11110 01 10000 00 10000 n d FMOV Dd, Dn - ------------------ 01 --------- FABS ------ - ------------------ 10 --------- FNEG ------ - ------------------ 11 --------- FSQRT ----- - */ - if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0) - && INSN(21,17) == BITS5(1,0,0,0,0) - && INSN(14,10) == BITS5(1,0,0,0,0)) { - Bool isD = INSN(22,22) == 1; - UInt opc = INSN(16,15); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRType ty = isD ? Ity_F64 : Ity_F32; - IRTemp res = newTemp(ty); - if (opc == BITS2(0,0)) { - assign(res, getQRegLO(nn, ty)); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - DIP("fmov %s, %s\n", - nameQRegLO(dd, ty), nameQRegLO(nn, ty)); - return True; - } - if (opc == BITS2(1,0) || opc == BITS2(0,1)) { - Bool isAbs = opc == BITS2(0,1); - IROp op = isAbs ? mkABSF(ty) : mkNEGF(ty); - assign(res, unop(op, getQRegLO(nn, ty))); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - DIP("%s %s, %s\n", isAbs ? "fabs" : "fneg", - nameQRegLO(dd, ty), nameQRegLO(nn, ty)); - return True; - } - if (opc == BITS2(1,1)) { - assign(res, - binop(mkSQRTF(ty), - mkexpr(mk_get_IR_rounding_mode()), getQRegLO(nn, ty))); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - DIP("fsqrt %s, %s\n", nameQRegLO(dd, ty), nameQRegLO(nn, ty)); - return True; - } - /* else fall through; other cases are ATC */ - } - - /* ---------------- F{ABS,NEG} (vector) ---------------- */ - /* 31 28 22 21 16 9 4 - 0q0 01110 1 sz 10000 01111 10 n d FABS Vd.T, Vn.T - 0q1 01110 1 sz 10000 01111 10 n d FNEG Vd.T, Vn.T - */ - if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,0,1) - && INSN(21,17) == BITS5(1,0,0,0,0) - && INSN(16,10) == BITS7(0,1,1,1,1,1,0)) { - UInt bitQ = INSN(30,30); - UInt bitSZ = INSN(22,22); - Bool isFNEG = INSN(29,29) == 1; - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - const HChar* ar = "??"; - IRType tyF = Ity_INVALID; - Bool zeroHI = False; - Bool ok = getLaneInfo_Q_SZ(NULL, &tyF, NULL, &zeroHI, &ar, - (Bool)bitQ, (Bool)bitSZ); - if (ok) { - vassert(tyF == Ity_F64 || tyF == Ity_F32); - IROp op = (tyF == Ity_F64) ? (isFNEG ? Iop_Neg64Fx2 : Iop_Abs64Fx2) - : (isFNEG ? Iop_Neg32Fx4 : Iop_Abs32Fx4); - IRTemp res = newTemp(Ity_V128); - assign(res, unop(op, getQReg128(nn))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(res)) - : mkexpr(res)); - DIP("%s %s.%s, %s.%s\n", isFNEG ? "fneg" : "fabs", - nameQReg128(dd), ar, nameQReg128(nn), ar); - return True; - } - /* else fall through */ - } - - /* -------------------- FCMP,FCMPE -------------------- */ - /* 31 23 20 15 9 4 - 000 11110 01 1 m 00 1000 n 10 000 FCMPE Dn, Dm - 000 11110 01 1 00000 00 1000 n 11 000 FCMPE Dn, #0.0 - 000 11110 01 1 m 00 1000 n 00 000 FCMP Dn, Dm - 000 11110 01 1 00000 00 1000 n 01 000 FCMP Dn, #0.0 - - 000 11110 00 1 m 00 1000 n 10 000 FCMPE Sn, Sm - 000 11110 00 1 00000 00 1000 n 11 000 FCMPE Sn, #0.0 - 000 11110 00 1 m 00 1000 n 00 000 FCMP Sn, Sm - 000 11110 00 1 00000 00 1000 n 01 000 FCMP Sn, #0.0 - - FCMPE generates Invalid Operation exn if either arg is any kind - of NaN. FCMP generates Invalid Operation exn if either arg is a - signalling NaN. We ignore this detail here and produce the same - IR for both. - */ - if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0) && INSN(21,21) == 1 - && INSN(15,10) == BITS6(0,0,1,0,0,0) && INSN(2,0) == BITS3(0,0,0)) { - Bool isD = INSN(22,22) == 1; - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - Bool isCMPE = INSN(4,4) == 1; - Bool cmpZero = INSN(3,3) == 1; - IRType ty = isD ? Ity_F64 : Ity_F32; - Bool valid = True; - if (cmpZero && mm != 0) valid = False; - if (valid) { - IRTemp argL = newTemp(ty); - IRTemp argR = newTemp(ty); - IRTemp irRes = newTemp(Ity_I32); - assign(argL, getQRegLO(nn, ty)); - assign(argR, - cmpZero - ? (IRExpr_Const(isD ? IRConst_F64i(0) : IRConst_F32i(0))) - : getQRegLO(mm, ty)); - assign(irRes, binop(isD ? Iop_CmpF64 : Iop_CmpF32, - mkexpr(argL), mkexpr(argR))); - IRTemp nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes); - IRTemp nzcv_28x0 = newTemp(Ity_I64); - assign(nzcv_28x0, binop(Iop_Shl64, mkexpr(nzcv), mkU8(28))); - setFlags_COPY(nzcv_28x0); - DIP("fcmp%s %s, %s\n", isCMPE ? "e" : "", nameQRegLO(nn, ty), - cmpZero ? "#0.0" : nameQRegLO(mm, ty)); - return True; - } - } - - /* -------------------- F{N}M{ADD,SUB} -------------------- */ - /* 31 22 20 15 14 9 4 ix - 000 11111 0 sz 0 m 0 a n d 0 FMADD Fd,Fn,Fm,Fa - 000 11111 0 sz 0 m 1 a n d 1 FMSUB Fd,Fn,Fm,Fa - 000 11111 0 sz 1 m 0 a n d 2 FNMADD Fd,Fn,Fm,Fa - 000 11111 0 sz 1 m 1 a n d 3 FNMSUB Fd,Fn,Fm,Fa - where Fx=Dx when sz=1, Fx=Sx when sz=0 - - -----SPEC------ ----IMPL---- - fmadd a + n * m a + n * m - fmsub a + (-n) * m a - n * m - fnmadd (-a) + (-n) * m -(a + n * m) - fnmsub (-a) + n * m -(a - n * m) - */ - if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,1,0)) { - Bool isD = INSN(22,22) == 1; - UInt mm = INSN(20,16); - UInt aa = INSN(14,10); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - UInt ix = (INSN(21,21) << 1) | INSN(15,15); - IRType ty = isD ? Ity_F64 : Ity_F32; - IROp opADD = mkADDF(ty); - IROp opSUB = mkSUBF(ty); - IROp opMUL = mkMULF(ty); - IROp opNEG = mkNEGF(ty); - IRTemp res = newTemp(ty); - IRExpr* eA = getQRegLO(aa, ty); - IRExpr* eN = getQRegLO(nn, ty); - IRExpr* eM = getQRegLO(mm, ty); - IRExpr* rm = mkexpr(mk_get_IR_rounding_mode()); - IRExpr* eNxM = triop(opMUL, rm, eN, eM); - switch (ix) { - case 0: assign(res, triop(opADD, rm, eA, eNxM)); break; - case 1: assign(res, triop(opSUB, rm, eA, eNxM)); break; - case 2: assign(res, unop(opNEG, triop(opADD, rm, eA, eNxM))); break; - case 3: assign(res, unop(opNEG, triop(opSUB, rm, eA, eNxM))); break; - default: vassert(0); - } - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - const HChar* names[4] = { "fmadd", "fmsub", "fnmadd", "fnmsub" }; - DIP("%s %s, %s, %s, %s\n", - names[ix], nameQRegLO(dd, ty), nameQRegLO(nn, ty), - nameQRegLO(mm, ty), nameQRegLO(aa, ty)); - return True; - } - - /* -------- FCVT{N,P,M,Z}{S,U} (scalar, integer) -------- */ - /* 30 23 20 18 15 9 4 - sf 00 11110 0x 1 00 000 000000 n d FCVTNS Rd, Fn (round to - sf 00 11110 0x 1 00 001 000000 n d FCVTNU Rd, Fn nearest) - ---------------- 01 -------------- FCVTP-------- (round to +inf) - ---------------- 10 -------------- FCVTM-------- (round to -inf) - ---------------- 11 -------------- FCVTZ-------- (round to zero) - - Rd is Xd when sf==1, Wd when sf==0 - Fn is Dn when x==1, Sn when x==0 - 20:19 carry the rounding mode, using the same encoding as FPCR - */ - if (INSN(30,23) == BITS8(0,0,1,1,1,1,0,0) && INSN(21,21) == 1 - && INSN(18,17) == BITS2(0,0) && INSN(15,10) == BITS6(0,0,0,0,0,0)) { - Bool isI64 = INSN(31,31) == 1; - Bool isF64 = INSN(22,22) == 1; - UInt rm = INSN(20,19); - Bool isU = INSN(16,16) == 1; - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - /* Decide on the IR rounding mode to use. */ - IRRoundingMode irrm = 8; /*impossible*/ - HChar ch = '?'; - switch (rm) { - case BITS2(0,0): ch = 'n'; irrm = Irrm_NEAREST; break; - case BITS2(0,1): ch = 'p'; irrm = Irrm_PosINF; break; - case BITS2(1,0): ch = 'm'; irrm = Irrm_NegINF; break; - case BITS2(1,1): ch = 'z'; irrm = Irrm_ZERO; break; - default: vassert(0); - } - vassert(irrm != 8); - /* Decide on the conversion primop, based on the source size, - dest size and signedness (8 possibilities). Case coding: - F32 ->s I32 0 - F32 ->u I32 1 - F32 ->s I64 2 - F32 ->u I64 3 - F64 ->s I32 4 - F64 ->u I32 5 - F64 ->s I64 6 - F64 ->u I64 7 - */ - UInt ix = (isF64 ? 4 : 0) | (isI64 ? 2 : 0) | (isU ? 1 : 0); - vassert(ix < 8); - const IROp ops[8] - = { Iop_F32toI32S, Iop_F32toI32U, Iop_F32toI64S, Iop_F32toI64U, - Iop_F64toI32S, Iop_F64toI32U, Iop_F64toI64S, Iop_F64toI64U }; - IROp op = ops[ix]; - // A bit of ATCery: bounce all cases we haven't seen an example of. - if (/* F32toI32S */ - (op == Iop_F32toI32S && irrm == Irrm_ZERO) /* FCVTZS Wd,Sn */ - || (op == Iop_F32toI32S && irrm == Irrm_NegINF) /* FCVTMS Wd,Sn */ - || (op == Iop_F32toI32S && irrm == Irrm_PosINF) /* FCVTPS Wd,Sn */ - /* F32toI32U */ - || (op == Iop_F32toI32U && irrm == Irrm_ZERO) /* FCVTZU Wd,Sn */ - || (op == Iop_F32toI32U && irrm == Irrm_NegINF) /* FCVTMU Wd,Sn */ - /* F32toI64S */ - || (op == Iop_F32toI64S && irrm == Irrm_ZERO) /* FCVTZS Xd,Sn */ - /* F32toI64U */ - || (op == Iop_F32toI64U && irrm == Irrm_ZERO) /* FCVTZU Xd,Sn */ - /* F64toI32S */ - || (op == Iop_F64toI32S && irrm == Irrm_ZERO) /* FCVTZS Wd,Dn */ - || (op == Iop_F64toI32S && irrm == Irrm_NegINF) /* FCVTMS Wd,Dn */ - || (op == Iop_F64toI32S && irrm == Irrm_PosINF) /* FCVTPS Wd,Dn */ - /* F64toI32U */ - || (op == Iop_F64toI32U && irrm == Irrm_ZERO) /* FCVTZU Wd,Dn */ - || (op == Iop_F64toI32U && irrm == Irrm_NegINF) /* FCVTMU Wd,Dn */ - || (op == Iop_F64toI32U && irrm == Irrm_PosINF) /* FCVTPU Wd,Dn */ - /* F64toI64S */ - || (op == Iop_F64toI64S && irrm == Irrm_ZERO) /* FCVTZS Xd,Dn */ - || (op == Iop_F64toI64S && irrm == Irrm_NegINF) /* FCVTMS Xd,Dn */ - || (op == Iop_F64toI64S && irrm == Irrm_PosINF) /* FCVTPS Xd,Dn */ - /* F64toI64U */ - || (op == Iop_F64toI64U && irrm == Irrm_ZERO) /* FCVTZU Xd,Dn */ - || (op == Iop_F64toI64U && irrm == Irrm_PosINF) /* FCVTPU Xd,Dn */ - ) { - /* validated */ - } else { - return False; - } - IRType srcTy = isF64 ? Ity_F64 : Ity_F32; - IRType dstTy = isI64 ? Ity_I64 : Ity_I32; - IRTemp src = newTemp(srcTy); - IRTemp dst = newTemp(dstTy); - assign(src, getQRegLO(nn, srcTy)); - assign(dst, binop(op, mkU32(irrm), mkexpr(src))); - putIRegOrZR(isI64, dd, mkexpr(dst)); - DIP("fcvt%c%c %s, %s\n", ch, isU ? 'u' : 's', - nameIRegOrZR(isI64, dd), nameQRegLO(nn, srcTy)); - return True; - } - - /* -------- FCVTAS (KLUDGED) (scalar, integer) -------- */ - /* 30 23 20 18 15 9 4 - 1 00 11110 0x 1 00 100 000000 n d FCVTAS Xd, Fn - 0 00 11110 0x 1 00 100 000000 n d FCVTAS Wd, Fn - Fn is Dn when x==1, Sn when x==0 - */ - if (INSN(30,23) == BITS8(0,0,1,1,1,1,0,0) - && INSN(21,16) == BITS6(1,0,0,1,0,0) - && INSN(15,10) == BITS6(0,0,0,0,0,0)) { - Bool isI64 = INSN(31,31) == 1; - Bool isF64 = INSN(22,22) == 1; - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - /* Decide on the IR rounding mode to use. */ - /* KLUDGE: should be Irrm_NEAREST_TIE_AWAY_0 */ - IRRoundingMode irrm = Irrm_NEAREST; - /* Decide on the conversion primop. */ - IROp op = isI64 ? (isF64 ? Iop_F64toI64S : Iop_F32toI64S) - : (isF64 ? Iop_F64toI32S : Iop_F32toI32S); - IRType srcTy = isF64 ? Ity_F64 : Ity_F32; - IRType dstTy = isI64 ? Ity_I64 : Ity_I32; - IRTemp src = newTemp(srcTy); - IRTemp dst = newTemp(dstTy); - assign(src, getQRegLO(nn, srcTy)); - assign(dst, binop(op, mkU32(irrm), mkexpr(src))); - putIRegOrZR(isI64, dd, mkexpr(dst)); - DIP("fcvtas %s, %s (KLUDGED)\n", - nameIRegOrZR(isI64, dd), nameQRegLO(nn, srcTy)); - return True; - } - - /* ---------------- FRINT{I,M,P,Z} (scalar) ---------------- */ - /* 31 23 21 17 14 9 4 - 000 11110 0x 1001 111 10000 n d FRINTI Fd, Fm (round per FPCR) - rm - x==0 => S-registers, x==1 => D-registers - rm (17:15) encodings: - 111 per FPCR (FRINTI) - 001 +inf (FRINTP) - 010 -inf (FRINTM) - 011 zero (FRINTZ) - 000 tieeven - 100 tieaway (FRINTA) -- !! FIXME KLUDGED !! - 110 per FPCR + "exact = TRUE" - 101 unallocated - */ - if (INSN(31,23) == BITS9(0,0,0,1,1,1,1,0,0) - && INSN(21,18) == BITS4(1,0,0,1) && INSN(14,10) == BITS5(1,0,0,0,0)) { - Bool isD = INSN(22,22) == 1; - UInt rm = INSN(17,15); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRType ty = isD ? Ity_F64 : Ity_F32; - IRExpr* irrmE = NULL; - UChar ch = '?'; - switch (rm) { - case BITS3(0,1,1): ch = 'z'; irrmE = mkU32(Irrm_ZERO); break; - case BITS3(0,1,0): ch = 'm'; irrmE = mkU32(Irrm_NegINF); break; - case BITS3(0,0,1): ch = 'p'; irrmE = mkU32(Irrm_PosINF); break; - // The following is a kludge. Should be: Irrm_NEAREST_TIE_AWAY_0 - case BITS3(1,0,0): ch = 'a'; irrmE = mkU32(Irrm_NEAREST); break; - default: break; - } - if (irrmE) { - IRTemp src = newTemp(ty); - IRTemp dst = newTemp(ty); - assign(src, getQRegLO(nn, ty)); - assign(dst, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt, - irrmE, mkexpr(src))); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(dst)); - DIP("frint%c %s, %s\n", - ch, nameQRegLO(dd, ty), nameQRegLO(nn, ty)); - return True; - } - /* else unhandled rounding mode case -- fall through */ - } - - /* ------------------ FCVT (scalar) ------------------ */ - /* 31 23 21 16 14 9 4 - 000 11110 11 10001 00 10000 n d FCVT Sd, Hn (unimp) - --------- 11 ----- 01 --------- FCVT Dd, Hn (unimp) - --------- 00 ----- 11 --------- FCVT Hd, Sn (unimp) - --------- 00 ----- 01 --------- FCVT Dd, Sn - --------- 01 ----- 11 --------- FCVT Hd, Dn (unimp) - --------- 01 ----- 00 --------- FCVT Sd, Dn - Rounding, when dst is smaller than src, is per the FPCR. - */ - if (INSN(31,24) == BITS8(0,0,0,1,1,1,1,0) - && INSN(21,17) == BITS5(1,0,0,0,1) - && INSN(14,10) == BITS5(1,0,0,0,0)) { - UInt b2322 = INSN(23,22); - UInt b1615 = INSN(16,15); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - if (b2322 == BITS2(0,0) && b1615 == BITS2(0,1)) { - /* Convert S to D */ - IRTemp res = newTemp(Ity_F64); - assign(res, unop(Iop_F32toF64, getQRegLO(nn, Ity_F32))); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - DIP("fcvt %s, %s\n", - nameQRegLO(dd, Ity_F64), nameQRegLO(nn, Ity_F32)); - return True; - } - if (b2322 == BITS2(0,1) && b1615 == BITS2(0,0)) { - /* Convert D to S */ - IRTemp res = newTemp(Ity_F32); - assign(res, binop(Iop_F64toF32, mkexpr(mk_get_IR_rounding_mode()), - getQRegLO(nn, Ity_F64))); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - DIP("fcvt %s, %s\n", - nameQRegLO(dd, Ity_F32), nameQRegLO(nn, Ity_F64)); - return True; - } - /* else unhandled */ - } - - /* ------------------ FABD (scalar) ------------------ */ - /* 31 23 20 15 9 4 - 011 11110 111 m 110101 n d FABD Dd, Dn, Dm - 011 11110 101 m 110101 n d FABD Sd, Sn, Sm - */ - if (INSN(31,23) == BITS9(0,1,1,1,1,1,1,0,1) && INSN(21,21) == 1 - && INSN(15,10) == BITS6(1,1,0,1,0,1)) { - Bool isD = INSN(22,22) == 1; - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRType ty = isD ? Ity_F64 : Ity_F32; - IRTemp res = newTemp(ty); - assign(res, unop(mkABSF(ty), - triop(mkSUBF(ty), - mkexpr(mk_get_IR_rounding_mode()), - getQRegLO(nn,ty), getQRegLO(mm,ty)))); - putQReg128(dd, mkV128(0x0000)); - putQRegLO(dd, mkexpr(res)); - DIP("fabd %s, %s, %s\n", - nameQRegLO(dd, ty), nameQRegLO(nn, ty), nameQRegLO(mm, ty)); - return True; - } - - /* -------------- {S,U}CVTF (vector, integer) -------------- */ - /* 31 28 22 21 15 9 4 - 0q0 01110 0 sz 1 00001 110110 n d SCVTF Vd, Vn - 0q1 01110 0 sz 1 00001 110110 n d UCVTF Vd, Vn - with laneage: - case sz:Q of 00 -> 2S, zero upper, 01 -> 4S, 10 -> illegal, 11 -> 2D - */ - if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,0,0) - && INSN(21,16) == BITS6(1,0,0,0,0,1) - && INSN(15,10) == BITS6(1,1,0,1,1,0)) { - Bool isQ = INSN(30,30) == 1; - Bool isU = INSN(29,29) == 1; - Bool isF64 = INSN(22,22) == 1; - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - if (isQ || !isF64) { - IRType tyF = Ity_INVALID, tyI = Ity_INVALID; - UInt nLanes = 0; - Bool zeroHI = False; - const HChar* arrSpec = NULL; - Bool ok = getLaneInfo_Q_SZ(&tyI, &tyF, &nLanes, &zeroHI, &arrSpec, - isQ, isF64 ); - IROp op = isU ? (isF64 ? Iop_I64UtoF64 : Iop_I32UtoF32) - : (isF64 ? Iop_I64StoF64 : Iop_I32StoF32); - IRTemp rm = mk_get_IR_rounding_mode(); - UInt i; - vassert(ok); /* the 'if' above should ensure this */ - for (i = 0; i < nLanes; i++) { - putQRegLane(dd, i, - binop(op, mkexpr(rm), getQRegLane(nn, i, tyI))); - } - if (zeroHI) { - putQRegLane(dd, 1, mkU64(0)); - } - DIP("%ccvtf %s.%s, %s.%s\n", isU ? 'u' : 's', - nameQReg128(dd), arrSpec, nameQReg128(nn), arrSpec); - return True; } - /* else fall through */ - } - - /* ---------- F{ADD,SUB,MUL,DIV,MLA,MLS} (vector) ---------- */ - /* 31 28 22 21 20 15 9 4 case - 0q0 01110 0 sz 1 m 110101 n d FADD Vd,Vn,Vm 1 - 0q0 01110 1 sz 1 m 110101 n d FSUB Vd,Vn,Vm 2 - 0q1 01110 0 sz 1 m 110111 n d FMUL Vd,Vn,Vm 3 - 0q1 01110 0 sz 1 m 111111 n d FDIV Vd,Vn,Vm 4 - 0q0 01110 0 sz 1 m 110011 n d FMLA Vd,Vn,Vm 5 - 0q0 01110 1 sz 1 m 110011 n d FMLS Vd,Vn,Vm 6 - 0q1 01110 1 sz 1 m 110101 n d FABD Vd,Vn,Vm 7 - */ - if (INSN(31,31) == 0 - && INSN(28,24) == BITS5(0,1,1,1,0) && INSN(21,21) == 1) { - Bool isQ = INSN(30,30) == 1; - UInt b29 = INSN(29,29); - UInt b23 = INSN(23,23); - Bool isF64 = INSN(22,22) == 1; - UInt mm = INSN(20,16); - UInt b1510 = INSN(15,10); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - UInt ix = 0; - /**/ if (b29 == 0 && b23 == 0 && b1510 == BITS6(1,1,0,1,0,1)) ix = 1; - else if (b29 == 0 && b23 == 1 && b1510 == BITS6(1,1,0,1,0,1)) ix = 2; - else if (b29 == 1 && b23 == 0 && b1510 == BITS6(1,1,0,1,1,1)) ix = 3; - else if (b29 == 1 && b23 == 0 && b1510 == BITS6(1,1,1,1,1,1)) ix = 4; - else if (b29 == 0 && b23 == 0 && b1510 == BITS6(1,1,0,0,1,1)) ix = 5; - else if (b29 == 0 && b23 == 1 && b1510 == BITS6(1,1,0,0,1,1)) ix = 6; - else if (b29 == 1 && b23 == 1 && b1510 == BITS6(1,1,0,1,0,1)) ix = 7; - IRType laneTy = Ity_INVALID; - Bool zeroHI = False; - const HChar* arr = "??"; - Bool ok - = getLaneInfo_Q_SZ(NULL, &laneTy, NULL, &zeroHI, &arr, isQ, isF64); - /* Skip MLA/MLS for the time being */ - if (ok && ix >= 1 && ix <= 4) { - const IROp ops64[4] - = { Iop_Add64Fx2, Iop_Sub64Fx2, Iop_Mul64Fx2, Iop_Div64Fx2 }; - const IROp ops32[4] - = { Iop_Add32Fx4, Iop_Sub32Fx4, Iop_Mul32Fx4, Iop_Div32Fx4 }; - const HChar* names[4] - = { "fadd", "fsub", "fmul", "fdiv" }; - IROp op = laneTy==Ity_F64 ? ops64[ix-1] : ops32[ix-1]; - IRTemp rm = mk_get_IR_rounding_mode(); - IRTemp t1 = newTemp(Ity_V128); - IRTemp t2 = newTemp(Ity_V128); - assign(t1, triop(op, mkexpr(rm), getQReg128(nn), getQReg128(mm))); - assign(t2, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t1)) - : mkexpr(t1)); - putQReg128(dd, mkexpr(t2)); - DIP("%s %s.%s, %s.%s, %s.%s\n", names[ix-1], - nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr); - return True; - } - if (ok && ix >= 5 && ix <= 6) { - IROp opADD = laneTy==Ity_F64 ? Iop_Add64Fx2 : Iop_Add32Fx4; - IROp opSUB = laneTy==Ity_F64 ? Iop_Sub64Fx2 : Iop_Sub32Fx4; - IROp opMUL = laneTy==Ity_F64 ? Iop_Mul64Fx2 : Iop_Mul32Fx4; - IRTemp rm = mk_get_IR_rounding_mode(); - IRTemp t1 = newTemp(Ity_V128); - IRTemp t2 = newTemp(Ity_V128); - // FIXME: double rounding; use FMA primops instead - assign(t1, triop(opMUL, - mkexpr(rm), getQReg128(nn), getQReg128(mm))); - assign(t2, triop(ix == 5 ? opADD : opSUB, - mkexpr(rm), getQReg128(dd), mkexpr(t1))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t2)) - : mkexpr(t2)); - DIP("%s %s.%s, %s.%s, %s.%s\n", ix == 5 ? "fmla" : "fmls", - nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr); - return True; - } - if (ok && ix == 7) { - IROp opSUB = laneTy==Ity_F64 ? Iop_Sub64Fx2 : Iop_Sub32Fx4; - IROp opABS = laneTy==Ity_F64 ? Iop_Abs64Fx2 : Iop_Abs32Fx4; - IRTemp rm = mk_get_IR_rounding_mode(); - IRTemp t1 = newTemp(Ity_V128); - IRTemp t2 = newTemp(Ity_V128); - // FIXME: use Abd primop instead? - assign(t1, triop(opSUB, - mkexpr(rm), getQReg128(nn), getQReg128(mm))); - assign(t2, unop(opABS, mkexpr(t1))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t2)) - : mkexpr(t2)); - DIP("fabd %s.%s, %s.%s, %s.%s\n", - nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr); - return True; - } - } - - /* ------------ FCM{EQ,GE,GT}, FAC{GE,GT} (vector) ------------ */ - /* 31 28 22 20 15 9 4 case - 0q1 01110 0 sz 1 m 111011 n d FACGE Vd, Vn, Vm - 0q1 01110 1 sz 1 m 111011 n d FACGT Vd, Vn, Vm - 0q0 01110 0 sz 1 m 111001 n d FCMEQ Vd, Vn, Vm - 0q1 01110 0 sz 1 m 111001 n d FCMGE Vd, Vn, Vm - 0q1 01110 1 sz 1 m 111001 n d FCMGT Vd, Vn, Vm - */ - if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0) && INSN(21,21) == 1 - && INSN(15,12) == BITS4(1,1,1,0) && INSN(10,10) == 1) { - Bool isQ = INSN(30,30) == 1; - UInt U = INSN(29,29); - UInt E = INSN(23,23); - Bool isF64 = INSN(22,22) == 1; - UInt ac = INSN(11,11); - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - /* */ - UInt EUac = (E << 2) | (U << 1) | ac; - IROp opABS = Iop_INVALID; - IROp opCMP = Iop_INVALID; - IRType laneTy = Ity_INVALID; - Bool zeroHI = False; - Bool swap = True; - const HChar* arr = "??"; - const HChar* nm = "??"; - Bool ok - = getLaneInfo_Q_SZ(NULL, &laneTy, NULL, &zeroHI, &arr, isQ, isF64); - if (ok) { - vassert((isF64 && laneTy == Ity_F64) || (!isF64 && laneTy == Ity_F32)); - switch (EUac) { - case BITS3(0,0,0): - nm = "fcmeq"; - opCMP = isF64 ? Iop_CmpEQ64Fx2 : Iop_CmpEQ32Fx4; - swap = False; - break; - case BITS3(0,1,0): - nm = "fcmge"; - opCMP = isF64 ? Iop_CmpLE64Fx2 : Iop_CmpLE32Fx4; - break; - case BITS3(0,1,1): - nm = "facge"; - opCMP = isF64 ? Iop_CmpLE64Fx2 : Iop_CmpLE32Fx4; - opABS = isF64 ? Iop_Abs64Fx2 : Iop_Abs32Fx4; - break; - case BITS3(1,1,0): - nm = "fcmgt"; - opCMP = isF64 ? Iop_CmpLT64Fx2 : Iop_CmpLT32Fx4; - break; - case BITS3(1,1,1): - nm = "facgt"; - opCMP = isF64 ? Iop_CmpLE64Fx2 : Iop_CmpLE32Fx4; // wrong? - opABS = isF64 ? Iop_Abs64Fx2 : Iop_Abs32Fx4; - break; - default: - break; - } - } - if (opCMP != Iop_INVALID) { - IRExpr* argN = getQReg128(nn); - IRExpr* argM = getQReg128(mm); - if (opABS != Iop_INVALID) { - argN = unop(opABS, argN); - argM = unop(opABS, argM); - } - IRExpr* res = swap ? binop(opCMP, argM, argN) - : binop(opCMP, argN, argM); - if (zeroHI) { - res = unop(Iop_ZeroHI64ofV128, res); - } - putQReg128(dd, res); - DIP("%s %s.%s, %s.%s, %s.%s\n", nm, - nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr); - return True; - } - /* else fall through */ - } - - /* -------------------- FCVTN -------------------- */ - /* 31 28 23 20 15 9 4 - 0q0 01110 0s1 00001 011010 n d FCVTN Vd, Vn - where case q:s of 00: 16Fx4(lo) <- 32Fx4 - 01: 32Fx2(lo) <- 64Fx2 - 10: 16Fx4(hi) <- 32Fx4 - 11: 32Fx2(hi) <- 64Fx2 - Only deals with the 32Fx2 <- 64Fx2 version (s==1) - */ - if (INSN(31,31) == 0 && INSN(29,23) == BITS7(0,0,1,1,1,0,0) - && INSN(21,10) == BITS12(1,0,0,0,0,1,0,1,1,0,1,0)) { - UInt bQ = INSN(30,30); - UInt bS = INSN(22,22); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - if (bS == 1) { - IRTemp rm = mk_get_IR_rounding_mode(); - IRExpr* srcLo = getQRegLane(nn, 0, Ity_F64); - IRExpr* srcHi = getQRegLane(nn, 1, Ity_F64); - putQRegLane(dd, 2 * bQ + 0, binop(Iop_F64toF32, mkexpr(rm), srcLo)); - putQRegLane(dd, 2 * bQ + 1, binop(Iop_F64toF32, mkexpr(rm), srcHi)); - if (bQ == 0) { - putQRegLane(dd, 1, mkU64(0)); - } - DIP("fcvtn%s %s.%s, %s.2d\n", bQ ? "2" : "", - nameQReg128(dd), bQ ? "4s" : "2s", nameQReg128(nn)); - return True; - } - /* else fall through */ - } - - /* ---------------- ADD/SUB (vector) ---------------- */ - /* 31 28 23 21 20 15 9 4 - 0q0 01110 size 1 m 100001 n d ADD Vd.T, Vn.T, Vm.T - 0q1 01110 size 1 m 100001 n d SUB Vd.T, Vn.T, Vm.T - */ - if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0) - && INSN(21,21) == 1 && INSN(15,10) == BITS6(1,0,0,0,0,1)) { - Bool isQ = INSN(30,30) == 1; - UInt szBlg2 = INSN(23,22); - Bool isSUB = INSN(29,29) == 1; - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - Bool zeroHI = False; - const HChar* arrSpec = ""; - Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 ); - if (ok) { - const IROp opsADD[4] - = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_Add64x2 }; - const IROp opsSUB[4] - = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 }; - vassert(szBlg2 < 4); - IROp op = isSUB ? opsSUB[szBlg2] : opsADD[szBlg2]; - IRTemp t = newTemp(Ity_V128); - assign(t, binop(op, getQReg128(nn), getQReg128(mm))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t)) - : mkexpr(t)); - const HChar* nm = isSUB ? "sub" : "add"; - DIP("%s %s.%s, %s.%s, %s.%s\n", nm, - nameQReg128(dd), arrSpec, - nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec); - return True; - } - /* else fall through */ - } - - /* ---------------- ADD/SUB (scalar) ---------------- */ - /* 31 28 23 21 20 15 9 4 - 010 11110 11 1 m 100001 n d ADD Dd, Dn, Dm - 011 11110 11 1 m 100001 n d SUB Dd, Dn, Dm - */ - if (INSN(31,30) == BITS2(0,1) && INSN(28,21) == BITS8(1,1,1,1,0,1,1,1) - && INSN(15,10) == BITS6(1,0,0,0,0,1)) { - Bool isSUB = INSN(29,29) == 1; - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRTemp res = newTemp(Ity_I64); - assign(res, binop(isSUB ? Iop_Sub64 : Iop_Add64, - getQRegLane(nn, 0, Ity_I64), - getQRegLane(mm, 0, Ity_I64))); - putQRegLane(dd, 0, mkexpr(res)); - putQRegLane(dd, 1, mkU64(0)); - DIP("%s %s, %s, %s\n", isSUB ? "sub" : "add", - nameQRegLO(dd, Ity_I64), - nameQRegLO(nn, Ity_I64), nameQRegLO(mm, Ity_I64)); - return True; - } - - /* ------------ MUL/PMUL/MLA/MLS (vector) ------------ */ - /* 31 28 23 21 20 15 9 4 - 0q0 01110 size 1 m 100111 n d MUL Vd.T, Vn.T, Vm.T B/H/S only - 0q1 01110 size 1 m 100111 n d PMUL Vd.T, Vn.T, Vm.T B only - 0q0 01110 size 1 m 100101 n d MLA Vd.T, Vn.T, Vm.T B/H/S only - 0q1 01110 size 1 m 100101 n d MLS Vd.T, Vn.T, Vm.T B/H/S only - */ - if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0) - && INSN(21,21) == 1 - && (INSN(15,10) & BITS6(1,1,1,1,0,1)) == BITS6(1,0,0,1,0,1)) { - Bool isQ = INSN(30,30) == 1; - UInt szBlg2 = INSN(23,22); - UInt bit29 = INSN(29,29); - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - Bool isMLAS = INSN(11,11) == 0; - const IROp opsADD[4] - = { Iop_Add8x16, Iop_Add16x8, Iop_Add32x4, Iop_INVALID }; - const IROp opsSUB[4] - = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_INVALID }; - const IROp opsMUL[4] - = { Iop_Mul8x16, Iop_Mul16x8, Iop_Mul32x4, Iop_INVALID }; - const IROp opsPMUL[4] - = { Iop_PolynomialMul8x16, Iop_INVALID, Iop_INVALID, Iop_INVALID }; - /* Set opMUL and, if necessary, opACC. A result value of - Iop_INVALID for opMUL indicates that the instruction is - invalid. */ - Bool zeroHI = False; - const HChar* arrSpec = ""; - Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 ); - vassert(szBlg2 < 4); - IROp opACC = Iop_INVALID; - IROp opMUL = Iop_INVALID; - if (ok) { - opMUL = (bit29 == 1 && !isMLAS) ? opsPMUL[szBlg2] - : opsMUL[szBlg2]; - opACC = isMLAS ? (bit29 == 1 ? opsSUB[szBlg2] : opsADD[szBlg2]) - : Iop_INVALID; - } - if (ok && opMUL != Iop_INVALID) { - IRTemp t1 = newTemp(Ity_V128); - assign(t1, binop(opMUL, getQReg128(nn), getQReg128(mm))); - IRTemp t2 = newTemp(Ity_V128); - assign(t2, opACC == Iop_INVALID - ? mkexpr(t1) - : binop(opACC, getQReg128(dd), mkexpr(t1))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t2)) - : mkexpr(t2)); - const HChar* nm = isMLAS ? (bit29 == 1 ? "mls" : "mla") - : (bit29 == 1 ? "pmul" : "mul"); - DIP("%s %s.%s, %s.%s, %s.%s\n", nm, - nameQReg128(dd), arrSpec, - nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec); - return True; - } - /* else fall through */ - } - - /* ---------------- {S,U}{MIN,MAX} (vector) ---------------- */ - /* 31 28 23 21 20 15 9 4 - 0q0 01110 size 1 m 011011 n d SMIN Vd.T, Vn.T, Vm.T - 0q1 01110 size 1 m 011011 n d UMIN Vd.T, Vn.T, Vm.T - 0q0 01110 size 1 m 011001 n d SMAX Vd.T, Vn.T, Vm.T - 0q1 01110 size 1 m 011001 n d UMAX Vd.T, Vn.T, Vm.T - */ - if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0) - && INSN(21,21) == 1 - && ((INSN(15,10) & BITS6(1,1,1,1,0,1)) == BITS6(0,1,1,0,0,1))) { - Bool isQ = INSN(30,30) == 1; - Bool isU = INSN(29,29) == 1; - UInt szBlg2 = INSN(23,22); - Bool isMAX = INSN(11,11) == 0; - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - Bool zeroHI = False; - const HChar* arrSpec = ""; - Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 ); - if (ok) { - const IROp opMINS[4] - = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4, Iop_Min64Sx2 }; - const IROp opMINU[4] - = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4, Iop_Min64Ux2 }; - const IROp opMAXS[4] - = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4, Iop_Max64Sx2 }; - const IROp opMAXU[4] - = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4, Iop_Max64Ux2 }; - vassert(szBlg2 < 4); - IROp op = isMAX ? (isU ? opMAXU[szBlg2] : opMAXS[szBlg2]) - : (isU ? opMINU[szBlg2] : opMINS[szBlg2]); - IRTemp t = newTemp(Ity_V128); - assign(t, binop(op, getQReg128(nn), getQReg128(mm))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(t)) - : mkexpr(t)); - const HChar* nm = isMAX ? (isU ? "umax" : "smax") - : (isU ? "umin" : "smin"); - DIP("%s %s.%s, %s.%s, %s.%s\n", nm, - nameQReg128(dd), arrSpec, - nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec); - return True; - } - /* else fall through */ - } - - /* -------------------- {S,U}{MIN,MAX}V -------------------- */ - /* 31 28 23 21 16 15 9 4 - 0q0 01110 size 11000 1 101010 n d SMINV Vd, Vn.T - 0q1 01110 size 11000 1 101010 n d UMINV Vd, Vn.T - 0q0 01110 size 11000 0 101010 n d SMAXV Vd, Vn.T - 0q1 01110 size 11000 0 101010 n d UMAXV Vd, Vn.T - */ - if (INSN(31,31) == 0 && INSN(28,24) == BITS5(0,1,1,1,0) - && INSN(21,17) == BITS5(1,1,0,0,0) - && INSN(15,10) == BITS6(1,0,1,0,1,0)) { - Bool isQ = INSN(30,30) == 1; - Bool isU = INSN(29,29) == 1; - UInt szBlg2 = INSN(23,22); - Bool isMAX = INSN(16,16) == 0; - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - Bool zeroHI = False; - const HChar* arrSpec = ""; - Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2); - if (ok) { - if (szBlg2 == 3) ok = False; - if (szBlg2 == 2 && !isQ) ok = False; - } - if (ok) { - const IROp opMINS[3] - = { Iop_Min8Sx16, Iop_Min16Sx8, Iop_Min32Sx4 }; - const IROp opMINU[3] - = { Iop_Min8Ux16, Iop_Min16Ux8, Iop_Min32Ux4 }; - const IROp opMAXS[3] - = { Iop_Max8Sx16, Iop_Max16Sx8, Iop_Max32Sx4 }; - const IROp opMAXU[3] - = { Iop_Max8Ux16, Iop_Max16Ux8, Iop_Max32Ux4 }; - vassert(szBlg2 < 3); - IROp op = isMAX ? (isU ? opMAXU[szBlg2] : opMAXS[szBlg2]) - : (isU ? opMINU[szBlg2] : opMINS[szBlg2]); - IRTemp tN1 = newTemp(Ity_V128); - assign(tN1, getQReg128(nn)); - /* If Q == 0, we're just folding lanes in the lower half of - the value. In which case, copy the lower half of the - source into the upper half, so we can then treat it the - same as the full width case. */ - IRTemp tN2 = newTemp(Ity_V128); - assign(tN2, zeroHI ? mk_CatEvenLanes64x2(tN1,tN1) : mkexpr(tN1)); - IRTemp res = math_MINMAXV(tN2, op); - if (res == IRTemp_INVALID) - return False; /* means math_MINMAXV - doesn't handle this case yet */ - putQReg128(dd, mkexpr(res)); - const HChar* nm = isMAX ? (isU ? "umaxv" : "smaxv") - : (isU ? "uminv" : "sminv"); - const IRType tys[3] = { Ity_I8, Ity_I16, Ity_I32 }; - IRType laneTy = tys[szBlg2]; - DIP("%s %s, %s.%s\n", nm, - nameQRegLO(dd, laneTy), nameQReg128(nn), arrSpec); - return True; - } - /* else fall through */ - } - - /* ------------ {AND,BIC,ORR,ORN} (vector) ------------ */ - /* 31 28 23 20 15 9 4 - 0q0 01110 001 m 000111 n d AND Vd.T, Vn.T, Vm.T - 0q0 01110 011 m 000111 n d BIC Vd.T, Vn.T, Vm.T - 0q0 01110 101 m 000111 n d ORR Vd.T, Vn.T, Vm.T - 0q0 01110 111 m 000111 n d ORN Vd.T, Vn.T, Vm.T - T is 16b when q==1, 8b when q==0 - */ - if (INSN(31,31) == 0 && INSN(29,24) == BITS6(0,0,1,1,1,0) - && INSN(21,21) == 1 && INSN(15,10) == BITS6(0,0,0,1,1,1)) { - Bool isQ = INSN(30,30) == 1; - Bool isORR = INSN(23,23) == 1; - Bool invert = INSN(22,22) == 1; - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRTemp res = newTemp(Ity_V128); - assign(res, binop(isORR ? Iop_OrV128 : Iop_AndV128, - getQReg128(nn), - invert ? unop(Iop_NotV128, getQReg128(mm)) - : getQReg128(mm))); - putQReg128(dd, isQ ? mkexpr(res) - : unop(Iop_ZeroHI64ofV128, mkexpr(res))); - const HChar* names[4] = { "and", "bic", "orr", "orn" }; - const HChar* ar = isQ ? "16b" : "8b"; - DIP("%s %s.%s, %s.%s, %s.%s\n", names[INSN(23,22)], - nameQReg128(dd), ar, nameQReg128(nn), ar, nameQReg128(mm), ar); - return True; - } - - /* ---------- CM{EQ,HI,HS,GE,GT,TST,LE,LT} (vector) ---------- */ - /* 31 28 23 21 15 9 4 ix - 0q1 01110 size 1 m 100011 n d CMEQ Vd.T, Vn.T, Vm.T (1) == - 0q0 01110 size 1 m 100011 n d CMTST Vd.T, Vn.T, Vm.T (2) &, != 0 - - 0q1 01110 size 1 m 001101 n d CMHI Vd.T, Vn.T, Vm.T (3) >u - 0q0 01110 size 1 m 001101 n d CMGT Vd.T, Vn.T, Vm.T (4) >s - - 0q1 01110 size 1 m 001111 n d CMHS Vd.T, Vn.T, Vm.T (5) >=u - 0q0 01110 size 1 m 001111 n d CMGE Vd.T, Vn.T, Vm.T (6) >=s - - 0q1 01110 size 100000 100010 n d CMGE Vd.T, Vn.T, #0 (7) >=s 0 - 0q0 01110 size 100000 100010 n d CMGT Vd.T, Vn.T, #0 (8) >s 0 - - 0q1 01110 size 100000 100110 n d CMLE Vd.T, Vn.T, #0 (9) <=s 0 - 0q0 01110 size 100000 100110 n d CMEQ Vd.T, Vn.T, #0 (10) == 0 - - 0q0 01110 size 100000 101010 n d CMLT Vd.T, Vn.T, #0 (11) y can be expressed directly - x < y == y > x - x <= y == not (x > y) - x >= y == not (y > x) - */ - switch (ix) { - case 1: res = binop(opsEQ[szBlg2], argL, argR); break; - case 2: res = unop(Iop_NotV128, binop(opsEQ[szBlg2], - binop(Iop_AndV128, argL, argR), - mkV128(0x0000))); - break; - case 3: res = binop(opsGTU[szBlg2], argL, argR); break; - case 4: res = binop(opsGTS[szBlg2], argL, argR); break; - case 5: res = unop(Iop_NotV128, binop(opsGTU[szBlg2], argR, argL)); - break; - case 6: res = unop(Iop_NotV128, binop(opsGTS[szBlg2], argR, argL)); - break; - case 7: res = unop(Iop_NotV128, binop(opsGTS[szBlg2], argR, argL)); - break; - case 8: res = binop(opsGTS[szBlg2], argL, argR); break; - case 9: res = unop(Iop_NotV128, - binop(opsGTS[szBlg2], argL, argR)); - break; - case 10: res = binop(opsEQ[szBlg2], argL, argR); break; - case 11: res = binop(opsGTS[szBlg2], argR, argL); break; - default: vassert(0); - } - vassert(res); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, res) : res); - const HChar* nms[11] = { "eq", "tst", "hi", "gt", "hs", "ge", - "ge", "gt", "le", "eq", "lt" }; - if (ix <= 6) { - DIP("cm%s %s.%s, %s.%s, %s.%s\n", nms[ix-1], - nameQReg128(dd), arrSpec, - nameQReg128(nn), arrSpec, nameQReg128(mm), arrSpec); - } else { - DIP("cm%s %s.%s, %s.%s, #0\n", nms[ix-1], - nameQReg128(dd), arrSpec, nameQReg128(nn), arrSpec); - } - return True; - } - /* else fall through */ - } - - /* -------------- {EOR,BSL,BIT,BIF} (vector) -------------- */ - /* 31 28 23 20 15 9 4 - 0q1 01110 00 1 m 000111 n d EOR Vd.T, Vm.T, Vn.T - 0q1 01110 01 1 m 000111 n d BSL Vd.T, Vm.T, Vn.T - 0q1 01110 10 1 m 000111 n d BIT Vd.T, Vm.T, Vn.T - 0q1 01110 11 1 m 000111 n d BIF Vd.T, Vm.T, Vn.T - */ - if (INSN(31,31) == 0 && INSN(29,24) == BITS6(1,0,1,1,1,0) - && INSN(21,21) == 1 && INSN(15,10) == BITS6(0,0,0,1,1,1)) { - Bool isQ = INSN(30,30) == 1; - UInt op = INSN(23,22); - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRTemp argD = newTemp(Ity_V128); - IRTemp argN = newTemp(Ity_V128); - IRTemp argM = newTemp(Ity_V128); - assign(argD, getQReg128(dd)); - assign(argN, getQReg128(nn)); - assign(argM, getQReg128(mm)); - const IROp opXOR = Iop_XorV128; - const IROp opAND = Iop_AndV128; - const IROp opNOT = Iop_NotV128; - IRExpr* res = NULL; - switch (op) { - case BITS2(0,0): /* EOR */ - res = binop(opXOR, mkexpr(argM), mkexpr(argN)); - break; - case BITS2(0,1): /* BSL */ - res = binop(opXOR, mkexpr(argM), - binop(opAND, - binop(opXOR, mkexpr(argM), mkexpr(argN)), - mkexpr(argD))); - break; - case BITS2(1,0): /* BIT */ - res = binop(opXOR, mkexpr(argD), - binop(opAND, - binop(opXOR, mkexpr(argD), mkexpr(argN)), - mkexpr(argM))); - break; - case BITS2(1,1): /* BIF */ - res = binop(opXOR, mkexpr(argD), - binop(opAND, - binop(opXOR, mkexpr(argD), mkexpr(argN)), - unop(opNOT, mkexpr(argM)))); - break; - default: - vassert(0); - } - vassert(res); - putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res)); - const HChar* nms[4] = { "eor", "bsl", "bit", "bif" }; - const HChar* arr = isQ ? "16b" : "8b"; - vassert(op < 4); - DIP("%s %s.%s, %s.%s, %s.%s\n", nms[op], - nameQReg128(dd), arr, nameQReg128(nn), arr, nameQReg128(mm), arr); - return True; - } - - /* ------------ {USHR,SSHR,SHL} (vector, immediate) ------------ */ - /* 31 28 22 18 15 9 4 - 0q1 011110 immh immb 000001 n d USHR Vd.T, Vn.T, #shift (1) - 0q0 011110 immh immb 000001 n d SSHR Vd.T, Vn.T, #shift (2) - 0q0 011110 immh immb 010101 n d SHL Vd.T, Vn.T, #shift (3) - laneTy, shift = case immh:immb of - 0001:xxx -> B, SHR:8-xxx, SHL:xxx - 001x:xxx -> H, SHR:16-xxxx SHL:xxxx - 01xx:xxx -> S, SHR:32-xxxxx SHL:xxxxx - 1xxx:xxx -> D, SHR:64-xxxxxx SHL:xxxxxx - other -> invalid - As usual the case laneTy==D && q==0 is not allowed. - */ - if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,1,0) - && INSN(10,10) == 1) { - UInt ix = 0; - /**/ if (INSN(29,29) == 1 && INSN(15,11) == BITS5(0,0,0,0,0)) ix = 1; - else if (INSN(29,29) == 0 && INSN(15,11) == BITS5(0,0,0,0,0)) ix = 2; - else if (INSN(29,29) == 0 && INSN(15,11) == BITS5(0,1,0,1,0)) ix = 3; - if (ix > 0) { - Bool isQ = INSN(30,30) == 1; - UInt immh = INSN(22,19); - UInt immb = INSN(18,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - const IROp opsSHRN[4] - = { Iop_ShrN8x16, Iop_ShrN16x8, Iop_ShrN32x4, Iop_ShrN64x2 }; - const IROp opsSARN[4] - = { Iop_SarN8x16, Iop_SarN16x8, Iop_SarN32x4, Iop_SarN64x2 }; - const IROp opsSHLN[4] - = { Iop_ShlN8x16, Iop_ShlN16x8, Iop_ShlN32x4, Iop_ShlN64x2 }; - UInt szBlg2 = 0; - UInt shift = 0; - Bool ok = getLaneInfo_IMMH_IMMB(&shift, &szBlg2, immh, immb); - if (ix == 3) { - /* The shift encoding has opposite sign for the leftwards - case. Adjust shift to compensate. */ - shift = (8 << szBlg2) - shift; - } - if (ok && szBlg2 < 4 && shift > 0 && shift < (8 << szBlg2) - && !(szBlg2 == 3/*64bit*/ && !isQ)) { - IROp op = Iop_INVALID; - const HChar* nm = NULL; - switch (ix) { - case 1: op = opsSHRN[szBlg2]; nm = "ushr"; break; - case 2: op = opsSARN[szBlg2]; nm = "sshr"; break; - case 3: op = opsSHLN[szBlg2]; nm = "shl"; break; - default: vassert(0); - } - IRExpr* src = getQReg128(nn); - IRExpr* res = binop(op, src, mkU8(shift)); - putQReg128(dd, isQ ? res : unop(Iop_ZeroHI64ofV128, res)); - HChar laneCh = "bhsd"[szBlg2]; - UInt nLanes = (isQ ? 128 : 64) / (8 << szBlg2); - DIP("%s %s.%u%c, %s.%u%c, #%u\n", nm, - nameQReg128(dd), nLanes, laneCh, - nameQReg128(nn), nLanes, laneCh, shift); - return True; - } - /* else fall through */ - } - } - - /* -------------------- {U,S}SHLL{,2} -------------------- */ - /* 31 28 22 18 15 9 4 - 0q0 011110 immh immb 101001 n d SSHLL Vd.Ta, Vn.Tb, #sh - 0q1 011110 immh immb 101001 n d USHLL Vd.Ta, Vn.Tb, #sh - where Ta,Tb,sh - = case immh of 1xxx -> invalid - 01xx -> 2d, 2s(q0)/4s(q1), immh:immb - 32 (0..31) - 001x -> 4s, 4h(q0)/8h(q1), immh:immb - 16 (0..15) - 0001 -> 8h, 8b(q0)/16b(q1), immh:immb - 8 (0..7) - 0000 -> AdvSIMD modified immediate (???) - */ - if (INSN(31,31) == 0 && INSN(28,23) == BITS6(0,1,1,1,1,0) - && INSN(15,10) == BITS6(1,0,1,0,0,1)) { - Bool isQ = INSN(30,30) == 1; - Bool isU = INSN(29,29) == 1; - UInt immh = INSN(22,19); - UInt immb = INSN(18,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - UInt immhb = (immh << 3) | immb; - IRTemp src = newTemp(Ity_V128); - IRTemp zero = newTemp(Ity_V128); - IRExpr* res = NULL; - UInt sh = 0; - const HChar* ta = "??"; - const HChar* tb = "??"; - assign(src, getQReg128(nn)); - assign(zero, mkV128(0x0000)); - if (immh & 8) { - /* invalid; don't assign to res */ - } - else if (immh & 4) { - sh = immhb - 32; - vassert(sh < 32); /* so 32-sh is 1..32 */ - ta = "2d"; - tb = isQ ? "4s" : "2s"; - IRExpr* tmp = isQ ? mk_InterleaveHI32x4(src, zero) - : mk_InterleaveLO32x4(src, zero); - res = binop(isU ? Iop_ShrN64x2 : Iop_SarN64x2, tmp, mkU8(32-sh)); - } - else if (immh & 2) { - sh = immhb - 16; - vassert(sh < 16); /* so 16-sh is 1..16 */ - ta = "4s"; - tb = isQ ? "8h" : "4h"; - IRExpr* tmp = isQ ? mk_InterleaveHI16x8(src, zero) - : mk_InterleaveLO16x8(src, zero); - res = binop(isU ? Iop_ShrN32x4 : Iop_SarN32x4, tmp, mkU8(16-sh)); - } - else if (immh & 1) { - sh = immhb - 8; - vassert(sh < 8); /* so 8-sh is 1..8 */ - ta = "8h"; - tb = isQ ? "16b" : "8b"; - IRExpr* tmp = isQ ? mk_InterleaveHI8x16(src, zero) - : mk_InterleaveLO8x16(src, zero); - res = binop(isU ? Iop_ShrN16x8 : Iop_SarN16x8, tmp, mkU8(8-sh)); - } else { - vassert(immh == 0); - /* invalid; don't assign to res */ - } - /* */ - if (res) { - putQReg128(dd, res); - DIP("%cshll%s %s.%s, %s.%s, #%d\n", - isU ? 'u' : 's', isQ ? "2" : "", - nameQReg128(dd), ta, nameQReg128(nn), tb, sh); - return True; - } - /* else fall through */ - } - - /* -------------------- XTN{,2} -------------------- */ - /* 31 28 23 21 15 9 4 XTN{,2} Vd.Tb, Vn.Ta - 0q0 01110 size 100001 001010 n d - */ - if (INSN(31,31) == 0 && INSN(29,24) == BITS6(0,0,1,1,1,0) - && INSN(21,16) == BITS6(1,0,0,0,0,1) - && INSN(15,10) == BITS6(0,0,1,0,1,0)) { - Bool isQ = INSN(30,30) == 1; - UInt size = INSN(23,22); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IROp op = Iop_INVALID; - const HChar* tb = NULL; - const HChar* ta = NULL; - switch ((size << 1) | (isQ ? 1 : 0)) { - case 0: tb = "8b"; ta = "8h"; op = Iop_NarrowUn16to8x8; break; - case 1: tb = "16b"; ta = "8h"; op = Iop_NarrowUn16to8x8; break; - case 2: tb = "4h"; ta = "4s"; op = Iop_NarrowUn32to16x4; break; - case 3: tb = "8h"; ta = "4s"; op = Iop_NarrowUn32to16x4; break; - case 4: tb = "2s"; ta = "2d"; op = Iop_NarrowUn64to32x2; break; - case 5: tb = "4s"; ta = "2d"; op = Iop_NarrowUn64to32x2; break; - case 6: break; - case 7: break; - default: vassert(0); - } - if (op != Iop_INVALID) { - if (!isQ) { - putQRegLane(dd, 1, mkU64(0)); - } - putQRegLane(dd, isQ ? 1 : 0, unop(op, getQReg128(nn))); - DIP("xtn%s %s.%s, %s.%s\n", isQ ? "2" : "", - nameQReg128(dd), tb, nameQReg128(nn), ta); - return True; - } - /* else fall through */ - } - - /* ---------------- DUP (element, vector) ---------------- */ - /* 31 28 20 15 9 4 - 0q0 01110000 imm5 000001 n d DUP Vd.T, Vn.Ts[index] - */ - if (INSN(31,31) == 0 && INSN(29,21) == BITS9(0,0,1,1,1,0,0,0,0) - && INSN(15,10) == BITS6(0,0,0,0,0,1)) { - Bool isQ = INSN(30,30) == 1; - UInt imm5 = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - IRTemp w0 = newTemp(Ity_I64); - const HChar* arT = "??"; - const HChar* arTs = "??"; - IRType laneTy = Ity_INVALID; - UInt laneNo = 16; /* invalid */ - if (imm5 & 1) { - arT = isQ ? "16b" : "8b"; - arTs = "b"; - laneNo = (imm5 >> 1) & 15; - laneTy = Ity_I8; - assign(w0, unop(Iop_8Uto64, getQRegLane(nn, laneNo, laneTy))); - } - else if (imm5 & 2) { - arT = isQ ? "8h" : "4h"; - arTs = "h"; - laneNo = (imm5 >> 2) & 7; - laneTy = Ity_I16; - assign(w0, unop(Iop_16Uto64, getQRegLane(nn, laneNo, laneTy))); - } - else if (imm5 & 4) { - arT = isQ ? "4s" : "2s"; - arTs = "s"; - laneNo = (imm5 >> 3) & 3; - laneTy = Ity_I32; - assign(w0, unop(Iop_32Uto64, getQRegLane(nn, laneNo, laneTy))); - } - else if ((imm5 & 8) && isQ) { - arT = "2d"; - arTs = "d"; - laneNo = (imm5 >> 4) & 1; - laneTy = Ity_I64; - assign(w0, getQRegLane(nn, laneNo, laneTy)); - } - else { - /* invalid; leave laneTy unchanged. */ - } - /* */ - if (laneTy != Ity_INVALID) { - vassert(laneNo < 16); - IRTemp w1 = math_DUP_TO_64(w0, laneTy); - putQReg128(dd, binop(Iop_64HLtoV128, - isQ ? mkexpr(w1) : mkU64(0), mkexpr(w1))); - DIP("dup %s.%s, %s.%s[%u]\n", - nameQReg128(dd), arT, nameQReg128(nn), arTs, laneNo); - return True; - } - /* else fall through */ - } - - /* ---------------------- {S,U}MOV ---------------------- */ - /* 31 28 20 15 9 4 - 0q0 01110 000 imm5 001111 n d UMOV Xd/Wd, Vn.Ts[index] - 0q0 01110 000 imm5 001011 n d SMOV Xd/Wd, Vn.Ts[index] - dest is Xd when q==1, Wd when q==0 - UMOV: - Ts,index,ops = case q:imm5 of - 0:xxxx1 -> B, xxxx, 8Uto64 - 1:xxxx1 -> invalid - 0:xxx10 -> H, xxx, 16Uto64 - 1:xxx10 -> invalid - 0:xx100 -> S, xx, 32Uto64 - 1:xx100 -> invalid - 1:x1000 -> D, x, copy64 - other -> invalid - SMOV: - Ts,index,ops = case q:imm5 of - 0:xxxx1 -> B, xxxx, (32Uto64 . 8Sto32) - 1:xxxx1 -> B, xxxx, 8Sto64 - 0:xxx10 -> H, xxx, (32Uto64 . 16Sto32) - 1:xxx10 -> H, xxx, 16Sto64 - 0:xx100 -> invalid - 1:xx100 -> S, xx, 32Sto64 - 1:x1000 -> invalid - other -> invalid - */ - if (INSN(31,31) == 0 && INSN(29,21) == BITS9(0,0,1,1,1,0,0,0,0) - && (INSN(15,10) & BITS6(1,1,1,0,1,1)) == BITS6(0,0,1,0,1,1)) { - UInt bitQ = INSN(30,30) == 1; - UInt imm5 = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - Bool isU = INSN(12,12) == 1; - const HChar* arTs = "??"; - UInt laneNo = 16; /* invalid */ - // Setting 'res' to non-NULL determines valid/invalid - IRExpr* res = NULL; - if (!bitQ && (imm5 & 1)) { // 0:xxxx1 - laneNo = (imm5 >> 1) & 15; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I8); - res = isU ? unop(Iop_8Uto64, lane) - : unop(Iop_32Uto64, unop(Iop_8Sto32, lane)); - arTs = "b"; - } - else if (bitQ && (imm5 & 1)) { // 1:xxxx1 - laneNo = (imm5 >> 1) & 15; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I8); - res = isU ? NULL - : unop(Iop_8Sto64, lane); - arTs = "b"; - } - else if (!bitQ && (imm5 & 2)) { // 0:xxx10 - laneNo = (imm5 >> 2) & 7; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I16); - res = isU ? unop(Iop_16Uto64, lane) - : unop(Iop_32Uto64, unop(Iop_16Sto32, lane)); - arTs = "h"; - } - else if (bitQ && (imm5 & 2)) { // 1:xxx10 - laneNo = (imm5 >> 2) & 7; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I16); - res = isU ? NULL - : unop(Iop_16Sto64, lane); - arTs = "h"; - } - else if (!bitQ && (imm5 & 4)) { // 0:xx100 - laneNo = (imm5 >> 3) & 3; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I32); - res = isU ? unop(Iop_32Uto64, lane) - : NULL; - arTs = "s"; - } - else if (bitQ && (imm5 & 4)) { // 1:xxx10 - laneNo = (imm5 >> 3) & 3; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I32); - res = isU ? NULL - : unop(Iop_32Sto64, lane); - arTs = "s"; - } - else if (bitQ && (imm5 & 8)) { // 1:x1000 - laneNo = (imm5 >> 4) & 1; - IRExpr* lane = getQRegLane(nn, laneNo, Ity_I64); - res = isU ? lane - : NULL; - arTs = "d"; - } - /* */ - if (res) { - vassert(laneNo < 16); - putIReg64orZR(dd, res); - DIP("%cmov %s, %s.%s[%u]\n", isU ? 'u' : 's', - nameIRegOrZR(bitQ == 1, dd), - nameQReg128(nn), arTs, laneNo); - return True; - } - /* else fall through */ - } - - /* -------------------- INS (general) -------------------- */ - /* 31 28 20 15 9 4 - 010 01110000 imm5 000111 n d INS Vd.Ts[ix], Rn - where Ts,ix = case imm5 of xxxx1 -> B, xxxx - xxx10 -> H, xxx - xx100 -> S, xx - x1000 -> D, x - */ - if (INSN(31,21) == BITS11(0,1,0,0,1,1,1,0,0,0,0) - && INSN(15,10) == BITS6(0,0,0,1,1,1)) { - UInt imm5 = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - HChar ts = '?'; - UInt laneNo = 16; - IRExpr* src = NULL; - if (imm5 & 1) { - src = unop(Iop_64to8, getIReg64orZR(nn)); - laneNo = (imm5 >> 1) & 15; - ts = 'b'; - } - else if (imm5 & 2) { - src = unop(Iop_64to16, getIReg64orZR(nn)); - laneNo = (imm5 >> 2) & 7; - ts = 'h'; - } - else if (imm5 & 4) { - src = unop(Iop_64to32, getIReg64orZR(nn)); - laneNo = (imm5 >> 3) & 3; - ts = 's'; - } - else if (imm5 & 8) { - src = getIReg64orZR(nn); - laneNo = (imm5 >> 4) & 1; - ts = 'd'; - } - /* */ - if (src) { - vassert(laneNo < 16); - putQRegLane(dd, laneNo, src); - DIP("ins %s.%c[%u], %s\n", - nameQReg128(dd), ts, laneNo, nameIReg64orZR(nn)); - return True; - } - /* else invalid; fall through */ - } - - /* -------------------- NEG (vector) -------------------- */ - /* 31 28 23 21 16 9 4 - 0q1 01110 sz 10000 0101110 n d NEG Vd, Vn - sz is laneSz, q:sz == 011 is disallowed, as usual - */ - if (INSN(31,31) == 0 && INSN(29,24) == BITS6(1,0,1,1,1,0) - && INSN(21,10) == BITS12(1,0,0,0,0,0,1,0,1,1,1,0)) { - Bool isQ = INSN(30,30) == 1; - UInt szBlg2 = INSN(23,22); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - Bool zeroHI = False; - const HChar* arrSpec = ""; - Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2 ); - if (ok) { - const IROp opSUB[4] - = { Iop_Sub8x16, Iop_Sub16x8, Iop_Sub32x4, Iop_Sub64x2 }; - IRTemp res = newTemp(Ity_V128); - vassert(szBlg2 < 4); - assign(res, binop(opSUB[szBlg2], mkV128(0x0000), getQReg128(nn))); - putQReg128(dd, zeroHI ? unop(Iop_ZeroHI64ofV128, mkexpr(res)) - : mkexpr(res)); - DIP("neg %s.%s, %s.%s\n", - nameQReg128(dd), arrSpec, nameQReg128(nn), arrSpec); - return True; - } - /* else fall through */ - } - - /* -------------------- TBL, TBX -------------------- */ - /* 31 28 20 15 14 12 9 4 - 0q0 01110 000 m 0 len 000 n d TBL Vd.Ta, {Vn .. V(n+len)%32}, Vm.Ta - 0q0 01110 000 m 0 len 100 n d TBX Vd.Ta, {Vn .. V(n+len)%32}, Vm.Ta - where Ta = 16b(q=1) or 8b(q=0) - */ - if (INSN(31,31) == 0 && INSN(29,21) == BITS9(0,0,1,1,1,0,0,0,0) - && INSN(15,15) == 0 && INSN(11,10) == BITS2(0,0)) { - Bool isQ = INSN(30,30) == 1; - Bool isTBX = INSN(12,12) == 1; - UInt mm = INSN(20,16); - UInt len = INSN(14,13); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - /* The out-of-range values to use. */ - IRTemp oor_values = newTemp(Ity_V128); - assign(oor_values, isTBX ? getQReg128(dd) : mkV128(0)); - /* src value */ - IRTemp src = newTemp(Ity_V128); - assign(src, getQReg128(mm)); - /* The table values */ - IRTemp tab[4]; - UInt i; - for (i = 0; i <= len; i++) { - vassert(i < 4); - tab[i] = newTemp(Ity_V128); - assign(tab[i], getQReg128((nn + i) % 32)); - } - IRTemp res = math_TBL_TBX(tab, len, src, oor_values); - putQReg128(dd, isQ ? mkexpr(res) - : unop(Iop_ZeroHI64ofV128, mkexpr(res)) ); - const HChar* Ta = isQ ? "16b" : "8b"; - const HChar* nm = isTBX ? "tbx" : "tbl"; - DIP("%s %s.%s, {v%d.16b .. v%d.16b}, %s.%s\n", - nm, nameQReg128(dd), Ta, nn, (nn + len) % 32, nameQReg128(mm), Ta); - return True; - } - /* FIXME Temporary hacks to get through ld.so FIXME */ - - /* ------------------ movi vD.4s, #0x0 ------------------ */ - /* 0x4F 0x00 0x04 000 vD */ - if ((insn & 0xFFFFFFE0) == 0x4F000400) { - UInt vD = INSN(4,0); - putQReg128(vD, mkV128(0x0000)); - DIP("movi v%u.4s, #0x0\n", vD); - return True; - } - - /* ---------------- MOV vD.16b, vN.16b ---------------- */ - /* 31 23 20 15 9 4 - 010 01110 101 m 000111 n d ORR vD.16b, vN.16b, vM.16b - This only handles the N == M case. - */ - if (INSN(31,24) == BITS8(0,1,0,0,1,1,1,0) - && INSN(23,21) == BITS3(1,0,1) && INSN(15,10) == BITS6(0,0,0,1,1,1)) { - UInt mm = INSN(20,16); - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - if (mm == nn) { - putQReg128(dd, getQReg128(nn)); - DIP("mov v%u.16b, v%u.16b\n", dd, nn); - return True; - } - /* else it's really an ORR; fall through. */ - } - - /* ---------------- CMEQ_d_d_#0 ---------------- */ - /* - 010 11110 11 10000 0100 110 n d CMEQ Dd, Dn, #0 - */ - if ((INSN(31,0) & 0xFFFFFC00) == 0x5EE09800) { - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - putQReg128(dd, unop(Iop_ZeroHI64ofV128, - binop(Iop_CmpEQ64x2, getQReg128(nn), - mkV128(0x0000)))); - DIP("cmeq d%u, d%u, #0\n", dd, nn); - return True; - } - - /* ---------------- SHL_d_d_#imm ---------------- */ - /* 31 22 21 18 15 9 4 - 010 111110 1 ih3 ib 010101 n d SHL Dd, Dn, #(ih3:ib) - */ - if (INSN(31,22) == BITS10(0,1,0,1,1,1,1,1,0,1) - && INSN(15,10) == BITS6(0,1,0,1,0,1)) { - UInt nn = INSN(9,5); - UInt dd = INSN(4,0); - UInt sh = INSN(21,16); - vassert(sh < 64); - putQReg128(dd, unop(Iop_ZeroHI64ofV128, - binop(Iop_ShlN64x2, getQReg128(nn), mkU8(sh)))); - DIP("shl d%u, d%u, #%u\n", dd, nn, sh); - return True; - } - - vex_printf("ARM64 front end: simd_and_fp\n"); - return False; -# undef INSN -} - /*------------------------------------------------------------*/ /*--- Disassemble a single ARM64 instruction ---*/