aboutsummaryrefslogtreecommitdiff
path: root/opcodes/aarch64-opc.c
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:55:22 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:55:22 +0100
commit2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e (patch)
tree3cf11472e060354947af66613dd1b4a6361f9b02 /opcodes/aarch64-opc.c
parent245d2e3fe8d9ff35c65ed1329609fb7e59034877 (diff)
downloadgdb-2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e.zip
gdb-2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e.tar.gz
gdb-2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e.tar.bz2
[AArch64][SVE 24/32] Add AARCH64_OPND_SVE_PATTERN_SCALED
Some SVE instructions count the number of elements in a given vector pattern and allow a scale factor of [1, 16] to be applied to the result. This scale factor is written ", MUL #n", where "MUL" is a new operator. E.g.: UQINCD X0, POW2, MUL #2 This patch adds support for this kind of operand. All existing operators were shifts of some kind, so there was a natural range of [0, 63] regardless of context. This was then narrowered further by later checks (e.g. to [0, 31] when used for 32-bit values). In contrast, MUL doesn't really have a natural context-independent range. Rather than pick one arbitrarily, it seemed better to make the "shift" amount a full 64-bit value and leave the range test to the usual operand-checking code. I've rearranged the fields of aarch64_opnd_info so that this doesn't increase the size of the structure (although I don't think its size is critical anyway). include/ * opcode/aarch64.h (AARCH64_OPND_SVE_PATTERN_SCALED): New aarch64_opnd. (AARCH64_MOD_MUL): New aarch64_modifier_kind. (aarch64_opnd_info): Make shifter.amount an int64_t and rearrange the fields. opcodes/ * aarch64-tbl.h (AARCH64_OPERANDS): Add an entry for AARCH64_OPND_SVE_PATTERN_SCALED. * aarch64-opc.h (FLD_SVE_imm4): New aarch64_field_kind. * aarch64-opc.c (fields): Add a corresponding entry. (set_multiplier_out_of_range_error): New function. (aarch64_operand_modifiers): Add entry for AARCH64_MOD_MUL. (operand_general_constraint_met_p): Handle AARCH64_OPND_SVE_PATTERN_SCALED. (print_register_offset_address): Use PRIi64 to print the shift amount. (aarch64_print_operand): Likewise. Handle AARCH64_OPND_SVE_PATTERN_SCALED. * aarch64-opc-2.c: Regenerate. * aarch64-asm.h (ins_sve_scale): New inserter. * aarch64-asm.c (aarch64_ins_sve_scale): New function. * aarch64-asm-2.c: Regenerate. * aarch64-dis.h (ext_sve_scale): New inserter. * aarch64-dis.c (aarch64_ext_sve_scale): New function. * aarch64-dis-2.c: Regenerate. gas/ * config/tc-aarch64.c (SHIFTED_MUL): New parse_shift_mode. (parse_shift): Handle it. Reject AARCH64_MOD_MUL for all other shift modes. Skip range tests for AARCH64_MOD_MUL. (process_omitted_operand): Handle AARCH64_OPND_SVE_PATTERN_SCALED. (parse_operands): Likewise.
Diffstat (limited to 'opcodes/aarch64-opc.c')
-rw-r--r--opcodes/aarch64-opc.c54
1 files changed, 49 insertions, 5 deletions
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 934c14d..326b94e 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -279,6 +279,7 @@ const aarch64_field fields[] =
{ 16, 5 }, /* SVE_Zm_16: SVE vector register, bits [20,16]. */
{ 5, 5 }, /* SVE_Zn: SVE vector register, bits [9,5]. */
{ 0, 5 }, /* SVE_Zt: SVE vector register, bits [4,0]. */
+ { 16, 4 }, /* SVE_imm4: 4-bit immediate field. */
{ 5, 5 }, /* SVE_pattern: vector pattern enumeration. */
{ 0, 4 }, /* SVE_prfop: prefetch operation for SVE PRF[BHWD]. */
{ 22, 2 }, /* SVE_tszh: triangular size select high, bits [23,22]. */
@@ -359,6 +360,7 @@ const struct aarch64_name_value_pair aarch64_operand_modifiers [] =
{"sxth", 0x5},
{"sxtw", 0x6},
{"sxtx", 0x7},
+ {"mul", 0x0},
{NULL, 0},
};
@@ -1303,6 +1305,18 @@ set_sft_amount_out_of_range_error (aarch64_operand_error *mismatch_detail,
_("shift amount"));
}
+/* Report that the MUL modifier in operand IDX should be in the range
+ [LOWER_BOUND, UPPER_BOUND]. */
+static inline void
+set_multiplier_out_of_range_error (aarch64_operand_error *mismatch_detail,
+ int idx, int lower_bound, int upper_bound)
+{
+ if (mismatch_detail == NULL)
+ return;
+ set_out_of_range_error (mismatch_detail, idx, lower_bound, upper_bound,
+ _("multiplier"));
+}
+
static inline void
set_unaligned_error (aarch64_operand_error *mismatch_detail, int idx,
int alignment)
@@ -2001,6 +2015,15 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
}
break;
+ case AARCH64_OPND_SVE_PATTERN_SCALED:
+ assert (opnd->shifter.kind == AARCH64_MOD_MUL);
+ if (!value_in_range_p (opnd->shifter.amount, 1, 16))
+ {
+ set_multiplier_out_of_range_error (mismatch_detail, idx, 1, 16);
+ return 0;
+ }
+ break;
+
default:
break;
}
@@ -2525,7 +2548,8 @@ print_register_offset_address (char *buf, size_t size,
if (print_extend_p)
{
if (print_amount_p)
- snprintf (tb, sizeof (tb), ",%s #%d", shift_name, opnd->shifter.amount);
+ snprintf (tb, sizeof (tb), ",%s #%" PRIi64, shift_name,
+ opnd->shifter.amount);
else
snprintf (tb, sizeof (tb), ",%s", shift_name);
}
@@ -2620,7 +2644,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
}
}
if (opnd->shifter.amount)
- snprintf (buf, size, "%s, %s #%d",
+ snprintf (buf, size, "%s, %s #%" PRIi64,
get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0),
aarch64_operand_modifiers[kind].name,
opnd->shifter.amount);
@@ -2637,7 +2661,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
snprintf (buf, size, "%s",
get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0));
else
- snprintf (buf, size, "%s, %s #%d",
+ snprintf (buf, size, "%s, %s #%" PRIi64,
get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0),
aarch64_operand_modifiers[opnd->shifter.kind].name,
opnd->shifter.amount);
@@ -2760,6 +2784,26 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
snprintf (buf, size, "#%" PRIi64, opnd->imm.value);
break;
+ case AARCH64_OPND_SVE_PATTERN_SCALED:
+ if (optional_operand_p (opcode, idx)
+ && !opnd->shifter.operator_present
+ && opnd->imm.value == get_optional_operand_default_value (opcode))
+ break;
+ enum_value = opnd->imm.value;
+ assert (enum_value < ARRAY_SIZE (aarch64_sve_pattern_array));
+ if (aarch64_sve_pattern_array[opnd->imm.value])
+ snprintf (buf, size, "%s", aarch64_sve_pattern_array[opnd->imm.value]);
+ else
+ snprintf (buf, size, "#%" PRIi64, opnd->imm.value);
+ if (opnd->shifter.operator_present)
+ {
+ size_t len = strlen (buf);
+ snprintf (buf + len, size - len, ", %s #%" PRIi64,
+ aarch64_operand_modifiers[opnd->shifter.kind].name,
+ opnd->shifter.amount);
+ }
+ break;
+
case AARCH64_OPND_SVE_PRFOP:
enum_value = opnd->imm.value;
assert (enum_value < ARRAY_SIZE (aarch64_sve_prfop_array));
@@ -2794,7 +2838,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
case AARCH64_OPND_AIMM:
case AARCH64_OPND_HALF:
if (opnd->shifter.amount)
- snprintf (buf, size, "#0x%" PRIx64 ", lsl #%d", opnd->imm.value,
+ snprintf (buf, size, "#0x%" PRIx64 ", lsl #%" PRIi64, opnd->imm.value,
opnd->shifter.amount);
else
snprintf (buf, size, "#0x%" PRIx64, opnd->imm.value);
@@ -2806,7 +2850,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
|| opnd->shifter.kind == AARCH64_MOD_NONE)
snprintf (buf, size, "#0x%" PRIx64, opnd->imm.value);
else
- snprintf (buf, size, "#0x%" PRIx64 ", %s #%d", opnd->imm.value,
+ snprintf (buf, size, "#0x%" PRIx64 ", %s #%" PRIi64, opnd->imm.value,
aarch64_operand_modifiers[opnd->shifter.kind].name,
opnd->shifter.amount);
break;