aarch64: Add support for xzr register in register pair operands
Analysis of the allowed operand values for `sysp' and `tlbip' reveals a significant departure from the allowed behavior for operand register pairs (hitherto labeled AARCH64_OPND_PAIRREG) observed for other insns in this category. For instructions `casp', `mrrs' and `msrr' the register pair must always start at an even index and the second register in the pair is the index + 1. This precludes the use of xzr as the first register, given it corresponds to register number 31. This is different in the case of `sysp' and `tlbip', however. These allow the use of xzr and, where the first operand in the pair is omitted, this is the default value assigned to it. When this operand is assigned xzr, it is expected that the second operand will likewise take on a value of xzr. These two instructions therefore "break" two rules of register pairs: * The first of the two registers is odd-numbered. * The index of the second register is equal to that of the first, and not n+1. To allow for this departure from hitherto standard behavior, we extend the functionality of the assembler by defining an extension of the AARCH64_OPND_PAIRREG, called AARCH64_OPND_PAIRREG_OR_XZR. It is used in defining `sysp' and `tlbip' and allows `operand_general_constraint_met_p' to allow the pair to both take on the value of xzr.
This commit is contained in:
parent
2ec6065a4f
commit
d30eb38d5b
@ -6521,6 +6521,7 @@ parse_operands (char *str, const aarch64_opcode *opcode)
|
|||||||
case AARCH64_OPND_Rt_LS64:
|
case AARCH64_OPND_Rt_LS64:
|
||||||
case AARCH64_OPND_Rt_SYS:
|
case AARCH64_OPND_Rt_SYS:
|
||||||
case AARCH64_OPND_PAIRREG:
|
case AARCH64_OPND_PAIRREG:
|
||||||
|
case AARCH64_OPND_PAIRREG_OR_XZR:
|
||||||
case AARCH64_OPND_SVE_Rm:
|
case AARCH64_OPND_SVE_Rm:
|
||||||
po_int_fp_reg_or_fail (REG_TYPE_R_ZR);
|
po_int_fp_reg_or_fail (REG_TYPE_R_ZR);
|
||||||
|
|
||||||
|
@ -455,6 +455,7 @@ enum aarch64_opnd
|
|||||||
AARCH64_OPND_Rn_SP, /* Integer Rn or SP. */
|
AARCH64_OPND_Rn_SP, /* Integer Rn or SP. */
|
||||||
AARCH64_OPND_Rm_SP, /* Integer Rm or SP. */
|
AARCH64_OPND_Rm_SP, /* Integer Rm or SP. */
|
||||||
AARCH64_OPND_PAIRREG, /* Paired register operand. */
|
AARCH64_OPND_PAIRREG, /* Paired register operand. */
|
||||||
|
AARCH64_OPND_PAIRREG_OR_XZR, /* Paired register operand, optionally xzr. */
|
||||||
AARCH64_OPND_Rm_EXT, /* Integer Rm extended. */
|
AARCH64_OPND_Rm_EXT, /* Integer Rm extended. */
|
||||||
AARCH64_OPND_Rm_SFT, /* Integer Rm shifted. */
|
AARCH64_OPND_Rm_SFT, /* Integer Rm shifted. */
|
||||||
|
|
||||||
|
@ -302,8 +302,11 @@ aarch64_ext_regno_pair (const aarch64_operand *self ATTRIBUTE_UNUSED, aarch64_op
|
|||||||
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
|
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
|
||||||
{
|
{
|
||||||
assert (info->idx == 1
|
assert (info->idx == 1
|
||||||
|| info->idx ==3);
|
|| info->idx == 3);
|
||||||
info->reg.regno = inst->operands[info->idx - 1].reg.regno + 1;
|
|
||||||
|
unsigned prev_regno = inst->operands[info->idx - 1].reg.regno;
|
||||||
|
info->reg.regno = (prev_regno == 0x1f) ? 0x1f
|
||||||
|
: prev_regno + 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1693,8 +1693,22 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
|
|||||||
switch (aarch64_operands[type].op_class)
|
switch (aarch64_operands[type].op_class)
|
||||||
{
|
{
|
||||||
case AARCH64_OPND_CLASS_INT_REG:
|
case AARCH64_OPND_CLASS_INT_REG:
|
||||||
/* Check pair reg constraints for cas* instructions. */
|
/* Check for pair of xzr registers. */
|
||||||
if (type == AARCH64_OPND_PAIRREG)
|
if (type == AARCH64_OPND_PAIRREG_OR_XZR
|
||||||
|
&& opnds[idx - 1].reg.regno == 0x1f)
|
||||||
|
{
|
||||||
|
if (opnds[idx].reg.regno != 0x1f)
|
||||||
|
{
|
||||||
|
set_syntax_error (mismatch_detail, idx - 1,
|
||||||
|
_("second reg in pair should be xzr if first is"
|
||||||
|
" xzr"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Check pair reg constraints for instructions taking a pair of
|
||||||
|
consecutively-numbered general-purpose registers. */
|
||||||
|
else if (type == AARCH64_OPND_PAIRREG
|
||||||
|
|| type == AARCH64_OPND_PAIRREG_OR_XZR)
|
||||||
{
|
{
|
||||||
assert (idx == 1 || idx == 3);
|
assert (idx == 1 || idx == 3);
|
||||||
if (opnds[idx - 1].reg.regno % 2 != 0)
|
if (opnds[idx - 1].reg.regno % 2 != 0)
|
||||||
@ -3771,6 +3785,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
|
|||||||
case AARCH64_OPND_Rt_LS64:
|
case AARCH64_OPND_Rt_LS64:
|
||||||
case AARCH64_OPND_Rt_SYS:
|
case AARCH64_OPND_Rt_SYS:
|
||||||
case AARCH64_OPND_PAIRREG:
|
case AARCH64_OPND_PAIRREG:
|
||||||
|
case AARCH64_OPND_PAIRREG_OR_XZR:
|
||||||
case AARCH64_OPND_SVE_Rm:
|
case AARCH64_OPND_SVE_Rm:
|
||||||
case AARCH64_OPND_LSE128_Rt:
|
case AARCH64_OPND_LSE128_Rt:
|
||||||
case AARCH64_OPND_LSE128_Rt2:
|
case AARCH64_OPND_LSE128_Rt2:
|
||||||
|
@ -6174,6 +6174,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
|
|||||||
"an integer or stack pointer register") \
|
"an integer or stack pointer register") \
|
||||||
X(INT_REG, 0, ext_regno_pair, "PAIRREG", 0, F(), \
|
X(INT_REG, 0, ext_regno_pair, "PAIRREG", 0, F(), \
|
||||||
"the second reg of a pair") \
|
"the second reg of a pair") \
|
||||||
|
X(INT_REG, 0, ext_regno_pair, "PAIRREG_OR_XZR", 0, F(), \
|
||||||
|
"the second reg of a pair") \
|
||||||
Y(MODIFIED_REG, reg_extended, "Rm_EXT", 0, F(), \
|
Y(MODIFIED_REG, reg_extended, "Rm_EXT", 0, F(), \
|
||||||
"an integer register with optional extension") \
|
"an integer register with optional extension") \
|
||||||
Y(MODIFIED_REG, reg_shifted, "Rm_SFT", 0, F(), \
|
Y(MODIFIED_REG, reg_shifted, "Rm_SFT", 0, F(), \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user