summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:54:53 +0100
committerRichard Sandiford <richard.sandiford@arm.com>2016-09-21 16:54:53 +0100
commit245d2e3fe8d9ff35c65ed1329609fb7e59034877 (patch)
treeb35423d664e70149dadbee4992d77506f8a8787c
parentd50c751e00b5336b4604b92271ab84615fdb0d27 (diff)
downloadbinutils-gdb-245d2e3fe8d9ff35c65ed1329609fb7e59034877.tar.gz
[AArch64][SVE 23/32] Add SVE pattern and prfop operands
The SVE instructions have two enumerated operands: one to select a vector pattern and another to select a prefetch operation. The latter is a cut-down version of the base AArch64 prefetch operation. Both types of operand can also be specified as raw enum values such as #31. Reserved values can only be specified this way. If it hadn't been for the pattern operand, I would have been tempted to use the existing parsing for prefetch operations and add extra checks for SVE. However, since the patterns needed new enum parsing code anyway, it seeemed cleaner to reuse it for the prefetches too. Because of the small number of enum values, I don't think we'd gain anything by using hash tables. include/ * opcode/aarch64.h (AARCH64_OPND_SVE_PATTERN): New aarch64_opnd. (AARCH64_OPND_SVE_PRFOP): Likewise. (aarch64_sve_pattern_array): Declare. (aarch64_sve_prfop_array): Likewise. opcodes/ * aarch64-tbl.h (AARCH64_OPERANDS): Add entries for AARCH64_OPND_SVE_PATTERN and AARCH64_OPND_SVE_PRFOP. * aarch64-opc.h (FLD_SVE_pattern): New aarch64_field_kind. (FLD_SVE_prfop): Likewise. * aarch64-opc.c: Include libiberty.h. (aarch64_sve_pattern_array): New variable. (aarch64_sve_prfop_array): Likewise. (fields): Add entries for FLD_SVE_pattern and FLD_SVE_prfop. (aarch64_print_operand): Handle AARCH64_OPND_SVE_PATTERN and AARCH64_OPND_SVE_PRFOP. * aarch64-asm-2.c: Regenerate. * aarch64-dis-2.c: Likewise. * aarch64-opc-2.c: Likewise. gas/ * config/tc-aarch64.c (parse_enum_string): New function. (po_enum_or_fail): New macro. (parse_operands): Handle AARCH64_OPND_SVE_PATTERN and AARCH64_OPND_SVE_PRFOP.
-rw-r--r--gas/ChangeLog7
-rw-r--r--gas/config/tc-aarch64.c64
-rw-r--r--include/ChangeLog7
-rw-r--r--include/opcode/aarch64.h5
-rw-r--r--opcodes/ChangeLog16
-rw-r--r--opcodes/aarch64-asm-2.c12
-rw-r--r--opcodes/aarch64-dis-2.c12
-rw-r--r--opcodes/aarch64-opc-2.c2
-rw-r--r--opcodes/aarch64-opc.c90
-rw-r--r--opcodes/aarch64-opc.h2
-rw-r--r--opcodes/aarch64-tbl.h4
11 files changed, 210 insertions, 11 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 589b2cfe152..d532bb1b450 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,5 +1,12 @@
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
+ AARCH64_OPND_SVE_PRFOP.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* config/tc-aarch64.c (vector_el_type): Add NT_zero and NT_merge.
(parse_vector_type_for_operand): Assert that the skipped character
is a '.'.
diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index f87726244e0..7a3a39d2863 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -3584,6 +3584,52 @@ parse_adrp (char **str)
/* Miscellaneous. */
+/* Parse a symbolic operand such as "pow2" at *STR. ARRAY is an array
+ of SIZE tokens in which index I gives the token for field value I,
+ or is null if field value I is invalid. REG_TYPE says which register
+ names should be treated as registers rather than as symbolic immediates.
+
+ Return true on success, moving *STR past the operand and storing the
+ field value in *VAL. */
+
+static int
+parse_enum_string (char **str, int64_t *val, const char *const *array,
+ size_t size, aarch64_reg_type reg_type)
+{
+ expressionS exp;
+ char *p, *q;
+ size_t i;
+
+ /* Match C-like tokens. */
+ p = q = *str;
+ while (ISALNUM (*q))
+ q++;
+
+ for (i = 0; i < size; ++i)
+ if (array[i]
+ && strncasecmp (array[i], p, q - p) == 0
+ && array[i][q - p] == 0)
+ {
+ *val = i;
+ *str = q;
+ return TRUE;
+ }
+
+ if (!parse_immediate_expression (&p, &exp, reg_type))
+ return FALSE;
+
+ if (exp.X_op == O_constant
+ && (uint64_t) exp.X_add_number < size)
+ {
+ *val = exp.X_add_number;
+ *str = p;
+ return TRUE;
+ }
+
+ /* Use the default error for this operand. */
+ return FALSE;
+}
+
/* Parse an option for a preload instruction. Returns the encoding for the
option, or PARSE_FAIL. */
@@ -3793,6 +3839,12 @@ parse_sys_ins_reg (char **str, struct hash_control *sys_ins_regs)
} \
} while (0)
+#define po_enum_or_fail(array) do { \
+ if (!parse_enum_string (&str, &val, array, \
+ ARRAY_SIZE (array), imm_reg_type)) \
+ goto failure; \
+ } while (0)
+
#define po_misc_or_fail(expr) do { \
if (!expr) \
goto failure; \
@@ -4806,6 +4858,8 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
case AARCH64_OPND_WIDTH:
case AARCH64_OPND_UIMM7:
case AARCH64_OPND_NZCV:
+ case AARCH64_OPND_SVE_PATTERN:
+ case AARCH64_OPND_SVE_PRFOP:
operand->imm.value = default_value;
break;
@@ -5314,6 +5368,16 @@ parse_operands (char *str, const aarch64_opcode *opcode)
info->imm.value = val;
break;
+ case AARCH64_OPND_SVE_PATTERN:
+ po_enum_or_fail (aarch64_sve_pattern_array);
+ info->imm.value = val;
+ break;
+
+ case AARCH64_OPND_SVE_PRFOP:
+ po_enum_or_fail (aarch64_sve_prfop_array);
+ info->imm.value = val;
+ break;
+
case AARCH64_OPND_UIMM7:
po_imm_or_fail (0, 127);
info->imm.value = val;
diff --git a/include/ChangeLog b/include/ChangeLog
index 175d1d54333..96da0a3fac9 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,5 +1,12 @@
2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+ * opcode/aarch64.h (AARCH64_OPND_SVE_PATTERN): New aarch64_opnd.
+ (AARCH64_OPND_SVE_PRFOP): Likewise.
+ (aarch64_sve_pattern_array): Declare.
+ (aarch64_sve_prfop_array): Likewise.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* opcode/aarch64.h (AARCH64_OPND_QLF_P_Z): New aarch64_opnd_qualifier.
(AARCH64_OPND_QLF_P_M): Likewise.
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 8eae0b941c9..dd191cf805f 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -244,6 +244,8 @@ enum aarch64_opnd
AARCH64_OPND_PRFOP, /* Prefetch operation. */
AARCH64_OPND_BARRIER_PSB, /* Barrier operand for PSB. */
+ AARCH64_OPND_SVE_PATTERN, /* SVE vector pattern enumeration. */
+ AARCH64_OPND_SVE_PRFOP, /* SVE prefetch operation. */
AARCH64_OPND_SVE_Pd, /* SVE p0-p15 in Pd. */
AARCH64_OPND_SVE_Pg3, /* SVE p0-p7 in Pg. */
AARCH64_OPND_SVE_Pg4_5, /* SVE p0-p15 in Pg, bits [8,5]. */
@@ -1037,6 +1039,9 @@ aarch64_verbose (const char *, ...) __attribute__ ((format (printf, 1, 2)));
#define DEBUG_TRACE_IF(C, M, ...) ;
#endif /* DEBUG_AARCH64 */
+extern const char *const aarch64_sve_pattern_array[32];
+extern const char *const aarch64_sve_prfop_array[16];
+
#ifdef __cplusplus
}
#endif
diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog
index 5d2ddb14056..a2afc0d77c6 100644
--- a/opcodes/ChangeLog
+++ b/opcodes/ChangeLog
@@ -1,5 +1,21 @@
2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+ * aarch64-tbl.h (AARCH64_OPERANDS): Add entries for
+ AARCH64_OPND_SVE_PATTERN and AARCH64_OPND_SVE_PRFOP.
+ * aarch64-opc.h (FLD_SVE_pattern): New aarch64_field_kind.
+ (FLD_SVE_prfop): Likewise.
+ * aarch64-opc.c: Include libiberty.h.
+ (aarch64_sve_pattern_array): New variable.
+ (aarch64_sve_prfop_array): Likewise.
+ (fields): Add entries for FLD_SVE_pattern and FLD_SVE_prfop.
+ (aarch64_print_operand): Handle AARCH64_OPND_SVE_PATTERN and
+ AARCH64_OPND_SVE_PRFOP.
+ * aarch64-asm-2.c: Regenerate.
+ * aarch64-dis-2.c: Likewise.
+ * aarch64-opc-2.c: Likewise.
+
+2016-09-21 Richard Sandiford <richard.sandiford@arm.com>
+
* aarch64-opc.c (aarch64_opnd_qualifiers): Add entries for
AARCH64_OPND_QLF_P_[ZM].
(aarch64_print_operand): Print /z and /m where appropriate.
diff --git a/opcodes/aarch64-asm-2.c b/opcodes/aarch64-asm-2.c
index 9c797b2ea5a..0a6e476314f 100644
--- a/opcodes/aarch64-asm-2.c
+++ b/opcodes/aarch64-asm-2.c
@@ -480,8 +480,6 @@ aarch64_insert_operand (const aarch64_operand *self,
case 27:
case 35:
case 36:
- case 89:
- case 90:
case 91:
case 92:
case 93:
@@ -494,7 +492,9 @@ aarch64_insert_operand (const aarch64_operand *self,
case 100:
case 101:
case 102:
- case 105:
+ case 103:
+ case 104:
+ case 107:
return aarch64_ins_regno (self, info, code, inst);
case 12:
return aarch64_ins_reg_extended (self, info, code, inst);
@@ -531,6 +531,8 @@ aarch64_insert_operand (const aarch64_operand *self,
case 68:
case 69:
case 70:
+ case 89:
+ case 90:
return aarch64_ins_imm (self, info, code, inst);
case 38:
case 39:
@@ -581,10 +583,10 @@ aarch64_insert_operand (const aarch64_operand *self,
return aarch64_ins_prfop (self, info, code, inst);
case 88:
return aarch64_ins_hint (self, info, code, inst);
- case 103:
+ case 105:
return aarch64_ins_sve_index (self, info, code, inst);
- case 104:
case 106:
+ case 108:
return aarch64_ins_sve_reglist (self, info, code, inst);
default: assert (0); abort ();
}
diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c
index 6ea010b3573..9f936f0b833 100644
--- a/opcodes/aarch64-dis-2.c
+++ b/opcodes/aarch64-dis-2.c
@@ -10426,8 +10426,6 @@ aarch64_extract_operand (const aarch64_operand *self,
case 27:
case 35:
case 36:
- case 89:
- case 90:
case 91:
case 92:
case 93:
@@ -10440,7 +10438,9 @@ aarch64_extract_operand (const aarch64_operand *self,
case 100:
case 101:
case 102:
- case 105:
+ case 103:
+ case 104:
+ case 107:
return aarch64_ext_regno (self, info, code, inst);
case 8:
return aarch64_ext_regrt_sysins (self, info, code, inst);
@@ -10482,6 +10482,8 @@ aarch64_extract_operand (const aarch64_operand *self,
case 68:
case 69:
case 70:
+ case 89:
+ case 90:
return aarch64_ext_imm (self, info, code, inst);
case 38:
case 39:
@@ -10534,10 +10536,10 @@ aarch64_extract_operand (const aarch64_operand *self,
return aarch64_ext_prfop (self, info, code, inst);
case 88:
return aarch64_ext_hint (self, info, code, inst);
- case 103:
+ case 105:
return aarch64_ext_sve_index (self, info, code, inst);
- case 104:
case 106:
+ case 108:
return aarch64_ext_sve_reglist (self, info, code, inst);
default: assert (0); abort ();
}
diff --git a/opcodes/aarch64-opc-2.c b/opcodes/aarch64-opc-2.c
index f8a7079c690..39050532914 100644
--- a/opcodes/aarch64-opc-2.c
+++ b/opcodes/aarch64-opc-2.c
@@ -113,6 +113,8 @@ const struct aarch64_operand aarch64_operands[] =
{AARCH64_OPND_CLASS_SYSTEM, "BARRIER_ISB", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "the ISB option name SY or an optional 4-bit unsigned immediate"},
{AARCH64_OPND_CLASS_SYSTEM, "PRFOP", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "a prefetch operation specifier"},
{AARCH64_OPND_CLASS_SYSTEM, "BARRIER_PSB", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {}, "the PSB option name CSYNC"},
+ {AARCH64_OPND_CLASS_IMMEDIATE, "SVE_PATTERN", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_pattern}, "an enumeration value such as POW2"},
+ {AARCH64_OPND_CLASS_IMMEDIATE, "SVE_PRFOP", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_prfop}, "an enumeration value such as PLDL1KEEP"},
{AARCH64_OPND_CLASS_PRED_REG, "SVE_Pd", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Pd}, "an SVE predicate register"},
{AARCH64_OPND_CLASS_PRED_REG, "SVE_Pg3", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Pg3}, "an SVE predicate register"},
{AARCH64_OPND_CLASS_PRED_REG, "SVE_Pg4_5", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_SVE_Pg4_5}, "an SVE predicate register"},
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 41c058f47aa..934c14db2a3 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -27,6 +27,7 @@
#include <inttypes.h>
#include "opintl.h"
+#include "libiberty.h"
#include "aarch64-opc.h"
@@ -34,6 +35,70 @@
int debug_dump = FALSE;
#endif /* DEBUG_AARCH64 */
+/* The enumeration strings associated with each value of a 5-bit SVE
+ pattern operand. A null entry indicates a reserved meaning. */
+const char *const aarch64_sve_pattern_array[32] = {
+ /* 0-7. */
+ "pow2",
+ "vl1",
+ "vl2",
+ "vl3",
+ "vl4",
+ "vl5",
+ "vl6",
+ "vl7",
+ /* 8-15. */
+ "vl8",
+ "vl16",
+ "vl32",
+ "vl64",
+ "vl128",
+ "vl256",
+ 0,
+ 0,
+ /* 16-23. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ /* 24-31. */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ "mul4",
+ "mul3",
+ "all"
+};
+
+/* The enumeration strings associated with each value of a 4-bit SVE
+ prefetch operand. A null entry indicates a reserved meaning. */
+const char *const aarch64_sve_prfop_array[16] = {
+ /* 0-7. */
+ "pldl1keep",
+ "pldl1strm",
+ "pldl2keep",
+ "pldl2strm",
+ "pldl3keep",
+ "pldl3strm",
+ 0,
+ 0,
+ /* 8-15. */
+ "pstl1keep",
+ "pstl1strm",
+ "pstl2keep",
+ "pstl2strm",
+ "pstl3keep",
+ "pstl3strm",
+ 0,
+ 0
+};
+
/* Helper functions to determine which operand to be used to encode/decode
the size:Q fields for AdvSIMD instructions. */
@@ -214,6 +279,8 @@ 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]. */
+ { 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]. */
};
@@ -2489,7 +2556,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
const char *name = NULL;
const aarch64_opnd_info *opnd = opnds + idx;
enum aarch64_modifier_kind kind;
- uint64_t addr;
+ uint64_t addr, enum_value;
buf[0] = '\0';
if (pcrel_p)
@@ -2681,6 +2748,27 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
snprintf (buf, size, "#%" PRIi64, opnd->imm.value);
break;
+ case AARCH64_OPND_SVE_PATTERN:
+ if (optional_operand_p (opcode, idx)
+ && 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[enum_value])
+ snprintf (buf, size, "%s", aarch64_sve_pattern_array[enum_value]);
+ else
+ snprintf (buf, size, "#%" PRIi64, opnd->imm.value);
+ break;
+
+ case AARCH64_OPND_SVE_PRFOP:
+ enum_value = opnd->imm.value;
+ assert (enum_value < ARRAY_SIZE (aarch64_sve_prfop_array));
+ if (aarch64_sve_prfop_array[enum_value])
+ snprintf (buf, size, "%s", aarch64_sve_prfop_array[enum_value]);
+ else
+ snprintf (buf, size, "#%" PRIi64, opnd->imm.value);
+ break;
+
case AARCH64_OPND_IMM_MOV:
switch (aarch64_get_qualifier_esize (opnds[0].qualifier))
{
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index cc3dbefd631..b54f35edbcf 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -106,6 +106,8 @@ enum aarch64_field_kind
FLD_SVE_Zm_16,
FLD_SVE_Zn,
FLD_SVE_Zt,
+ FLD_SVE_pattern,
+ FLD_SVE_prfop,
FLD_SVE_tszh,
};
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 9dbe0c0ec5d..73415f72222 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -2820,6 +2820,10 @@ struct aarch64_opcode aarch64_opcode_table[] =
"a prefetch operation specifier") \
Y (SYSTEM, hint, "BARRIER_PSB", 0, F (), \
"the PSB option name CSYNC") \
+ Y(IMMEDIATE, imm, "SVE_PATTERN", 0, F(FLD_SVE_pattern), \
+ "an enumeration value such as POW2") \
+ Y(IMMEDIATE, imm, "SVE_PRFOP", 0, F(FLD_SVE_prfop), \
+ "an enumeration value such as PLDL1KEEP") \
Y(PRED_REG, regno, "SVE_Pd", 0, F(FLD_SVE_Pd), \
"an SVE predicate register") \
Y(PRED_REG, regno, "SVE_Pg3", 0, F(FLD_SVE_Pg3), \