aboutsummaryrefslogtreecommitdiff
path: root/gas
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 /gas
parent245d2e3fe8d9ff35c65ed1329609fb7e59034877 (diff)
downloadfsf-binutils-gdb-2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e.zip
fsf-binutils-gdb-2442d8466e221ba6cf4ec4bd2a819fdcb1e5ea7e.tar.gz
fsf-binutils-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 'gas')
-rw-r--r--gas/ChangeLog8
-rw-r--r--gas/config/tc-aarch64.c42
2 files changed, 49 insertions, 1 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index d532bb1..97f1a61 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,13 @@
2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+ * 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.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* config/tc-aarch64.c (parse_enum_string): New function.
(po_enum_or_fail): New macro.
(parse_operands): Handle AARCH64_OPND_SVE_PATTERN and
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 7a3a39d..79ee054 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -2882,6 +2882,7 @@ enum parse_shift_mode
SHIFTED_LOGIC_IMM, /* "rn{,lsl|lsr|asl|asr|ror #n}" or
"#imm" */
SHIFTED_LSL, /* bare "lsl #n" */
+ SHIFTED_MUL, /* bare "mul #n" */
SHIFTED_LSL_MSL, /* "lsl|msl #n" */
SHIFTED_REG_OFFSET /* [su]xtw|sxtx {#n} or lsl #n */
};
@@ -2923,6 +2924,13 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode)
return FALSE;
}
+ if (kind == AARCH64_MOD_MUL
+ && mode != SHIFTED_MUL)
+ {
+ set_syntax_error (_("invalid use of 'MUL'"));
+ return FALSE;
+ }
+
switch (mode)
{
case SHIFTED_LOGIC_IMM:
@@ -2949,6 +2957,14 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode)
}
break;
+ case SHIFTED_MUL:
+ if (kind != AARCH64_MOD_MUL)
+ {
+ set_syntax_error (_("only 'MUL' is permitted"));
+ return FALSE;
+ }
+ break;
+
case SHIFTED_REG_OFFSET:
if (kind != AARCH64_MOD_UXTW && kind != AARCH64_MOD_LSL
&& kind != AARCH64_MOD_SXTW && kind != AARCH64_MOD_SXTX)
@@ -3001,7 +3017,11 @@ parse_shift (char **str, aarch64_opnd_info *operand, enum parse_shift_mode mode)
set_syntax_error (_("constant shift amount required"));
return FALSE;
}
- else if (exp.X_add_number < 0 || exp.X_add_number > 63)
+ /* For parsing purposes, MUL #n has no inherent range. The range
+ depends on the operand and will be checked by operand-specific
+ routines. */
+ else if (kind != AARCH64_MOD_MUL
+ && (exp.X_add_number < 0 || exp.X_add_number > 63))
{
set_fatal_syntax_error (_("shift amount out of range 0 to 63"));
return FALSE;
@@ -4863,6 +4883,12 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
operand->imm.value = default_value;
break;
+ case AARCH64_OPND_SVE_PATTERN_SCALED:
+ operand->imm.value = default_value;
+ operand->shifter.kind = AARCH64_MOD_MUL;
+ operand->shifter.amount = 1;
+ break;
+
case AARCH64_OPND_EXCEPTION:
inst.reloc.type = BFD_RELOC_UNUSED;
break;
@@ -5373,6 +5399,20 @@ parse_operands (char *str, const aarch64_opcode *opcode)
info->imm.value = val;
break;
+ case AARCH64_OPND_SVE_PATTERN_SCALED:
+ po_enum_or_fail (aarch64_sve_pattern_array);
+ info->imm.value = val;
+ if (skip_past_comma (&str)
+ && !parse_shift (&str, info, SHIFTED_MUL))
+ goto failure;
+ if (!info->shifter.operator_present)
+ {
+ gas_assert (info->shifter.kind == AARCH64_MOD_NONE);
+ info->shifter.kind = AARCH64_MOD_MUL;
+ info->shifter.amount = 1;
+ }
+ break;
+
case AARCH64_OPND_SVE_PRFOP:
po_enum_or_fail (aarch64_sve_prfop_array);
info->imm.value = val;