aboutsummaryrefslogtreecommitdiff
path: root/gas/config/tc-aarch64.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/config/tc-aarch64.c')
-rw-r--r--gas/config/tc-aarch64.c161
1 files changed, 130 insertions, 31 deletions
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 8335230..be88d29 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -87,8 +87,9 @@ enum vector_el_type
};
/* Bits for DEFINED field in vector_type_el. */
-#define NTA_HASTYPE 1
-#define NTA_HASINDEX 2
+#define NTA_HASTYPE 1
+#define NTA_HASINDEX 2
+#define NTA_HASVARWIDTH 4
struct vector_type_el
{
@@ -265,6 +266,8 @@ struct reloc_entry
BASIC_REG_TYPE(FP_Q) /* q[0-31] */ \
BASIC_REG_TYPE(CN) /* c[0-7] */ \
BASIC_REG_TYPE(VN) /* v[0-31] */ \
+ BASIC_REG_TYPE(ZN) /* z[0-31] */ \
+ BASIC_REG_TYPE(PN) /* p[0-15] */ \
/* Typecheck: any 64-bit int reg (inc SP exc XZR). */ \
MULTI_REG_TYPE(R64_SP, REG_TYPE(R_64) | REG_TYPE(SP_64)) \
/* Typecheck: x[0-30], w[0-30] or [xw]zr. */ \
@@ -393,6 +396,12 @@ get_reg_expected_msg (aarch64_reg_type reg_type)
case REG_TYPE_VN: /* any V reg */
msg = N_("vector register expected");
break;
+ case REG_TYPE_ZN:
+ msg = N_("SVE vector register expected");
+ break;
+ case REG_TYPE_PN:
+ msg = N_("SVE predicate register expected");
+ break;
default:
as_fatal (_("invalid register type %d"), reg_type);
}
@@ -724,15 +733,16 @@ aarch64_reg_parse_32_64 (char **ccp, aarch64_opnd_qualifier_t *qualifier)
return reg;
}
-/* Parse the qualifier of a SIMD vector register or a SIMD vector element.
- Fill in *PARSED_TYPE and return TRUE if the parsing succeeds;
- otherwise return FALSE.
+/* Parse the qualifier of a vector register or vector element of type
+ REG_TYPE. Fill in *PARSED_TYPE and return TRUE if the parsing
+ succeeds; otherwise return FALSE.
Accept only one occurrence of:
8b 16b 2h 4h 8h 2s 4s 1d 2d
b h s d q */
static bfd_boolean
-parse_vector_type_for_operand (struct vector_type_el *parsed_type, char **str)
+parse_vector_type_for_operand (aarch64_reg_type reg_type,
+ struct vector_type_el *parsed_type, char **str)
{
char *ptr = *str;
unsigned width;
@@ -742,7 +752,7 @@ parse_vector_type_for_operand (struct vector_type_el *parsed_type, char **str)
/* skip '.' */
ptr++;
- if (!ISDIGIT (*ptr))
+ if (reg_type == REG_TYPE_ZN || reg_type == REG_TYPE_PN || !ISDIGIT (*ptr))
{
width = 0;
goto elt_size;
@@ -849,15 +859,23 @@ parse_typed_reg (char **ccp, aarch64_reg_type type, aarch64_reg_type *rtype,
}
type = reg->type;
- if (type == REG_TYPE_VN && *str == '.')
+ if ((type == REG_TYPE_VN || type == REG_TYPE_ZN || type == REG_TYPE_PN)
+ && *str == '.')
{
- if (!parse_vector_type_for_operand (&parsetype, &str))
+ if (!parse_vector_type_for_operand (type, &parsetype, &str))
return PARSE_FAIL;
/* Register if of the form Vn.[bhsdq]. */
is_typed_vecreg = TRUE;
- if (parsetype.width == 0)
+ if (type == REG_TYPE_ZN || type == REG_TYPE_PN)
+ {
+ /* The width is always variable; we don't allow an integer width
+ to be specified. */
+ gas_assert (parsetype.width == 0);
+ atype.defined |= NTA_HASVARWIDTH | NTA_HASTYPE;
+ }
+ else if (parsetype.width == 0)
/* Expect index. In the new scheme we cannot have
Vn.[bhsdq] represent a scalar. Therefore any
Vn.[bhsdq] should have an index following it.
@@ -1034,7 +1052,7 @@ parse_vector_reg_list (char **ccp, aarch64_reg_type type,
continue;
}
/* reject [bhsd]n */
- if (typeinfo.defined == 0)
+ if (type == REG_TYPE_VN && typeinfo.defined == 0)
{
set_first_syntax_error (_("invalid scalar register in list"));
error = TRUE;
@@ -4639,7 +4657,7 @@ vectype_to_qualifier (const struct vector_type_el *vectype)
gas_assert (vectype->type >= NT_b && vectype->type <= NT_q);
- if (vectype->defined & NTA_HASINDEX)
+ if (vectype->defined & (NTA_HASINDEX | NTA_HASVARWIDTH))
/* Vector element register. */
return AARCH64_OPND_QLF_S_B + vectype->type;
else
@@ -4979,6 +4997,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
struct vector_type_el vectype;
aarch64_opnd_qualifier_t qualifier;
aarch64_opnd_info *info = &inst.base.operands[i];
+ aarch64_reg_type reg_type;
DEBUG_TRACE ("parse operand %d", i);
@@ -5061,22 +5080,54 @@ parse_operands (char *str, const aarch64_opcode *opcode)
info->qualifier = AARCH64_OPND_QLF_S_B + (rtype - REG_TYPE_FP_B);
break;
+ case AARCH64_OPND_SVE_Pd:
+ case AARCH64_OPND_SVE_Pg3:
+ case AARCH64_OPND_SVE_Pg4_5:
+ case AARCH64_OPND_SVE_Pg4_10:
+ case AARCH64_OPND_SVE_Pg4_16:
+ case AARCH64_OPND_SVE_Pm:
+ case AARCH64_OPND_SVE_Pn:
+ case AARCH64_OPND_SVE_Pt:
+ reg_type = REG_TYPE_PN;
+ goto vector_reg;
+
+ case AARCH64_OPND_SVE_Za_5:
+ case AARCH64_OPND_SVE_Za_16:
+ case AARCH64_OPND_SVE_Zd:
+ case AARCH64_OPND_SVE_Zm_5:
+ case AARCH64_OPND_SVE_Zm_16:
+ case AARCH64_OPND_SVE_Zn:
+ case AARCH64_OPND_SVE_Zt:
+ reg_type = REG_TYPE_ZN;
+ goto vector_reg;
+
case AARCH64_OPND_Vd:
case AARCH64_OPND_Vn:
case AARCH64_OPND_Vm:
- val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
+ reg_type = REG_TYPE_VN;
+ vector_reg:
+ val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
if (val == PARSE_FAIL)
{
- first_error (_(get_reg_expected_msg (REG_TYPE_VN)));
+ first_error (_(get_reg_expected_msg (reg_type)));
goto failure;
}
if (vectype.defined & NTA_HASINDEX)
goto failure;
info->reg.regno = val;
- info->qualifier = vectype_to_qualifier (&vectype);
- if (info->qualifier == AARCH64_OPND_QLF_NIL)
- goto failure;
+ if ((reg_type == REG_TYPE_PN || reg_type == REG_TYPE_ZN)
+ && vectype.type == NT_invtype)
+ /* Unqualified Pn and Zn registers are allowed in certain
+ contexts. Rely on F_STRICT qualifier checking to catch
+ invalid uses. */
+ info->qualifier = AARCH64_OPND_QLF_NIL;
+ else
+ {
+ info->qualifier = vectype_to_qualifier (&vectype);
+ if (info->qualifier == AARCH64_OPND_QLF_NIL)
+ goto failure;
+ }
break;
case AARCH64_OPND_VdD1:
@@ -5101,13 +5152,19 @@ parse_operands (char *str, const aarch64_opcode *opcode)
info->qualifier = AARCH64_OPND_QLF_S_D;
break;
+ case AARCH64_OPND_SVE_Zn_INDEX:
+ reg_type = REG_TYPE_ZN;
+ goto vector_reg_index;
+
case AARCH64_OPND_Ed:
case AARCH64_OPND_En:
case AARCH64_OPND_Em:
- val = aarch64_reg_parse (&str, REG_TYPE_VN, NULL, &vectype);
+ reg_type = REG_TYPE_VN;
+ vector_reg_index:
+ val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
if (val == PARSE_FAIL)
{
- first_error (_(get_reg_expected_msg (REG_TYPE_VN)));
+ first_error (_(get_reg_expected_msg (reg_type)));
goto failure;
}
if (vectype.type == NT_invtype || !(vectype.defined & NTA_HASINDEX))
@@ -5120,20 +5177,43 @@ parse_operands (char *str, const aarch64_opcode *opcode)
goto failure;
break;
+ case AARCH64_OPND_SVE_ZnxN:
+ case AARCH64_OPND_SVE_ZtxN:
+ reg_type = REG_TYPE_ZN;
+ goto vector_reg_list;
+
case AARCH64_OPND_LVn:
case AARCH64_OPND_LVt:
case AARCH64_OPND_LVt_AL:
case AARCH64_OPND_LEt:
- if ((val = parse_vector_reg_list (&str, REG_TYPE_VN,
- &vectype)) == PARSE_FAIL)
- goto failure;
- if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+ reg_type = REG_TYPE_VN;
+ vector_reg_list:
+ if (reg_type == REG_TYPE_ZN
+ && get_opcode_dependent_value (opcode) == 1
+ && *str != '{')
{
- set_fatal_syntax_error (_("invalid register list"));
- goto failure;
+ val = aarch64_reg_parse (&str, reg_type, NULL, &vectype);
+ if (val == PARSE_FAIL)
+ {
+ first_error (_(get_reg_expected_msg (reg_type)));
+ goto failure;
+ }
+ info->reglist.first_regno = val;
+ info->reglist.num_regs = 1;
+ }
+ else
+ {
+ val = parse_vector_reg_list (&str, reg_type, &vectype);
+ if (val == PARSE_FAIL)
+ goto failure;
+ if (! reg_list_valid_p (val, /* accept_alternate */ 0))
+ {
+ set_fatal_syntax_error (_("invalid register list"));
+ goto failure;
+ }
+ info->reglist.first_regno = (val >> 2) & 0x1f;
+ info->reglist.num_regs = (val & 0x3) + 1;
}
- info->reglist.first_regno = (val >> 2) & 0x1f;
- info->reglist.num_regs = (val & 0x3) + 1;
if (operands[i] == AARCH64_OPND_LEt)
{
if (!(vectype.defined & NTA_HASINDEX))
@@ -5141,8 +5221,17 @@ parse_operands (char *str, const aarch64_opcode *opcode)
info->reglist.has_index = 1;
info->reglist.index = vectype.index;
}
- else if (!(vectype.defined & NTA_HASTYPE))
- goto failure;
+ else
+ {
+ if (vectype.defined & NTA_HASINDEX)
+ goto failure;
+ if (!(vectype.defined & NTA_HASTYPE))
+ {
+ if (reg_type == REG_TYPE_ZN)
+ set_fatal_syntax_error (_("missing type suffix"));
+ goto failure;
+ }
+ }
info->qualifier = vectype_to_qualifier (&vectype);
if (info->qualifier == AARCH64_OPND_QLF_NIL)
goto failure;
@@ -6157,11 +6246,13 @@ aarch64_canonicalize_symbol_name (char *name)
#define REGDEF(s,n,t) { #s, n, REG_TYPE_##t, TRUE }
#define REGNUM(p,n,t) REGDEF(p##n, n, t)
-#define REGSET31(p,t) \
+#define REGSET16(p,t) \
REGNUM(p, 0,t), REGNUM(p, 1,t), REGNUM(p, 2,t), REGNUM(p, 3,t), \
REGNUM(p, 4,t), REGNUM(p, 5,t), REGNUM(p, 6,t), REGNUM(p, 7,t), \
REGNUM(p, 8,t), REGNUM(p, 9,t), REGNUM(p,10,t), REGNUM(p,11,t), \
- REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t), \
+ REGNUM(p,12,t), REGNUM(p,13,t), REGNUM(p,14,t), REGNUM(p,15,t)
+#define REGSET31(p,t) \
+ REGSET16(p, t), \
REGNUM(p,16,t), REGNUM(p,17,t), REGNUM(p,18,t), REGNUM(p,19,t), \
REGNUM(p,20,t), REGNUM(p,21,t), REGNUM(p,22,t), REGNUM(p,23,t), \
REGNUM(p,24,t), REGNUM(p,25,t), REGNUM(p,26,t), REGNUM(p,27,t), \
@@ -6201,10 +6292,18 @@ static const reg_entry reg_names[] = {
/* FP/SIMD registers. */
REGSET (v, VN), REGSET (V, VN),
+
+ /* SVE vector registers. */
+ REGSET (z, ZN), REGSET (Z, ZN),
+
+ /* SVE predicate registers. */
+ REGSET16 (p, PN), REGSET16 (P, PN)
};
#undef REGDEF
#undef REGNUM
+#undef REGSET16
+#undef REGSET31
#undef REGSET
#define N 1