{ 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]. */
+ { 22, 2 }, /* SVE_tszh: triangular size select high, bits [23,22]. */
};
enum aarch64_operand_class
}
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)
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
return int_reg[has_zr][1][regno];
}
+/* Get the name of the integer offset register in OPND, using the shift type
+ to decide whether it's a word or doubleword. */
+
+static inline const char *
+get_offset_int_reg_name (const aarch64_opnd_info *opnd)
+{
+ switch (opnd->shifter.kind)
+ {
+ case AARCH64_MOD_UXTW:
+ case AARCH64_MOD_SXTW:
+ return get_int_reg_name (opnd->addr.offset.regno, AARCH64_OPND_QLF_W, 0);
+
+ case AARCH64_MOD_LSL:
+ case AARCH64_MOD_SXTX:
+ return get_int_reg_name (opnd->addr.offset.regno, AARCH64_OPND_QLF_X, 0);
+
+ default:
+ abort ();
+ }
+}
+
/* Types for expanding an encoded 8-bit value to a floating-point value. */
typedef union
}
}
+/* Print the register+immediate address in OPND to BUF, which has SIZE
+ characters. BASE is the name of the base register. */
+
+static void
+print_immediate_offset_address (char *buf, size_t size,
+ const aarch64_opnd_info *opnd,
+ const char *base)
+{
+ if (opnd->addr.writeback)
+ {
+ if (opnd->addr.preind)
+ snprintf (buf, size, "[%s,#%d]!", base, opnd->addr.offset.imm);
+ else
+ snprintf (buf, size, "[%s],#%d", base, opnd->addr.offset.imm);
+ }
+ else
+ {
+ if (opnd->addr.offset.imm)
+ snprintf (buf, size, "[%s,#%d]", base, opnd->addr.offset.imm);
+ else
+ snprintf (buf, size, "[%s]", base);
+ }
+}
+
/* Produce the string representation of the register offset address operand
- *OPND in the buffer pointed by BUF of size SIZE. */
+ *OPND in the buffer pointed by BUF of size SIZE. BASE and OFFSET are
+ the names of the base and offset registers. */
static void
print_register_offset_address (char *buf, size_t size,
- const aarch64_opnd_info *opnd)
+ const aarch64_opnd_info *opnd,
+ const char *base, const char *offset)
{
char tb[16]; /* Temporary buffer. */
- bfd_boolean lsl_p = FALSE; /* Is LSL shift operator? */
- bfd_boolean wm_p = FALSE; /* Should Rm be Wm? */
bfd_boolean print_extend_p = TRUE;
bfd_boolean print_amount_p = TRUE;
const char *shift_name = aarch64_operand_modifiers[opnd->shifter.kind].name;
- switch (opnd->shifter.kind)
- {
- case AARCH64_MOD_UXTW: wm_p = TRUE; break;
- case AARCH64_MOD_LSL : lsl_p = TRUE; break;
- case AARCH64_MOD_SXTW: wm_p = TRUE; break;
- case AARCH64_MOD_SXTX: break;
- default: assert (0);
- }
-
if (!opnd->shifter.amount && (opnd->qualifier != AARCH64_OPND_QLF_S_B
|| !opnd->shifter.amount_present))
{
print_amount_p = FALSE;
/* Likewise, no need to print the shift operator LSL in such a
situation. */
- if (lsl_p)
+ if (opnd->shifter.kind == AARCH64_MOD_LSL)
print_extend_p = FALSE;
}
else
tb[0] = '\0';
- snprintf (buf, size, "[%s,%s%s]",
- get_64bit_int_reg_name (opnd->addr.base_regno, 1),
- get_int_reg_name (opnd->addr.offset.regno,
- wm_p ? AARCH64_OPND_QLF_W : AARCH64_OPND_QLF_X,
- 0 /* sp_reg_p */),
- tb);
+ snprintf (buf, size, "[%s,%s%s]", base, offset, tb);
}
/* Generate the string representation of the operand OPNDS[IDX] for OPCODE
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
+ 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);
break;
case AARCH64_OPND_ADDR_REGOFF:
- print_register_offset_address (buf, size, opnd);
+ print_register_offset_address
+ (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1),
+ get_offset_int_reg_name (opnd));
break;
case AARCH64_OPND_ADDR_SIMM7:
case AARCH64_OPND_ADDR_SIMM9:
case AARCH64_OPND_ADDR_SIMM9_2:
- name = get_64bit_int_reg_name (opnd->addr.base_regno, 1);
- if (opnd->addr.writeback)
- {
- if (opnd->addr.preind)
- snprintf (buf, size, "[%s,#%d]!", name, opnd->addr.offset.imm);
- else
- snprintf (buf, size, "[%s],#%d", name, opnd->addr.offset.imm);
- }
- else
- {
- if (opnd->addr.offset.imm)
- snprintf (buf, size, "[%s,#%d]", name, opnd->addr.offset.imm);
- else
- snprintf (buf, size, "[%s]", name);
- }
+ print_immediate_offset_address
+ (buf, size, opnd, get_64bit_int_reg_name (opnd->addr.base_regno, 1));
break;
case AARCH64_OPND_ADDR_UIMM12: