[PATCH 45/57][Arm][OBJDUMP] Add support for MVE instructions: vmov, vmvn, vorr, vorn, vmovx and vbic

opcodes/ChangeLog:
2019-05-16  Andre Vieira  <andre.simoesdiasvieira@arm.com>
	    Michael Collison <michael.collison@arm.com>

	* arm-dis.c (enum mve_instructions): Add new instructions.
	(enum mve_unpredictable): Add new reasons.
	(enum mve_undefined): Likewise.
	(is_mve_okay_in_it): Handle new isntructions.
	(is_mve_encoding_conflict): Likewise.
	(is_mve_undefined): Likewise.
	(is_mve_unpredictable): Likewise.
	(print_mve_vmov_index): Likewise.
	(print_simd_imm8): Likewise.
	(print_mve_undefined): Likewise.
	(print_mve_unpredictable): Likewise.
	(print_mve_size): Likewise.
	(print_insn_mve): Likewise.
This commit is contained in:
Andre Vieira 2019-05-16 14:29:36 +01:00
parent bf0b396de7
commit c507f10b07
2 changed files with 621 additions and 5 deletions

View File

@ -1,3 +1,20 @@
2019-05-16 Andre Vieira <andre.simoesdiasvieira@arm.com>
Michael Collison <michael.collison@arm.com>
* arm-dis.c (enum mve_instructions): Add new instructions.
(enum mve_unpredictable): Add new reasons.
(enum mve_undefined): Likewise.
(is_mve_okay_in_it): Handle new isntructions.
(is_mve_encoding_conflict): Likewise.
(is_mve_undefined): Likewise.
(is_mve_unpredictable): Likewise.
(print_mve_vmov_index): Likewise.
(print_simd_imm8): Likewise.
(print_mve_undefined): Likewise.
(print_mve_unpredictable): Likewise.
(print_mve_size): Likewise.
(print_insn_mve): Likewise.
2019-05-16 Andre Vieira <andre.simoesdiasvieira@arm.com>
Michael Collison <michael.collison@arm.com>

View File

@ -129,6 +129,21 @@ enum mve_instructions
MVE_VCVT_FP_HALF_FP,
MVE_VCVT_FROM_FP_TO_INT,
MVE_VRINT_FP,
MVE_VMOV_HFP_TO_GP,
MVE_VMOV_GP_TO_VEC_LANE,
MVE_VMOV_IMM_TO_VEC,
MVE_VMOV_VEC_TO_VEC,
MVE_VMOV2_VEC_LANE_TO_GP,
MVE_VMOV2_GP_TO_VEC_LANE,
MVE_VMOV_VEC_LANE_TO_GP,
MVE_VMVN_IMM,
MVE_VMVN_REG,
MVE_VORR_IMM,
MVE_VORR_REG,
MVE_VORN,
MVE_VBIC_IMM,
MVE_VBIC_REG,
MVE_VMOVX,
MVE_NONE
};
@ -152,12 +167,17 @@ enum mve_unpredictable
UNPRED_OS, /* Unpredictable because offset scaled == 1. */
UNPRED_GP_REGS_EQUAL, /* Unpredictable because gp registers are the
same. */
UNPRED_Q_REGS_EQ_AND_SIZE_1, /* Unpredictable because q regs equal and
size = 1. */
UNPRED_Q_REGS_EQ_AND_SIZE_2, /* Unpredictable because q regs equal and
size = 2. */
UNPRED_NONE /* No unpredictable behavior. */
};
enum mve_undefined
{
UNDEF_SIZE_0, /* undefined because size == 0. */
UNDEF_SIZE_2, /* undefined because size == 2. */
UNDEF_SIZE_3, /* undefined because size == 3. */
UNDEF_SIZE_LE_1, /* undefined because size <= 1. */
UNDEF_SIZE_NOT_2, /* undefined because size != 2. */
@ -169,6 +189,12 @@ enum mve_undefined
UNDEF_NOT_UNSIGNED, /* undefined because U == 0. */
UNDEF_VCVT_IMM6, /* imm6 < 32. */
UNDEF_VCVT_FSI_IMM6, /* fsi = 0 and 32 >= imm6 <= 47. */
UNDEF_BAD_OP1_OP2, /* undefined with op2 = 2 and
op1 == (0 or 1). */
UNDEF_BAD_U_OP1_OP2, /* undefined with U = 1 and
op2 == 0 and op1 == (0 or 1). */
UNDEF_OP_0_BAD_CMODE, /* undefined because op == 0 and cmode
in {0xx1, x0x1}. */
UNDEF_NONE /* no undefined behavior. */
};
@ -1885,15 +1911,19 @@ static const struct opcode32 neon_opcodes[] =
%o print offset scaled for vldr[hwd] and vstr[hwd]
%w print writeback mode for MVE v{st,ld}[24]
%B print v{st,ld}[24] any one operands
%E print vmov, vmvn, vorr, vbic encoded constant
%N print generic index for vmov
%<bitfield>r print as an ARM register
%<bitfield>d print the bitfield in decimal
%<bitfield>Q print as a MVE Q register
%<bitfield>F print as a MVE S register
%<bitfield>Z as %<>r but r15 is ZR instead of PC and r13 is
UNPREDICTABLE
%<bitfield>s print size for vector predicate & non VMOV instructions
%<bitfield>i print immediate for vstr/vldr reg +/- imm
%<bitfield>k print immediate for vector conversion instruction
%<bitfield>x print the bitfield in hex.
*/
static const struct mopcode32 mve_opcodes[] =
@ -1948,6 +1978,18 @@ static const struct mopcode32 mve_opcodes[] =
0xfe011f40, 0xff811f50,
"vpt%i.s%20-21s\t%n, %17-19Q, %0-3Z"},
/* Vector VBIC immediate. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VBIC_IMM,
0xef800070, 0xefb81070,
"vbic%v.i%8-11s\t%13-15,22Q, %E"},
/* Vector VBIC register. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VBIC_REG,
0xef100150, 0xffb11f51,
"vbic%v\t%13-15,22Q, %17-19,7Q, %1-3,5Q"},
/* Vector VCMP floating point T1. */
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VCMP_FP_T1,
@ -2171,6 +2213,103 @@ static const struct mopcode32 mve_opcodes[] =
0xec101f00, 0xfe101f80,
"vldrw%v.u32\t%13-15,22Q, %d"},
/* Vector VMOV between gpr and half precision register, op == 0. */
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VMOV_HFP_TO_GP,
0xee000910, 0xfff00f7f,
"vmov.f16\t%7,16-19F, %12-15r"},
/* Vector VMOV between gpr and half precision register, op == 1. */
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VMOV_HFP_TO_GP,
0xee100910, 0xfff00f7f,
"vmov.f16\t%12-15r, %7,16-19F"},
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VMOV_GP_TO_VEC_LANE,
0xee000b10, 0xff900f1f,
"vmov%c.%5-6,21-22s\t%17-19,7Q[%N], %12-15r"},
/* Vector VORR immediate to vector.
NOTE: MVE_VORR_IMM must appear in the table
before MVE_VMOV_IMM_TO_VEC due to opcode aliasing. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VORR_IMM,
0xef800050, 0xefb810f0,
"vorr%v.i%8-11s\t%13-15,22Q, %E"},
/* Vector VMOV immediate to vector,
cmode == 11x1 -> VMVN which is UNDEFINED
for such a cmode. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMVN_IMM, 0xef800d50, 0xefb81dd0, UNDEFINED_INSTRUCTION},
/* Vector VMOV immediate to vector. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMOV_IMM_TO_VEC,
0xef800050, 0xefb810d0,
"vmov%v.%5,8-11s\t%13-15,22Q, %E"},
/* Vector VMOV two 32-bit lanes to two gprs, idx = 0. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMOV2_VEC_LANE_TO_GP,
0xec000f00, 0xffb01ff0,
"vmov%c\t%0-3r, %16-19r, %13-15,22Q[2], %13-15,22Q[0]"},
/* Vector VMOV two 32-bit lanes to two gprs, idx = 1. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMOV2_VEC_LANE_TO_GP,
0xec000f10, 0xffb01ff0,
"vmov%c\t%0-3r, %16-19r, %13-15,22Q[3], %13-15,22Q[1]"},
/* Vector VMOV Two gprs to two 32-bit lanes, idx = 0. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMOV2_GP_TO_VEC_LANE,
0xec100f00, 0xffb01ff0,
"vmov%c\t%13-15,22Q[2], %13-15,22Q[0], %0-3r, %16-19r"},
/* Vector VMOV Two gprs to two 32-bit lanes, idx = 1. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMOV2_GP_TO_VEC_LANE,
0xec100f10, 0xffb01ff0,
"vmov%c\t%13-15,22Q[2], %13-15,22Q[0], %0-3r, %16-19r"},
/* Vector VMOV Vector lane to gpr. */
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VMOV_VEC_LANE_TO_GP,
0xee100b10, 0xff100f1f,
"vmov%c.%u%5-6,21-22s\t%12-15r, %17-19,7Q[%N]"},
/* Floating point move extract. */
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VMOVX,
0xfeb00a40, 0xffbf0fd0,
"vmovx.f16\t%22,12-15F, %5,0-3F"},
/* Vector VMVN immediate to vector. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMVN_IMM,
0xef800070, 0xefb810f0,
"vmvn%v.i%8-11s\t%13-15,22Q, %E"},
/* Vector VMVN register. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VMVN_REG,
0xffb005c0, 0xffbf1fd1,
"vmvn%v\t%13-15,22Q, %1-3,5Q"},
/* Vector VORN, vector bitwise or not. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VORN,
0xef300150, 0xffb11f51,
"vorn%v\t%13-15,22Q, %17-19,7Q, %1-3,5Q"},
/* Vector VORR register. */
{ARM_FEATURE_COPROC (FPU_MVE),
MVE_VORR_REG,
0xef200150, 0xffb11f51,
"vorr%v\t%13-15,22Q, %17-19,7Q, %1-3,5Q"},
/* Vector VRINT floating point. */
{ARM_FEATURE_COPROC (FPU_MVE_FP),
MVE_VRINT_FP,
@ -4127,7 +4266,16 @@ arm_decode_shift (long given, fprintf_ftype func, void *stream,
static bfd_boolean
is_mve_okay_in_it (enum mve_instructions matched_insn)
{
return FALSE;
switch (matched_insn)
{
case MVE_VMOV_GP_TO_VEC_LANE:
case MVE_VMOV2_VEC_LANE_TO_GP:
case MVE_VMOV2_GP_TO_VEC_LANE:
case MVE_VMOV_VEC_LANE_TO_GP:
return TRUE;
default:
return FALSE;
}
}
static bfd_boolean
@ -4320,6 +4468,40 @@ is_mve_encoding_conflict (unsigned long given,
case MVE_VCVT_FP_FIX_VEC:
return (arm_decode_field (given, 16, 21) & 0x38) == 0;
case MVE_VBIC_IMM:
case MVE_VORR_IMM:
{
unsigned long cmode = arm_decode_field (given, 8, 11);
if ((cmode & 1) == 0)
return TRUE;
else if ((cmode & 0xc) == 0xc)
return TRUE;
else
return FALSE;
}
case MVE_VMVN_IMM:
{
unsigned long cmode = arm_decode_field (given, 8, 11);
if ((cmode & 9) == 1)
return TRUE;
else if ((cmode & 5) == 1)
return TRUE;
else if ((cmode & 0xe) == 0xe)
return TRUE;
else
return FALSE;
}
case MVE_VMOV_IMM_TO_VEC:
if ((arm_decode_field (given, 5, 5) == 1)
&& (arm_decode_field (given, 8, 11) != 0xe))
return TRUE;
else
return FALSE;
default:
return FALSE;
@ -4612,6 +4794,67 @@ is_mve_undefined (unsigned long given, enum mve_instructions matched_insn,
return FALSE;
}
case MVE_VMOV_VEC_LANE_TO_GP:
{
unsigned long op1 = arm_decode_field (given, 21, 22);
unsigned long op2 = arm_decode_field (given, 5, 6);
unsigned long u = arm_decode_field (given, 23, 23);
if ((op2 == 0) && (u == 1))
{
if ((op1 == 0) || (op1 == 1))
{
*undefined_code = UNDEF_BAD_U_OP1_OP2;
return TRUE;
}
else
return FALSE;
}
else if (op2 == 2)
{
if ((op1 == 0) || (op1 == 1))
{
*undefined_code = UNDEF_BAD_OP1_OP2;
return TRUE;
}
else
return FALSE;
}
return FALSE;
}
case MVE_VMOV_GP_TO_VEC_LANE:
if (arm_decode_field (given, 5, 6) == 2)
{
unsigned long op1 = arm_decode_field (given, 21, 22);
if ((op1 == 0) || (op1 == 1))
{
*undefined_code = UNDEF_BAD_OP1_OP2;
return TRUE;
}
else
return FALSE;
}
else
return FALSE;
case MVE_VMOV_IMM_TO_VEC:
if (arm_decode_field (given, 5, 5) == 0)
{
unsigned long cmode = arm_decode_field (given, 8, 11);
if (((cmode & 9) == 1) || ((cmode & 5) == 1))
{
*undefined_code = UNDEF_OP_0_BAD_CMODE;
return TRUE;
}
else
return FALSE;
}
else
return FALSE;
default:
return FALSE;
}
@ -4837,6 +5080,8 @@ is_mve_unpredictable (unsigned long given, enum mve_instructions matched_insn,
else
return FALSE;
case MVE_VMOV2_VEC_LANE_TO_GP:
case MVE_VMOV2_GP_TO_VEC_LANE:
case MVE_VCVT_BETWEEN_FP_INT:
case MVE_VCVT_FROM_FP_TO_INT:
{
@ -4862,11 +5107,224 @@ is_mve_unpredictable (unsigned long given, enum mve_instructions matched_insn,
return FALSE;
}
case MVE_VMOV_HFP_TO_GP:
case MVE_VMOV_GP_TO_VEC_LANE:
case MVE_VMOV_VEC_LANE_TO_GP:
{
unsigned long rda = arm_decode_field (given, 12, 15);
if (rda == 0xd)
{
*unpredictable_code = UNPRED_R13;
return TRUE;
}
else if (rda == 0xf)
{
*unpredictable_code = UNPRED_R15;
return TRUE;
}
return FALSE;
}
default:
return FALSE;
}
}
static void
print_mve_vmov_index (struct disassemble_info *info, unsigned long given)
{
unsigned long op1 = arm_decode_field (given, 21, 22);
unsigned long op2 = arm_decode_field (given, 5, 6);
unsigned long h = arm_decode_field (given, 16, 16);
unsigned long index, esize, targetBeat, idx;
void *stream = info->stream;
fprintf_ftype func = info->fprintf_func;
if ((op1 & 0x2) == 0x2)
{
index = op2;
esize = 8;
}
else if (((op1 & 0x2) == 0x0) && ((op2 & 0x1) == 0x1))
{
index = op2 >> 1;
esize = 16;
}
else if (((op1 & 0x2) == 0) && ((op2 & 0x3) == 0))
{
index = 0;
esize = 32;
}
else
{
func (stream, "<undefined index>");
return;
}
targetBeat = (op1 & 0x1) | (h << 1);
idx = index + targetBeat * (32/esize);
func (stream, "%lu", idx);
}
/* Print neon and mve 8-bit immediate that can be a 8, 16, 32, or 64-bits
in length and integer of floating-point type. */
static void
print_simd_imm8 (struct disassemble_info *info, unsigned long given,
unsigned int ibit_loc, const struct mopcode32 *insn)
{
int bits = 0;
int cmode = (given >> 8) & 0xf;
int op = (given >> 5) & 0x1;
unsigned long value = 0, hival = 0;
unsigned shift;
int size = 0;
int isfloat = 0;
void *stream = info->stream;
fprintf_ftype func = info->fprintf_func;
/* On Neon the 'i' bit is at bit 24, on mve it is
at bit 28. */
bits |= ((given >> ibit_loc) & 1) << 7;
bits |= ((given >> 16) & 7) << 4;
bits |= ((given >> 0) & 15) << 0;
if (cmode < 8)
{
shift = (cmode >> 1) & 3;
value = (unsigned long) bits << (8 * shift);
size = 32;
}
else if (cmode < 12)
{
shift = (cmode >> 1) & 1;
value = (unsigned long) bits << (8 * shift);
size = 16;
}
else if (cmode < 14)
{
shift = (cmode & 1) + 1;
value = (unsigned long) bits << (8 * shift);
value |= (1ul << (8 * shift)) - 1;
size = 32;
}
else if (cmode == 14)
{
if (op)
{
/* Bit replication into bytes. */
int ix;
unsigned long mask;
value = 0;
hival = 0;
for (ix = 7; ix >= 0; ix--)
{
mask = ((bits >> ix) & 1) ? 0xff : 0;
if (ix <= 3)
value = (value << 8) | mask;
else
hival = (hival << 8) | mask;
}
size = 64;
}
else
{
/* Byte replication. */
value = (unsigned long) bits;
size = 8;
}
}
else if (!op)
{
/* Floating point encoding. */
int tmp;
value = (unsigned long) (bits & 0x7f) << 19;
value |= (unsigned long) (bits & 0x80) << 24;
tmp = bits & 0x40 ? 0x3c : 0x40;
value |= (unsigned long) tmp << 24;
size = 32;
isfloat = 1;
}
else
{
func (stream, "<illegal constant %.8x:%x:%x>",
bits, cmode, op);
size = 32;
return;
}
// printU determines whether the immediate value should be printed as
// unsigned.
unsigned printU = 0;
switch (insn->mve_op)
{
default:
break;
// We want this for instructions that don't have a 'signed' type
case MVE_VBIC_IMM:
case MVE_VORR_IMM:
case MVE_VMVN_IMM:
case MVE_VMOV_IMM_TO_VEC:
printU = 1;
break;
}
switch (size)
{
case 8:
func (stream, "#%ld\t; 0x%.2lx", value, value);
break;
case 16:
func (stream,
printU
? "#%lu\t; 0x%.4lx"
: "#%ld\t; 0x%.4lx", value, value);
break;
case 32:
if (isfloat)
{
unsigned char valbytes[4];
double fvalue;
/* Do this a byte at a time so we don't have to
worry about the host's endianness. */
valbytes[0] = value & 0xff;
valbytes[1] = (value >> 8) & 0xff;
valbytes[2] = (value >> 16) & 0xff;
valbytes[3] = (value >> 24) & 0xff;
floatformat_to_double
(& floatformat_ieee_single_little, valbytes,
& fvalue);
func (stream, "#%.7g\t; 0x%.8lx", fvalue,
value);
}
else
func (stream,
printU
? "#%lu\t; 0x%.8lx"
: "#%ld\t; 0x%.8lx",
(long) (((value & 0x80000000L) != 0)
&& !printU
? value | ~0xffffffffL : value),
value);
break;
case 64:
func (stream, "#0x%.8lx%.8lx", hival, value);
break;
default:
abort ();
}
}
static void
print_mve_undefined (struct disassemble_info *info,
enum mve_undefined undefined_code)
@ -4882,6 +5340,10 @@ print_mve_undefined (struct disassemble_info *info,
func (stream, "size equals zero");
break;
case UNDEF_SIZE_2:
func (stream, "size equals two");
break;
case UNDEF_SIZE_3:
func (stream, "size equals three");
break;
@ -4918,6 +5380,18 @@ print_mve_undefined (struct disassemble_info *info,
func (stream, "fsi = 0 and invalid imm6");
break;
case UNDEF_BAD_OP1_OP2:
func (stream, "bad size with op2 = 2 and op1 = 0 or 1");
break;
case UNDEF_BAD_U_OP1_OP2:
func (stream, "unsigned with op2 = 0 and op1 = 0 or 1");
break;
case UNDEF_OP_0_BAD_CMODE:
func (stream, "op field equal 0 and bad cmode");
break;
case UNDEF_NONE:
break;
}
@ -4976,6 +5450,14 @@ print_mve_unpredictable (struct disassemble_info *info,
func (stream, "same general-purpose register used for both operands");
break;
case UNPRED_Q_REGS_EQ_AND_SIZE_1:
func (stream, "use of identical q registers and size = 1");
break;
case UNPRED_Q_REGS_EQ_AND_SIZE_2:
func (stream, "use of identical q registers and size = 1");
break;
case UNPRED_NONE:
break;
}
@ -5339,6 +5821,88 @@ print_mve_size (struct disassemble_info *info,
}
break;
case MVE_VMOV_GP_TO_VEC_LANE:
case MVE_VMOV_VEC_LANE_TO_GP:
switch (size)
{
case 0: case 4:
func (stream, "32");
break;
case 1: case 3:
case 5: case 7:
func (stream, "16");
break;
case 8: case 9: case 10: case 11:
case 12: case 13: case 14: case 15:
func (stream, "8");
break;
default:
break;
}
break;
case MVE_VMOV_IMM_TO_VEC:
switch (size)
{
case 0: case 4: case 8:
case 12: case 24: case 26:
func (stream, "i32");
break;
case 16: case 20:
func (stream, "i16");
break;
case 28:
func (stream, "i8");
break;
case 29:
func (stream, "i64");
break;
case 30:
func (stream, "f32");
break;
default:
break;
}
break;
case MVE_VMVN_IMM:
switch (size)
{
case 0: case 2: case 4:
case 6: case 12: case 13:
func (stream, "32");
break;
case 8: case 10:
func (stream, "16");
break;
default:
break;
}
break;
case MVE_VBIC_IMM:
case MVE_VORR_IMM:
switch (size)
{
case 1: case 3:
case 5: case 7:
func (stream, "32");
break;
case 9: case 11:
func (stream, "16");
break;
default:
break;
}
break;
default:
break;
}
@ -5563,7 +6127,6 @@ print_insn_coprocessor (bfd_vma pc,
don't let it match here. */
continue;
for (c = insn->assembler; *c; c++)
{
if (*c == '%')
@ -6830,10 +7393,30 @@ print_insn_mve (struct disassemble_info *info, long given)
case 'u':
{
if (arm_decode_field (given, 28, 28) == 0)
func (stream, "s");
unsigned long op1 = arm_decode_field (given, 21, 22);
if ((insn->mve_op == MVE_VMOV_VEC_LANE_TO_GP))
{
/* Check for signed. */
if (arm_decode_field (given, 23, 23) == 0)
{
/* We don't print 's' for S32. */
if ((arm_decode_field (given, 5, 6) == 0)
&& ((op1 == 0) || (op1 == 1)))
;
else
func (stream, "s");
}
else
func (stream, "u");
}
else
func (stream, "u");
{
if (arm_decode_field (given, 28, 28) == 0)
func (stream, "s");
else
func (stream, "u");
}
}
break;
@ -6850,6 +7433,16 @@ print_insn_mve (struct disassemble_info *info, long given)
print_mve_register_blocks (info, given, insn->mve_op);
break;
case 'E':
/* SIMD encoded constant for mov, mvn, vorr, vbic. */
print_simd_imm8 (info, given, 28, insn);
break;
case 'N':
print_mve_vmov_index (info, given);
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
@ -6907,12 +7500,18 @@ print_insn_mve (struct disassemble_info *info, long given)
func (stream, "%ld", value);
value_in_comment = value;
break;
case 'F':
func (stream, "s%ld", value);
break;
case 'Q':
if (value & 0x8)
func (stream, "<illegal reg q%ld.5>", value);
else
func (stream, "q%ld", value);
break;
case 'x':
func (stream, "0x%08lx", value);
break;
default:
abort ();
}