#include <inttypes.h>
#include "opintl.h"
+#include "libiberty.h"
#include "aarch64-opc.h"
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. */
{ 31, 1 }, /* b5: in the test bit and branch instructions. */
{ 19, 5 }, /* b40: in the test bit and branch instructions. */
{ 10, 6 }, /* scale: in the fixed-point scalar to fp converting inst. */
+ { 0, 4 }, /* SVE_Pd: p0-p15, bits [3,0]. */
+ { 10, 3 }, /* SVE_Pg3: p0-p7, bits [12,10]. */
+ { 5, 4 }, /* SVE_Pg4_5: p0-p15, bits [8,5]. */
+ { 10, 4 }, /* SVE_Pg4_10: p0-p15, bits [13,10]. */
+ { 16, 4 }, /* SVE_Pg4_16: p0-p15, bits [19,16]. */
+ { 16, 4 }, /* SVE_Pm: p0-p15, bits [19,16]. */
+ { 5, 4 }, /* SVE_Pn: p0-p15, bits [8,5]. */
+ { 0, 4 }, /* SVE_Pt: p0-p15, bits [3,0]. */
+ { 5, 5 }, /* SVE_Za_5: SVE vector register, bits [9,5]. */
+ { 16, 5 }, /* SVE_Za_16: SVE vector register, bits [20,16]. */
+ { 0, 5 }, /* SVE_Zd: SVE vector register. bits [4,0]. */
+ { 5, 5 }, /* SVE_Zm_5: SVE vector register, bits [9,5]. */
+ { 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]. */
};
enum aarch64_operand_class
{"sxth", 0x5},
{"sxtw", 0x6},
{"sxtx", 0x7},
+ {"mul", 0x0},
{NULL, 0},
};
{8, 2, 0x7, "2d", OQK_OPD_VARIANT},
{16, 1, 0x8, "1q", OQK_OPD_VARIANT},
+ {0, 0, 0, "z", OQK_OPD_VARIANT},
+ {0, 0, 0, "m", OQK_OPD_VARIANT},
+
/* Qualifiers constraining the value range.
First 3 fields:
Lower bound, higher bound, unused. */
_("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)
}
break;
+ case AARCH64_OPND_CLASS_SVE_REG:
+ switch (type)
+ {
+ case AARCH64_OPND_SVE_Zn_INDEX:
+ size = aarch64_get_qualifier_esize (opnd->qualifier);
+ if (!value_in_range_p (opnd->reglane.index, 0, 64 / size - 1))
+ {
+ set_elem_idx_out_of_range_error (mismatch_detail, idx,
+ 0, 64 / size - 1);
+ return 0;
+ }
+ break;
+
+ case AARCH64_OPND_SVE_ZnxN:
+ case AARCH64_OPND_SVE_ZtxN:
+ if (opnd->reglist.num_regs != get_opcode_dependent_value (opcode))
+ {
+ set_other_error (mismatch_detail, idx,
+ _("invalid register list"));
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case AARCH64_OPND_CLASS_PRED_REG:
+ if (opnd->reg.regno >= 8
+ && get_operand_fields_width (get_operand_from_code (type)) == 3)
+ {
+ set_other_error (mismatch_detail, idx, _("p0-p7 expected"));
+ return 0;
+ }
+ break;
+
case AARCH64_OPND_CLASS_COND:
if (type == AARCH64_OPND_COND1
&& (opnds[idx].cond->value & 0xe) == 0xe)
}
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;
}
DEBUG_TRACE ("enter");
+ /* Check for cases where a source register needs to be the same as the
+ destination register. Do this before matching qualifiers since if
+ an instruction has both invalid tying and invalid qualifiers,
+ the error about qualifiers would suggest several alternative
+ instructions that also have invalid tying. */
+ i = inst->opcode->tied_operand;
+ if (i > 0 && (inst->operands[0].reg.regno != inst->operands[i].reg.regno))
+ {
+ if (mismatch_detail)
+ {
+ mismatch_detail->kind = AARCH64_OPDE_UNTIED_OPERAND;
+ mismatch_detail->index = i;
+ mismatch_detail->error = NULL;
+ }
+ return 0;
+ }
+
/* Match operands' qualifier.
*INST has already had qualifier establish for some, if not all, of
its operands; we need to find out whether these established
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);
}
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)
}
}
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);
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);
print_register_list (buf, size, opnd, "v");
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:
+ if (opnd->qualifier == AARCH64_OPND_QLF_NIL)
+ snprintf (buf, size, "p%d", opnd->reg.regno);
+ else if (opnd->qualifier == AARCH64_OPND_QLF_P_Z
+ || opnd->qualifier == AARCH64_OPND_QLF_P_M)
+ snprintf (buf, size, "p%d/%s", opnd->reg.regno,
+ aarch64_get_qualifier_name (opnd->qualifier));
+ else
+ snprintf (buf, size, "p%d.%s", opnd->reg.regno,
+ aarch64_get_qualifier_name (opnd->qualifier));
+ break;
+
+ 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:
+ if (opnd->qualifier == AARCH64_OPND_QLF_NIL)
+ snprintf (buf, size, "z%d", opnd->reg.regno);
+ else
+ snprintf (buf, size, "z%d.%s", opnd->reg.regno,
+ aarch64_get_qualifier_name (opnd->qualifier));
+ break;
+
+ case AARCH64_OPND_SVE_ZnxN:
+ case AARCH64_OPND_SVE_ZtxN:
+ print_register_list (buf, size, opnd, "z");
+ break;
+
+ case AARCH64_OPND_SVE_Zn_INDEX:
+ snprintf (buf, size, "z%d.%s[%" PRIi64 "]", opnd->reglane.regno,
+ aarch64_get_qualifier_name (opnd->qualifier),
+ opnd->reglane.index);
+ break;
+
case AARCH64_OPND_Cn:
case AARCH64_OPND_Cm:
snprintf (buf, size, "C%d", opnd->reg.regno);
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_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));
+ 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))
{
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);
|| 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;