/* aarch64-opc.c -- AArch64 opcode support.
- Copyright (C) 2009-2016 Free Software Foundation, Inc.
+ Copyright (C) 2009-2017 Free Software Foundation, Inc.
Contributed by ARM Ltd.
This file is part of the GNU opcodes library.
{ 16, 6 }, /* immr: in bitfield and logical immediate instructions. */
{ 16, 3 }, /* immb: in advsimd shift by immediate instructions. */
{ 19, 4 }, /* immh: in advsimd shift by immediate instructions. */
+ { 22, 1 }, /* S: in LDRAA and LDRAB instructions. */
{ 22, 1 }, /* N: in logical (immediate) instructions. */
{ 11, 1 }, /* index: in ld/st inst deciding the pre/post-index. */
{ 24, 1 }, /* index2: in ld/st pair inst deciding the pre/post-index. */
{ 8, 2 }, /* SVE_tszl_8: triangular size select low, bits [9,8]. */
{ 19, 2 }, /* SVE_tszl_19: triangular size select low, bits [20,19]. */
{ 14, 1 }, /* SVE_xs_14: UXTW/SXTW select (bit 14). */
- { 22, 1 } /* SVE_xs_22: UXTW/SXTW select (bit 22). */
+ { 22, 1 }, /* SVE_xs_22: UXTW/SXTW select (bit 22). */
+ { 11, 2 }, /* rotate1: FCMLA immediate rotate. */
+ { 13, 2 }, /* rotate2: Indexed element FCMLA immediate rotate. */
+ { 12, 1 }, /* rotate3: FCADD immediate rotate. */
};
enum aarch64_operand_class
/* Table of all conditional affixes. */
const aarch64_cond aarch64_conds[16] =
{
- {{"eq"}, 0x0},
- {{"ne"}, 0x1},
- {{"cs", "hs"}, 0x2},
- {{"cc", "lo", "ul"}, 0x3},
- {{"mi"}, 0x4},
- {{"pl"}, 0x5},
+ {{"eq", "none"}, 0x0},
+ {{"ne", "any"}, 0x1},
+ {{"cs", "hs", "nlast"}, 0x2},
+ {{"cc", "lo", "ul", "last"}, 0x3},
+ {{"mi", "first"}, 0x4},
+ {{"pl", "nfrst"}, 0x5},
{{"vs"}, 0x6},
{{"vc"}, 0x7},
- {{"hi"}, 0x8},
- {{"ls"}, 0x9},
- {{"ge"}, 0xa},
- {{"lt"}, 0xb},
+ {{"hi", "pmore"}, 0x8},
+ {{"ls", "plast"}, 0x9},
+ {{"ge", "tcont"}, 0xa},
+ {{"lt", "tstop"}, 0xb},
{{"gt"}, 0xc},
{{"le"}, 0xd},
{{"al"}, 0xe},
First 3 fields:
Lower bound, higher bound, unused. */
+ {0, 15, 0, "CR", OQK_VALUE_IN_RANGE},
{0, 7, 0, "imm_0_7" , OQK_VALUE_IN_RANGE},
{0, 15, 0, "imm_0_15", OQK_VALUE_IN_RANGE},
{0, 31, 0, "imm_0_31", OQK_VALUE_IN_RANGE},
switch (log_e)
{
case 1: imm = (imm << 2) | imm;
+ /* Fall through. */
case 2: imm = (imm << 4) | imm;
+ /* Fall through. */
case 3: imm = (imm << 8) | imm;
+ /* Fall through. */
case 4: imm = (imm << 16) | imm;
+ /* Fall through. */
case 5: imm = (imm << 32) | imm;
+ /* Fall through. */
case 6: break;
default: abort ();
}
return 0;
}
break;
+ case ldst_imm10:
+ if (opnd->addr.writeback == 1 && opnd->addr.preind != 1)
+ {
+ set_syntax_error (mismatch_detail, idx,
+ _("unexpected address writeback"));
+ return 0;
+ }
+ break;
case ldst_imm9:
case ldstpair_indexed:
case asisdlsep:
_("negative or unaligned offset expected"));
return 0;
+ case AARCH64_OPND_ADDR_SIMM10:
+ /* Scaled signed 10 bits immediate offset. */
+ if (!value_in_range_p (opnd->addr.offset.imm, -4096, 4088))
+ {
+ set_offset_out_of_range_error (mismatch_detail, idx, -4096, 4088);
+ return 0;
+ }
+ if (!value_aligned_p (opnd->addr.offset.imm, 8))
+ {
+ set_unaligned_error (mismatch_detail, idx, 8);
+ return 0;
+ }
+ break;
+
case AARCH64_OPND_SIMD_ADDR_POST:
/* AdvSIMD load/store multiple structures, post-index. */
assert (idx == 1);
if (opnd->shifter.amount != 0 && opnd->shifter.amount != 12)
{
set_other_error (mismatch_detail, idx,
- _("shift amount expected to be 0 or 12"));
+ _("shift amount must be 0 or 12"));
return 0;
}
if (!value_fit_unsigned_field_p (opnd->imm.value, 12))
if (!value_aligned_p (opnd->shifter.amount, 16))
{
set_other_error (mismatch_detail, idx,
- _("shift amount should be a multiple of 16"));
+ _("shift amount must be a multiple of 16"));
return 0;
}
if (!value_in_range_p (opnd->shifter.amount, 0, size * 8 - 16))
{
case OP_MOV_IMM_WIDEN:
imm = ~imm;
- /* Fall through... */
+ /* Fall through. */
case OP_MOV_IMM_WIDE:
if (!aarch64_wide_constant_p (imm, esize == 4, NULL))
{
}
break;
+ case AARCH64_OPND_IMM_ROT1:
+ case AARCH64_OPND_IMM_ROT2:
+ if (opnd->imm.value != 0
+ && opnd->imm.value != 90
+ && opnd->imm.value != 180
+ && opnd->imm.value != 270)
+ {
+ set_other_error (mismatch_detail, idx,
+ _("rotate expected to be 0, 90, 180 or 270"));
+ return 0;
+ }
+ break;
+
+ case AARCH64_OPND_IMM_ROT3:
+ if (opnd->imm.value != 90 && opnd->imm.value != 270)
+ {
+ set_other_error (mismatch_detail, idx,
+ _("rotate expected to be 90 or 270"));
+ return 0;
+ }
+ break;
+
case AARCH64_OPND_SHLL_IMM:
assert (idx == 2);
size = 8 * aarch64_get_qualifier_esize (opnds[idx - 1].qualifier);
if (opnd->shifter.amount != 8 && opnd->shifter.amount != 16)
{
set_other_error (mismatch_detail, idx,
- _("shift amount expected to be 0 or 16"));
+ _("shift amount must be 0 or 16"));
return 0;
}
break;
}
break;
- case AARCH64_OPND_CLASS_CP_REG:
- /* Cn or Cm: 4-bit opcode field named for historical reasons.
- valid range: C0 - C15. */
- if (opnd->reg.regno > 15)
- {
- set_regno_out_of_range_error (mismatch_detail, idx, 0, 15);
- return 0;
- }
- break;
-
case AARCH64_OPND_CLASS_SYSTEM:
switch (type)
{
case AARCH64_OPND_CLASS_SIMD_ELEMENT:
/* Get the upper bound for the element index. */
- num = 16 / aarch64_get_qualifier_esize (qualifier) - 1;
+ if (opcode->op == OP_FCMLA_ELEM)
+ /* FCMLA index range depends on the vector size of other operands
+ and is halfed because complex numbers take two elements. */
+ num = aarch64_get_qualifier_nelem (opnds[0].qualifier)
+ * aarch64_get_qualifier_esize (opnds[0].qualifier) / 2;
+ else
+ num = 16;
+ num = num / aarch64_get_qualifier_esize (qualifier) - 1;
+
/* Index out-of-range. */
if (!value_in_range_p (opnd->reglane.index, 0, num))
{
if (opnd->addr.writeback)
{
if (opnd->addr.preind)
- snprintf (buf, size, "[%s,#%d]!", base, opnd->addr.offset.imm);
+ snprintf (buf, size, "[%s, #%d]!", base, opnd->addr.offset.imm);
else
- snprintf (buf, size, "[%s],#%d", base, opnd->addr.offset.imm);
+ snprintf (buf, size, "[%s], #%d", base, opnd->addr.offset.imm);
}
else
{
if (opnd->shifter.operator_present)
{
assert (opnd->shifter.kind == AARCH64_MOD_MUL_VL);
- snprintf (buf, size, "[%s,#%d,mul vl]",
+ snprintf (buf, size, "[%s, #%d, mul vl]",
base, opnd->addr.offset.imm);
}
else if (opnd->addr.offset.imm)
- snprintf (buf, size, "[%s,#%d]", base, opnd->addr.offset.imm);
+ snprintf (buf, size, "[%s, #%d]", base, opnd->addr.offset.imm);
else
snprintf (buf, size, "[%s]", base);
}
if (print_extend_p)
{
if (print_amount_p)
- snprintf (tb, sizeof (tb), ",%s #%" PRIi64, shift_name,
+ snprintf (tb, sizeof (tb), ", %s #%" PRIi64, shift_name,
opnd->shifter.amount);
else
- snprintf (tb, sizeof (tb), ",%s", shift_name);
+ snprintf (tb, sizeof (tb), ", %s", shift_name);
}
else
tb[0] = '\0';
- snprintf (buf, size, "[%s,%s%s]", base, offset, tb);
+ snprintf (buf, size, "[%s, %s%s]", base, offset, tb);
}
/* Generate the string representation of the operand OPNDS[IDX] for OPCODE
const aarch64_opnd_info *opnds, int idx, int *pcrel_p,
bfd_vma *address)
{
- int i;
+ unsigned int i, num_conds;
const char *name = NULL;
const aarch64_opnd_info *opnd = opnds + idx;
enum aarch64_modifier_kind kind;
/* The optional-ness of <Xt> in e.g. IC <ic_op>{, <Xt>} is determined by
the <ic_op>, therefore we we use opnd->present to override the
generic optional-ness information. */
- if (opnd->type == AARCH64_OPND_Rt_SYS && !opnd->present)
- break;
+ if (opnd->type == AARCH64_OPND_Rt_SYS)
+ {
+ if (!opnd->present)
+ break;
+ }
/* Omit the operand, e.g. RET. */
- if (optional_operand_p (opcode, idx)
- && opnd->reg.regno == get_optional_operand_default_value (opcode))
+ else if (optional_operand_p (opcode, idx)
+ && (opnd->reg.regno
+ == get_optional_operand_default_value (opcode)))
break;
assert (opnd->qualifier == AARCH64_OPND_QLF_W
|| opnd->qualifier == AARCH64_OPND_QLF_X);
case AARCH64_OPND_Rd_SP:
case AARCH64_OPND_Rn_SP:
case AARCH64_OPND_SVE_Rn_SP:
+ case AARCH64_OPND_Rm_SP:
assert (opnd->qualifier == AARCH64_OPND_QLF_W
|| opnd->qualifier == AARCH64_OPND_QLF_WSP
|| opnd->qualifier == AARCH64_OPND_QLF_X
opnd->reglane.index);
break;
- case AARCH64_OPND_Cn:
- case AARCH64_OPND_Cm:
- snprintf (buf, size, "C%d", opnd->reg.regno);
+ case AARCH64_OPND_CRn:
+ case AARCH64_OPND_CRm:
+ snprintf (buf, size, "C%" PRIi64, opnd->imm.value);
break;
case AARCH64_OPND_IDX:
case AARCH64_OPND_SVE_UIMM7:
case AARCH64_OPND_SVE_UIMM8:
case AARCH64_OPND_SVE_UIMM8_53:
+ case AARCH64_OPND_IMM_ROT1:
+ case AARCH64_OPND_IMM_ROT2:
+ case AARCH64_OPND_IMM_ROT3:
snprintf (buf, size, "#%" PRIi64, opnd->imm.value);
break;
case AARCH64_OPND_COND:
case AARCH64_OPND_COND1:
snprintf (buf, size, "%s", opnd->cond->names[0]);
+ num_conds = ARRAY_SIZE (opnd->cond->names);
+ for (i = 1; i < num_conds && opnd->cond->names[i]; ++i)
+ {
+ size_t len = strlen (buf);
+ if (i == 1)
+ snprintf (buf + len, size - len, " // %s = %s",
+ opnd->cond->names[0], opnd->cond->names[i]);
+ else
+ snprintf (buf + len, size - len, ", %s",
+ opnd->cond->names[i]);
+ }
break;
case AARCH64_OPND_ADDR_ADRP:
case AARCH64_OPND_ADDR_SIMM7:
case AARCH64_OPND_ADDR_SIMM9:
case AARCH64_OPND_ADDR_SIMM9_2:
+ case AARCH64_OPND_ADDR_SIMM10:
case AARCH64_OPND_SVE_ADDR_RI_S4xVL:
case AARCH64_OPND_SVE_ADDR_RI_S4x2xVL:
case AARCH64_OPND_SVE_ADDR_RI_S4x3xVL:
case AARCH64_OPND_ADDR_UIMM12:
name = get_64bit_int_reg_name (opnd->addr.base_regno, 1);
if (opnd->addr.offset.imm)
- snprintf (buf, size, "[%s,#%d]", name, opnd->addr.offset.imm);
+ snprintf (buf, size, "[%s, #%d]", name, opnd->addr.offset.imm);
else
snprintf (buf, size, "[%s]", name);
break;
{ "tcr_el3", CPENC(3,6,C2,C0,2), 0 },
{ "tcr_el12", CPENC (3, 5, C2, C0, 2), F_ARCHEXT },
{ "vtcr_el2", CPENC(3,4,C2,C1,2), 0 },
+ { "apiakeylo_el1", CPENC (3, 0, C2, C1, 0), F_ARCHEXT },
+ { "apiakeyhi_el1", CPENC (3, 0, C2, C1, 1), F_ARCHEXT },
+ { "apibkeylo_el1", CPENC (3, 0, C2, C1, 2), F_ARCHEXT },
+ { "apibkeyhi_el1", CPENC (3, 0, C2, C1, 3), F_ARCHEXT },
+ { "apdakeylo_el1", CPENC (3, 0, C2, C2, 0), F_ARCHEXT },
+ { "apdakeyhi_el1", CPENC (3, 0, C2, C2, 1), F_ARCHEXT },
+ { "apdbkeylo_el1", CPENC (3, 0, C2, C2, 2), F_ARCHEXT },
+ { "apdbkeyhi_el1", CPENC (3, 0, C2, C2, 3), F_ARCHEXT },
+ { "apgakeylo_el1", CPENC (3, 0, C2, C3, 0), F_ARCHEXT },
+ { "apgakeyhi_el1", CPENC (3, 0, C2, C3, 1), F_ARCHEXT },
{ "afsr0_el1", CPENC(3,0,C5,C1,0), 0 },
{ "afsr1_el1", CPENC(3,0,C5,C1,1), 0 },
{ "afsr0_el2", CPENC(3,4,C5,C1,0), 0 },
&& !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_PROFILE))
return FALSE;
+ /* ARMv8.3 Pointer authentication keys. */
+ if ((reg->value == CPENC (3, 0, C2, C1, 0)
+ || reg->value == CPENC (3, 0, C2, C1, 1)
+ || reg->value == CPENC (3, 0, C2, C1, 2)
+ || reg->value == CPENC (3, 0, C2, C1, 3)
+ || reg->value == CPENC (3, 0, C2, C2, 0)
+ || reg->value == CPENC (3, 0, C2, C2, 1)
+ || reg->value == CPENC (3, 0, C2, C2, 2)
+ || reg->value == CPENC (3, 0, C2, C2, 3)
+ || reg->value == CPENC (3, 0, C2, C3, 0)
+ || reg->value == CPENC (3, 0, C2, C3, 1))
+ && !AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_V8_3))
+ return FALSE;
+
return TRUE;
}