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. */
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,
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. */
/* -------- {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
# undef INSN
}
+
static
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)
{
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;
# undef INSN
}
+
static
Bool dis_AdvSIMD_scalar_three_different(/*MB_OUT*/DisResult* dres, UInt insn)
{
# undef INSN
}
+
static
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)
{
# undef INSN
}
+
static
Bool dis_AdvSIMD_three_different(/*MB_OUT*/DisResult* dres, UInt insn)
{
# undef INSN
}
+
static
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)
{
# undef INSN
}
+
static
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)
{
# undef INSN
}
+
static
Bool dis_AdvSIMD_fp_conditional_select(/*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) <s 0
- */
- 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 bit29 = INSN(29,29);
- UInt szBlg2 = INSN(23,22);
- UInt mm = INSN(20,16);
- UInt b1510 = INSN(15,10);
- UInt nn = INSN(9,5);
- UInt dd = INSN(4,0);
- const IROp opsEQ[4]
- = { Iop_CmpEQ8x16, Iop_CmpEQ16x8, Iop_CmpEQ32x4, Iop_CmpEQ64x2 };
- const IROp opsGTS[4]
- = { Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4, Iop_CmpGT64Sx2 };
- const IROp opsGTU[4]
- = { Iop_CmpGT8Ux16, Iop_CmpGT16Ux8, Iop_CmpGT32Ux4, Iop_CmpGT64Ux2 };
- Bool zeroHI = False;
- const HChar* arrSpec = "??";
- Bool ok = getLaneInfo_SIMPLE(&zeroHI, &arrSpec, isQ, szBlg2);
- UInt ix = 0;
- if (ok) {
- switch (b1510) {
- case BITS6(1,0,0,0,1,1): ix = bit29 ? 1 : 2; break;
- case BITS6(0,0,1,1,0,1): ix = bit29 ? 3 : 4; break;
- case BITS6(0,0,1,1,1,1): ix = bit29 ? 5 : 6; break;
- case BITS6(1,0,0,0,1,0):
- if (mm == 0) { ix = bit29 ? 7 : 8; }; break;
- case BITS6(1,0,0,1,1,0):
- if (mm == 0) { ix = bit29 ? 9 : 10; }; break;
- case BITS6(1,0,1,0,1,0):
- if (mm == 0 && bit29 == 0) { ix = 11; }; break;
- default: break;
- }
- }
- if (ix != 0) {
- vassert(ok && szBlg2 < 4);
- IRExpr* argL = getQReg128(nn);
- IRExpr* argR = (ix <= 6) ? getQReg128(mm) : mkV128(0x0000);
- IRExpr* res = NULL;
- /* Some useful identities:
- x > 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 ---*/