@@ -6024,6 +6024,25 @@ parse_operands (char *str, const aarch64_opcode *opcode)
/* skip_p */ 0);
break;
+ case AARCH64_OPND_ADDR_SIMM10:
+ po_misc_or_fail (parse_address (&str, info));
+ if (info->addr.pcrel || info->addr.offset.is_reg
+ || !info->addr.preind || info->addr.postind)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
+ {
+ set_syntax_error (_("relocation not allowed"));
+ goto failure;
+ }
+ assign_imm_if_const_or_fixup_later (&inst.reloc, info,
+ /* addr_off_p */ 1,
+ /* need_libopcodes_p */ 1,
+ /* skip_p */ 0);
+ break;
+
case AARCH64_OPND_ADDR_UIMM12:
po_misc_or_fail (parse_address (&str, info));
if (info->addr.pcrel || info->addr.offset.is_reg
@@ -6481,6 +6500,7 @@ warn_unpredictable_ldst (aarch64_instruction *instr, char *str)
{
case ldst_pos:
case ldst_imm9:
+ case ldst_imm10:
case ldst_unscaled:
case ldst_unpriv:
/* Loading/storing the base register is unpredictable if writeback. */
@@ -7350,6 +7370,7 @@ fix_insn (fixS *fixP, uint32_t flags, offsetT value)
case AARCH64_OPND_ADDR_SIMM7:
case AARCH64_OPND_ADDR_SIMM9:
case AARCH64_OPND_ADDR_SIMM9_2:
+ case AARCH64_OPND_ADDR_SIMM10:
case AARCH64_OPND_ADDR_UIMM12:
/* Immediate offset in an address. */
insn = get_aarch64_insn (buf);
new file mode 100644
@@ -0,0 +1,2 @@
+#as: -march=armv8.3-a -mno-verbose-error
+#error-output: illegal-ldraa.l
new file mode 100644
@@ -0,0 +1,35 @@
+[^:]+: Assembler messages:
+[^:]+:9: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#1\]'
+[^:]+:10: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#4\]'
+[^:]+:11: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#-10\]'
+[^:]+:12: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#4096\]'
+[^:]+:13: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#5555\]'
+[^:]+:14: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#-4104\]'
+[^:]+:15: Error: 64-bit integer or SP register expected at operand 2 -- `ldraa x0,\[xz\]'
+[^:]+:16: Error: missing offset in the pre-indexed address at operand 2 -- `ldraa x0,\[x1\]!'
+[^:]+:17: Error: invalid expression in the address at operand 2 -- `ldraa x0,\[sp\],'
+[^:]+:18: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#1\]!'
+[^:]+:19: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#4\]!'
+[^:]+:20: Error: immediate value must be a multiple of 8 at operand 2 -- `ldraa x0,\[x1,#-10\]!'
+[^:]+:21: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#4096\]!'
+[^:]+:22: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#5555\]!'
+[^:]+:23: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldraa x0,\[x1,#-4104\]!'
+[^:]+:24: Error: 64-bit integer or SP register expected at operand 2 -- `ldraa x0,\[xz\]'
+[^:]+:25: Error: invalid addressing mode at operand 2 -- `ldraa x0,\[x1\],#8'
+[^:]+:28: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#1\]'
+[^:]+:29: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#4\]'
+[^:]+:30: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#-10\]'
+[^:]+:31: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#4096\]'
+[^:]+:32: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#5555\]'
+[^:]+:33: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#-4104\]'
+[^:]+:34: Error: 64-bit integer or SP register expected at operand 2 -- `ldrab x0,\[xz\]'
+[^:]+:35: Error: missing offset in the pre-indexed address at operand 2 -- `ldrab x0,\[x1\]!'
+[^:]+:36: Error: invalid expression in the address at operand 2 -- `ldrab x0,\[sp\],'
+[^:]+:37: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#1\]!'
+[^:]+:38: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#4\]!'
+[^:]+:39: Error: immediate value must be a multiple of 8 at operand 2 -- `ldrab x0,\[x1,#-10\]!'
+[^:]+:40: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#4096\]!'
+[^:]+:41: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#5555\]!'
+[^:]+:42: Error: immediate offset out of range -4096 to 4088 at operand 2 -- `ldrab x0,\[x1,#-4104\]!'
+[^:]+:43: Error: 64-bit integer or SP register expected at operand 2 -- `ldrab x0,\[xz\]'
+[^:]+:44: Error: invalid addressing mode at operand 2 -- `ldrab x0,\[x1\],#8'
new file mode 100644
@@ -0,0 +1,44 @@
+// Test illegal ARMv8.3 LDRAA and LDRAB instructions
+.text
+
+ // Good.
+ ldraa x0, [x1,#8]
+ ldrab x0, [x1,#8]
+
+
+ ldraa x0, [x1,#1]
+ ldraa x0, [x1,#4]
+ ldraa x0, [x1,#-10]
+ ldraa x0, [x1,#4096]
+ ldraa x0, [x1,#5555]
+ ldraa x0, [x1,#-4104]
+ ldraa x0, [xz]
+ ldraa x0, [x1]!
+ ldraa x0, [sp],
+ ldraa x0, [x1,#1]!
+ ldraa x0, [x1,#4]!
+ ldraa x0, [x1,#-10]!
+ ldraa x0, [x1,#4096]!
+ ldraa x0, [x1,#5555]!
+ ldraa x0, [x1,#-4104]!
+ ldraa x0, [xz]
+ ldraa x0, [x1], #8
+
+
+ ldrab x0, [x1,#1]
+ ldrab x0, [x1,#4]
+ ldrab x0, [x1,#-10]
+ ldrab x0, [x1,#4096]
+ ldrab x0, [x1,#5555]
+ ldrab x0, [x1,#-4104]
+ ldrab x0, [xz]
+ ldrab x0, [x1]!
+ ldrab x0, [sp],
+ ldrab x0, [x1,#1]!
+ ldrab x0, [x1,#4]!
+ ldrab x0, [x1,#-10]!
+ ldrab x0, [x1,#4096]!
+ ldrab x0, [x1,#5555]!
+ ldrab x0, [x1,#-4104]!
+ ldrab x0, [xz]
+ ldrab x0, [x1], #8
@@ -50,3 +50,25 @@ Disassembly of section \.text:
a4: d65f0fff retab
a8: d69f0bff eretaa
ac: d69f0fff eretab
+ b0: f8200441 ldraa x1, \[x2\]
+ b4: f8200441 ldraa x1, \[x2\]
+ b8: f87ff483 ldraa x3, \[x4, #-8\]
+ bc: f82014c5 ldraa x5, \[x6, #8\]
+ c0: f83ff507 ldraa x7, \[x8, #4088\]
+ c4: f8600528 ldraa x8, \[x9, #-4096\]
+ c8: f82007e2 ldraa x2, \[sp\]
+ cc: f87067e4 ldraa x4, \[sp, #-2000\]
+ d0: f8a00441 ldrab x1, \[x2\]
+ d4: f8a00441 ldrab x1, \[x2\]
+ d8: f8fff483 ldrab x3, \[x4, #-8\]
+ dc: f8a014c5 ldrab x5, \[x6, #8\]
+ e0: f8bff507 ldrab x7, \[x8, #4088\]
+ e4: f8e00528 ldrab x8, \[x9, #-4096\]
+ e8: f8a007e2 ldrab x2, \[sp\]
+ ec: f8f067e4 ldrab x4, \[sp, #-2000\]
+ f0: f8201c62 ldraa x2, \[x3, #8\]!
+ f4: f87ffca4 ldraa x4, \[x5, #-8\]!
+ f8: f83fffe6 ldraa x6, \[sp, #4088\]!
+ fc: f8a01c62 ldrab x2, \[x3, #8\]!
+ 100: f8fffca4 ldrab x4, \[x5, #-8\]!
+ 104: f8bfffe6 ldrab x6, \[sp, #4088\]!
@@ -54,3 +54,26 @@
retab
eretaa
eretab
+
+ ldraa x1, [x2]
+ ldraa x1, [x2,#0]
+ ldraa x3, [x4,#-8]
+ ldraa x5, [x6,#8]
+ ldraa x7, [x8,#4088]
+ ldraa x8, [x9,#-4096]
+ ldraa x2, [sp]
+ ldraa x4, [sp,#-2000]
+ ldrab x1, [x2]
+ ldrab x1, [x2,#0]
+ ldrab x3, [x4,#-8]
+ ldrab x5, [x6,#8]
+ ldrab x7, [x8,#4088]
+ ldrab x8, [x9,#-4096]
+ ldrab x2, [sp]
+ ldrab x4, [sp,#-2000]
+ ldraa x2, [x3, #8]!
+ ldraa x4, [x5, #-8]!
+ ldraa x6, [sp, #4088]!
+ ldrab x2, [x3, #8]!
+ ldrab x4, [x5, #-8]!
+ ldrab x6, [sp, #4088]!
@@ -225,6 +225,7 @@ enum aarch64_opnd
friendly feature of using LDR/STR as the
the mnemonic name for LDUR/STUR instructions
wherever there is no ambiguity. */
+ AARCH64_OPND_ADDR_SIMM10, /* Address of signed 10-bit immediate. */
AARCH64_OPND_ADDR_UIMM12, /* Address of unsigned 12-bit immediate. */
AARCH64_OPND_SIMD_ADDR_SIMPLE,/* Address of ld/st multiple structures. */
AARCH64_OPND_SIMD_ADDR_POST, /* Address of ld/st multiple post-indexed. */
@@ -465,6 +466,7 @@ enum aarch64_insn_class
ldst_immpost,
ldst_immpre,
ldst_imm9, /* immpost or immpre */
+ ldst_imm10, /* LDRAA/LDRAB */
ldst_pos,
ldst_regoff,
ldst_unpriv,
@@ -606,6 +606,30 @@ aarch64_ins_addr_simm (const aarch64_operand *self,
return NULL;
}
+/* Encode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}]. */
+const char *
+aarch64_ins_addr_simm10 (const aarch64_operand *self,
+ const aarch64_opnd_info *info,
+ aarch64_insn *code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+ int imm;
+
+ /* Rn */
+ insert_field (self->fields[0], code, info->addr.base_regno, 0);
+ /* simm10 */
+ imm = info->addr.offset.imm >> 3;
+ insert_field (self->fields[1], code, imm >> 9, 0);
+ insert_field (self->fields[2], code, imm, 0);
+ /* writeback */
+ if (info->addr.writeback)
+ {
+ assert (info->addr.preind == 1 && info->addr.postind == 0);
+ insert_field (self->fields[3], code, 1, 0);
+ }
+ return NULL;
+}
+
/* Encode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>{, #<pimm>}]. */
const char *
aarch64_ins_addr_uimm12 (const aarch64_operand *self,
@@ -59,6 +59,7 @@ AARCH64_DECL_OPD_INSERTER (ins_ft);
AARCH64_DECL_OPD_INSERTER (ins_addr_simple);
AARCH64_DECL_OPD_INSERTER (ins_addr_regoff);
AARCH64_DECL_OPD_INSERTER (ins_addr_simm);
+AARCH64_DECL_OPD_INSERTER (ins_addr_simm10);
AARCH64_DECL_OPD_INSERTER (ins_addr_uimm12);
AARCH64_DECL_OPD_INSERTER (ins_simd_addr_post);
AARCH64_DECL_OPD_INSERTER (ins_cond);
@@ -981,6 +981,27 @@ aarch64_ext_addr_uimm12 (const aarch64_operand *self, aarch64_opnd_info *info,
return 1;
}
+/* Decode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}]. */
+int
+aarch64_ext_addr_simm10 (const aarch64_operand *self, aarch64_opnd_info *info,
+ aarch64_insn code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED)
+{
+ aarch64_insn imm;
+
+ info->qualifier = get_expected_qualifier (inst, info->idx);
+ /* Rn */
+ info->addr.base_regno = extract_field (self->fields[0], code, 0);
+ /* simm10 */
+ imm = extract_fields (code, 0, 2, self->fields[1], self->fields[2]);
+ info->addr.offset.imm = sign_extend (imm, 9) << 3;
+ if (extract_field (self->fields[3], code, 0) == 1) {
+ info->addr.writeback = 1;
+ info->addr.preind = 1;
+ }
+ return 1;
+}
+
/* Decode the address operand for e.g.
LD1 {<Vt>.<T>, <Vt2>.<T>, <Vt3>.<T>}, [<Xn|SP>], <Xm|#<amount>>. */
int
@@ -81,6 +81,7 @@ AARCH64_DECL_OPD_EXTRACTOR (ext_ft);
AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simple);
AARCH64_DECL_OPD_EXTRACTOR (ext_addr_regoff);
AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simm);
+AARCH64_DECL_OPD_EXTRACTOR (ext_addr_simm10);
AARCH64_DECL_OPD_EXTRACTOR (ext_addr_uimm12);
AARCH64_DECL_OPD_EXTRACTOR (ext_simd_addr_post);
AARCH64_DECL_OPD_EXTRACTOR (ext_cond);
@@ -253,6 +253,7 @@ const aarch64_field fields[] =
{ 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. */
@@ -1528,6 +1529,14 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
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:
@@ -1584,6 +1593,20 @@ operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
_("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);
@@ -3408,6 +3431,7 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
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:
@@ -80,6 +80,7 @@ enum aarch64_field_kind
FLD_immr,
FLD_immb,
FLD_immh,
+ FLD_S_imm10,
FLD_N,
FLD_index,
FLD_index2,
@@ -1094,6 +1094,12 @@
QLF3(W, X, NIL), \
}
+/* e.g. LDRAA <Xt>, [<Xn|SP>{,#imm}]. */
+#define QL_X1NIL \
+{ \
+ QLF2(X, NIL), \
+}
+
/* e.g. LDXP <Xt1>, <Xt2>, [<Xn|SP>{,#0}]. */
#define QL_R2NIL \
{ \
@@ -2916,6 +2922,9 @@ struct aarch64_opcode aarch64_opcode_table[] =
CORE_INSN ("ldur", 0xb8400000, 0xbfe00c00, ldst_unscaled, OP_LDUR, OP2 (Rt, ADDR_SIMM9), QL_LDST_R, F_GPRSIZE_IN_Q),
CORE_INSN ("ldursw", 0xb8800000, 0xffe00c00, ldst_unscaled, OP_LDURSW, OP2 (Rt, ADDR_SIMM9), QL_LDST_X32, 0),
CORE_INSN ("prfum", 0xf8800000, 0xffe00c00, ldst_unscaled, OP_PRFUM, OP2 (PRFOP, ADDR_SIMM9), QL_LDST_PRFM, 0),
+ /* Load/store register (scaled signed immediate). */
+ V8_3_INSN ("ldraa", 0xf8200400, 0xffa00400, ldst_imm10, OP2 (Rt, ADDR_SIMM10), QL_X1NIL, 0),
+ V8_3_INSN ("ldrab", 0xf8a00400, 0xffa00400, ldst_imm10, OP2 (Rt, ADDR_SIMM10), QL_X1NIL, 0),
/* Load/store exclusive. */
CORE_INSN ("stxrb", 0x8007c00, 0xffe08000, ldstexcl, 0, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0),
CORE_INSN ("stlxrb", 0x800fc00, 0xffe08000, ldstexcl, 0, OP3 (Rs, Rt, ADDR_SIMPLE), QL_W2_LDST_EXC, 0),
@@ -4117,6 +4126,8 @@ struct aarch64_opcode aarch64_opcode_table[] =
"an address with 9-bit signed immediate offset") \
Y(ADDRESS, addr_simm, "ADDR_SIMM9_2", 0, F(FLD_imm9,FLD_index), \
"an address with 9-bit negative or unaligned immediate offset") \
+ Y(ADDRESS, addr_simm10, "ADDR_SIMM10", 0, F(FLD_Rn,FLD_S_imm10,FLD_imm9,FLD_index),\
+ "an address with 10-bit scaled, signed immediate offset") \
Y(ADDRESS, addr_uimm12, "ADDR_UIMM12", 0, F(FLD_Rn,FLD_imm12), \
"an address with scaled, unsigned immediate offset") \
Y(ADDRESS, addr_simple, "SIMD_ADDR_SIMPLE", 0, F(), \