"AARCH64_OPDE_SYNTAX_ERROR",
"AARCH64_OPDE_FATAL_SYNTAX_ERROR",
"AARCH64_OPDE_INVALID_VARIANT",
- "AARCH64_OPDE_REG_LIST",
+ "AARCH64_OPDE_REG_LIST_LENGTH",
+ "AARCH64_OPDE_REG_LIST_STRIDE",
"AARCH64_OPDE_UNTIED_IMMS",
"AARCH64_OPDE_UNTIED_OPERAND",
"AARCH64_OPDE_OUT_OF_RANGE",
gas_assert (AARCH64_OPDE_SYNTAX_ERROR > AARCH64_OPDE_EXPECTED_A_AFTER_B);
gas_assert (AARCH64_OPDE_FATAL_SYNTAX_ERROR > AARCH64_OPDE_SYNTAX_ERROR);
gas_assert (AARCH64_OPDE_INVALID_VARIANT > AARCH64_OPDE_FATAL_SYNTAX_ERROR);
- gas_assert (AARCH64_OPDE_REG_LIST > AARCH64_OPDE_INVALID_VARIANT);
- gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST);
+ gas_assert (AARCH64_OPDE_REG_LIST_LENGTH > AARCH64_OPDE_INVALID_VARIANT);
+ gas_assert (AARCH64_OPDE_REG_LIST_STRIDE > AARCH64_OPDE_REG_LIST_LENGTH);
+ gas_assert (AARCH64_OPDE_OUT_OF_RANGE > AARCH64_OPDE_REG_LIST_STRIDE);
gas_assert (AARCH64_OPDE_UNALIGNED > AARCH64_OPDE_OUT_OF_RANGE);
- gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST);
+ gas_assert (AARCH64_OPDE_OTHER_ERROR > AARCH64_OPDE_REG_LIST_STRIDE);
gas_assert (AARCH64_OPDE_INVALID_REGNO > AARCH64_OPDE_OTHER_ERROR);
return lhs > rhs;
}
detail->data[0].i, idx + 1, str);
break;
- case AARCH64_OPDE_REG_LIST:
+ case AARCH64_OPDE_REG_LIST_LENGTH:
if (detail->data[0].i == (1 << 1))
handler (_("expected a single-register list at operand %d -- `%s'"),
idx + 1, str);
" at operand %d -- `%s'"), idx + 1, str);
break;
+ case AARCH64_OPDE_REG_LIST_STRIDE:
+ if (detail->data[0].i == (1 << 1))
+ handler (_("the register list must have a stride of %d"
+ " at operand %d -- `%s'"), 1, idx + 1, str);
+ else
+ handler (_("invalid register stride at operand %d -- `%s'"),
+ idx + 1, str);
+ break;
+
case AARCH64_OPDE_UNALIGNED:
handler (_("immediate value must be a multiple of "
"%d at operand %d -- `%s'"),
curr->detail.data[0].i, curr->detail.data[1].i,
curr->detail.data[2].i);
}
- else if (curr->detail.kind == AARCH64_OPDE_REG_LIST)
+ else if (curr->detail.kind == AARCH64_OPDE_REG_LIST_LENGTH
+ || curr->detail.kind == AARCH64_OPDE_REG_LIST_STRIDE)
{
DEBUG_TRACE ("\t%s [%x]",
operand_mismatch_kind_names[curr->detail.kind],
curr->detail.data[0].i, curr->detail.data[1].i,
curr->detail.data[2].i);
}
- else if (kind == AARCH64_OPDE_REG_LIST)
+ else if (kind == AARCH64_OPDE_REG_LIST_LENGTH
+ || kind == AARCH64_OPDE_REG_LIST_STRIDE)
{
record->detail.data[0].i |= curr->detail.data[0].i;
DEBUG_TRACE ("\t--> %s [%x]",
}
/* Check whether a register list REGINFO is valid. The registers must be
- numbered in increasing order (modulo 32), in increments of one or two.
+ numbered in increasing order (modulo 32). They must also have a
+ consistent stride.
- If ACCEPT_ALTERNATE is non-zero, the register numbers should be in
- increments of two.
-
- Return FALSE if such a register list is invalid, otherwise return TRUE. */
+ Return true if the list is valid, describing it in LIST if so. */
static bool
-reg_list_valid_p (uint32_t reginfo, int accept_alternate)
+reg_list_valid_p (uint32_t reginfo, struct aarch64_reglist *list)
{
uint32_t i, nb_regs, prev_regno, incr;
nb_regs = 1 + (reginfo & 0x3);
reginfo >>= 2;
prev_regno = reginfo & 0x1f;
- incr = accept_alternate ? 2 : 1;
+ incr = 1;
+
+ list->first_regno = prev_regno;
+ list->num_regs = nb_regs;
for (i = 1; i < nb_regs; ++i)
{
- uint32_t curr_regno;
+ uint32_t curr_regno, curr_incr;
reginfo >>= 5;
curr_regno = reginfo & 0x1f;
- if (curr_regno != ((prev_regno + incr) & 0x1f))
+ curr_incr = (curr_regno - prev_regno) & 0x1f;
+ if (curr_incr == 0)
+ return false;
+ else if (i == 1)
+ incr = curr_incr;
+ else if (curr_incr != incr)
return false;
prev_regno = curr_regno;
}
+ list->stride = incr;
return true;
}
goto failure;
info->reglist.first_regno = reg->number;
info->reglist.num_regs = 1;
+ info->reglist.stride = 1;
}
else
{
if (val == PARSE_FAIL)
goto failure;
- if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+ if (! reg_list_valid_p (val, &info->reglist))
{
set_fatal_syntax_error (_("invalid register list"));
goto failure;
(_("expected element type rather than vector type"));
goto failure;
}
-
- info->reglist.first_regno = (val >> 2) & 0x1f;
- info->reglist.num_regs = (val & 0x3) + 1;
}
if (operands[i] == AARCH64_OPND_LEt)
{
[^:]*:80: Error: immediate value out of range 0 to 15 at operand 1 -- `dmb #16'
[^:]*:81: Error: immediate value out of range 0 to 31 at operand 2 -- `tbz w0,#40,0x17c'
[^:]*:82: Error: expected a list of 2 registers at operand 1 -- `st2 \{v4.2d,v5.2d,v6.2d\},\[x3\]'
-[^:]*:83: Error: invalid register list at operand 1 -- `ld2 \{v1.4h,v0.4h\},\[x1\]'
+[^:]*:83: Error: the register list must have a stride of 1 at operand 1 -- `ld2 \{v1.4h,v0.4h\},\[x1\]'
[^:]*:84: Error: the specified option is not accepted in ISB at operand 1 -- `isb osh'
[^:]*:85: Error: invalid address at operand 2 -- `st2 \{v4.2d,v5.2d,v6.2d\},\\\[x3\\\]'
[^:]*:86: Error: immediate value must be a multiple of 4 at operand 3 -- `ldnp w7,w15,\[x3,#3\]'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `eortb z0\.s,z32\.s,z0\.s'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `eortb z0\.s,z0\.s,z32\.s'
[^ :]+:[0-9]+: Error: syntax error in register list at operand 2 -- `ext z0\.b,{,},#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z0\.b,z2\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z0\.b,z2\.b},#0'
[^ :]+:[0-9]+: Error: operand mismatch -- `ext z0\.h,{z0\.b,z1\.b},#0'
[^ :]+:[0-9]+: Info: did you mean this\?
[^ :]+:[0-9]+: Info: ext z0\.b, {z0\.b, z1\.b}, #0
[^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `ext z0\.b,{z0\.b,z1\.b,z2\.b},#0'
[^ :]+:[0-9]+: Error: expected a list of 2 registers at operand 2 -- `ext z0\.b,{z0\.b},#0'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `ext z0\.b,z0\.b,#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z31\.b,z1\.b},#0'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `ext z0\.b,{z0\.b,z31\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z31\.b,z1\.b},#0'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `ext z0\.b,{z0\.b,z31\.b},#0'
[^ :]+:[0-9]+: Error: immediate value out of range 0 to 255 at operand 3 -- `ext z0\.b,{z0\.b,z1\.b},#256'
[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `ext z32\.b,{z0\.b,z1\.b},#0'
[^ :]+:[0-9]+: Error: operand 2 must be a list of SVE vector registers -- `ext z0\.b,{z31\.b,z32\.b},#0'
[^ :]+:[0-9]+: Info: other valid variant\(s\):
[^ :]+:[0-9]+: Info: smullt z0\.s, z0\.h, z0\.h
[^ :]+:[0-9]+: Info: smullt z0\.d, z0\.s, z0\.s
-[^ :]+:[0-9]+: Error: invalid register list at operand 3 -- `splice z0\.b,p0,{z0\.b,z2\.b}'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 3 -- `splice z0\.b,p0,{z0\.b,z2\.b}'
[^ :]+:[0-9]+: Error: operand mismatch -- `splice z0\.h,p0,{z0\.b,z1\.b}'
[^ :]+:[0-9]+: Info: did you mean this\?
[^ :]+:[0-9]+: Info: splice z0\.b, p0, {z0\.b, z1\.b}
[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 3 -- `splice z0\.b,p0,{z0\.b,z1\.h}'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 1 -- `splice z32\.b,p0,{z0\.b,z1\.b}'
[^ :]+:[0-9]+: Error: p0-p7 expected at operand 2 -- `splice z0\.b,p8,{z0\.b,z1\.b}'
-[^ :]+:[0-9]+: Error: invalid register list at operand 3 -- `splice z0\.b,p0,{z31\.b,z1\.b}'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 3 -- `splice z0\.b,p0,{z31\.b,z1\.b}'
[^ :]+:[0-9]+: Error: operand 3 must be a list of SVE vector registers -- `splice z0\.b,p0,{z31\.b,z32\.b}'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `splice z0\.b,p0,{z32\.b,z1\.b}'
[^ :]+:[0-9]+: Error: expected a register at operand 1 -- `sqabs z32\.b,p0/m,z0\.b'
[^ :]+:[0-9]+: Info: suqadd z0\.d, p0/m, z0\.d, z0\.d
[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `tbl z32\.b,{z0\.b,z1\.b},z0\.b'
[^ :]+:[0-9]+: Error: operand 2 must be a list of SVE vector registers -- `tbl z0\.b,{z31\.b,z32\.b},z0\.b'
-[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `tbl z0\.b,{z31\.b,z1\.b},z0\.b'
+[^ :]+:[0-9]+: Error: the register list must have a stride of 1 at operand 2 -- `tbl z0\.b,{z31\.b,z1\.b},z0\.b'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `tbl z0\.b,{z0\.b,z1\.b},z32\.b'
[^ :]+:[0-9]+: Error: operand mismatch -- `tbl z0\.b,{z0\.b,z1\.b},z0\.h'
[^ :]+:[0-9]+: Info: did you mean this\?
[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 2 -- `tbl z0\.b,{z0\.b,z1\.h},z0\.b'
[^ :]+:[0-9]+: Error: type mismatch in vector register list at operand 2 -- `tbl z0\.b,{z0\.h,z0\.b},z0\.b'
[^ :]+:[0-9]+: Error: invalid register list at operand 2 -- `tbl z0\.h,{z0\.b,z0\.b},z0\.b'
+[^ :]+:[0-9]+: Error: operand mismatch -- `tbl z0\.h,{z0\.b,z1\.b},z0\.b'
+[^ :]+:[0-9]+: Info: did you mean this\?
+[^ :]+:[0-9]+: Info: tbl z0\.b, {z0\.b, z1\.b}, z0\.b
+[^ :]+:[0-9]+: Info: other valid variant\(s\):
+[^ :]+:[0-9]+: Info: tbl z0\.h, {z0\.h, z1\.h}, z0\.h
+[^ :]+:[0-9]+: Info: tbl z0\.s, {z0\.s, z1\.s}, z0\.s
+[^ :]+:[0-9]+: Info: tbl z0\.d, {z0\.d, z1\.d}, z0\.d
[^ :]+:[0-9]+: Error: expected a vector register at operand 1 -- `tbx z32\.h,z0\.b,z0\.b'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 2 -- `tbx z0\.h,z32\.b,z0\.b'
[^ :]+:[0-9]+: Error: expected an SVE vector register at operand 3 -- `tbx z0\.h,z0\.b,z32\.b'
tbl z0.b, { z0.b, z1.h }, z0.b
tbl z0.b, { z0.h, z0.b }, z0.b
tbl z0.h, { z0.b, z0.b }, z0.b
+tbl z0.h, { z0.b, z1.b }, z0.b
tbx z32.h, z0.b, z0.b
tbx z0.h, z32.b, z0.b
unsigned v : 1; /* <HV> horizontal or vertical vector indicator. */
};
+/* Information about a list of registers. */
+struct aarch64_reglist
+{
+ unsigned first_regno : 8;
+ unsigned num_regs : 8;
+ /* The difference between the nth and the n+1th register. */
+ unsigned stride : 8;
+ /* 1 if it is a list of reg element. */
+ unsigned has_index : 1;
+ /* Lane index; valid only when has_index is 1. */
+ int64_t index;
+} reglist;
+
/* Structure representing an operand. */
struct aarch64_opnd_info
int64_t index;
} reglane;
/* e.g. LVn. */
- struct
- {
- unsigned first_regno : 5;
- unsigned num_regs : 3;
- /* 1 if it is a list of reg element. */
- unsigned has_index : 1;
- /* Lane index; valid only when has_index is 1. */
- int64_t index;
- } reglist;
+ struct aarch64_reglist reglist;
/* e.g. immediate or pc relative address offset. */
struct
{
The following errors are only reported against an asm string that is
syntactically valid and that has valid operand qualifiers.
- AARCH64_OPDE_REG_LIST
- Error about the register list operand having an unexpected number of
+ AARCH64_OPDE_REG_LIST_LENGTH
+ Error about a register list operand having an unexpected number of
registers. This error is low severity because there might be another
opcode entry that supports the given number of registers.
+ AARCH64_OPDE_REG_LIST_STRIDE
+ Error about a register list operand having the correct number
+ (and type) of registers, but an unexpected stride. This error is
+ more severe than AARCH64_OPDE_REG_LIST_LENGTH because it implies
+ that the length is known to be correct. However, it is lower than
+ many other errors, since some instructions have forms that share
+ the same number of registers but have different strides.
+
AARCH64_OPDE_UNTIED_IMMS
The asm failed to use the same immediate for a destination operand
and a tied source operand.
AARCH64_OPDE_SYNTAX_ERROR,
AARCH64_OPDE_FATAL_SYNTAX_ERROR,
AARCH64_OPDE_INVALID_VARIANT,
- AARCH64_OPDE_REG_LIST,
+ AARCH64_OPDE_REG_LIST_LENGTH,
+ AARCH64_OPDE_REG_LIST_STRIDE,
AARCH64_OPDE_UNTIED_IMMS,
AARCH64_OPDE_UNTIED_OPERAND,
AARCH64_OPDE_OUT_OF_RANGE,
info->reglist.first_regno = extract_field (self->fields[0], code, 0);
/* len */
info->reglist.num_regs = extract_field (FLD_len, code, 0) + 1;
+ info->reglist.stride = 1;
return true;
}
if (expected_num != data[value].num_elements || data[value].is_reserved)
return false;
info->reglist.num_regs = data[value].num_regs;
+ info->reglist.stride = 1;
return true;
}
if (info->reglist.num_regs == 1 && value == (aarch64_insn) 1)
info->reglist.num_regs = 2;
+ info->reglist.stride = 1;
return true;
}
info->reglist.has_index = 1;
info->reglist.num_regs = 0;
+ info->reglist.stride = 1;
/* Number of registers is equal to the number of elements in
each structure to be loaded/stored. */
info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
{
info->reglist.first_regno = extract_field (self->fields[0], code, 0);
info->reglist.num_regs = get_opcode_dependent_value (inst->opcode);
+ info->reglist.stride = 1;
return true;
}
}
static inline void
-set_reg_list_error (aarch64_operand_error *mismatch_detail, int idx,
- int expected_num)
+set_reg_list_length_error (aarch64_operand_error *mismatch_detail, int idx,
+ int expected_num)
{
if (mismatch_detail == NULL)
return;
- set_error (mismatch_detail, AARCH64_OPDE_REG_LIST, idx, NULL);
+ set_error (mismatch_detail, AARCH64_OPDE_REG_LIST_LENGTH, idx, NULL);
+ mismatch_detail->data[0].i = 1 << expected_num;
+}
+
+static inline void
+set_reg_list_stride_error (aarch64_operand_error *mismatch_detail, int idx,
+ int expected_num)
+{
+ if (mismatch_detail == NULL)
+ return;
+ set_error (mismatch_detail, AARCH64_OPDE_REG_LIST_STRIDE, idx, NULL);
mismatch_detail->data[0].i = 1 << expected_num;
}
return true;
}
+/* Check that register list operand OPND has NUM_REGS registers and a
+ register stride of STRIDE. */
+
+static bool
+check_reglist (const aarch64_opnd_info *opnd,
+ aarch64_operand_error *mismatch_detail, int idx,
+ int num_regs, int stride)
+{
+ if (opnd->reglist.num_regs != num_regs)
+ {
+ set_reg_list_length_error (mismatch_detail, idx, num_regs);
+ return false;
+ }
+ if (opnd->reglist.stride != stride)
+ {
+ set_reg_list_stride_error (mismatch_detail, idx, stride);
+ return false;
+ }
+ return true;
+}
+
/* Check that indexed ZA operand OPND has:
- a selection register in the range [MIN_WREG, MIN_WREG + 3]
case AARCH64_OPND_CLASS_SVE_REGLIST:
num = get_opcode_dependent_value (opcode);
- if (opnd->reglist.num_regs != num)
- {
- set_reg_list_error (mismatch_detail, idx, num);
- return 0;
- }
+ if (!check_reglist (opnd, mismatch_detail, idx, num, 1))
+ return 0;
break;
case AARCH64_OPND_CLASS_ZA_ACCESS:
assert (num >= 1 && num <= 4);
/* Unless LD1/ST1, the number of registers should be equal to that
of the structure elements. */
- if (num != 1 && opnd->reglist.num_regs != num)
- {
- set_reg_list_error (mismatch_detail, idx, num);
- return 0;
- }
+ if (num != 1 && !check_reglist (opnd, mismatch_detail, idx, num, 1))
+ return 0;
break;
case AARCH64_OPND_LVt_AL:
case AARCH64_OPND_LEt:
assert (num >= 1 && num <= 4);
/* The number of registers should be equal to that of the structure
elements. */
- if (opnd->reglist.num_regs != num)
- {
- set_reg_list_error (mismatch_detail, idx, num);
- return 0;
- }
+ if (!check_reglist (opnd, mismatch_detail, idx, num, 1))
+ return 0;
break;
default:
break;
}
+ if (opnd->reglist.stride != 1)
+ {
+ set_reg_list_stride_error (mismatch_detail, idx, 1);
+ return 0;
+ }
break;
case AARCH64_OPND_CLASS_IMMEDIATE:
const char *prefix, struct aarch64_styler *styler)
{
const int num_regs = opnd->reglist.num_regs;
+ const int stride = opnd->reglist.stride;
const int first_reg = opnd->reglist.first_regno;
- const int last_reg = (first_reg + num_regs - 1) & 0x1f;
+ const int last_reg = (first_reg + (num_regs - 1) * stride) & 0x1f;
const char *qlf_name = aarch64_get_qualifier_name (opnd->qualifier);
char tb[16]; /* Temporary buffer. */
/* The hyphenated form is preferred for disassembly if there are
more than two registers in the list, and the register numbers
are monotonically increasing in increments of one. */
- if (num_regs > 2 && last_reg > first_reg)
+ if (stride == 1 && num_regs > 2 && last_reg > first_reg)
snprintf (buf, size, "{%s-%s}%s",
style_reg (styler, "%s%d.%s", prefix, first_reg, qlf_name),
style_reg (styler, "%s%d.%s", prefix, last_reg, qlf_name), tb);
else
{
const int reg0 = first_reg;
- const int reg1 = (first_reg + 1) & 0x1f;
- const int reg2 = (first_reg + 2) & 0x1f;
- const int reg3 = (first_reg + 3) & 0x1f;
+ const int reg1 = (first_reg + stride) & 0x1f;
+ const int reg2 = (first_reg + stride * 2) & 0x1f;
+ const int reg3 = (first_reg + stride * 3) & 0x1f;
switch (num_regs)
{