+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * config/tc-aarch64.c (aarch64_addr_reg_parse): Add capability
+ registers.
+ (parse_address_main): Support capability address operands.
+ (parse_cap_address): New function.
+ (parse_operands): Add CAPADDR_SIMPLE and CAPADDR_SIMM7.
+ * testsuite/gas/aarch64/morello_ldst-c64.d: Add tests.
+ * testsuite/gas/aarch64/morello_ldst.d: Likewise.
+ * testsuite/gas/aarch64/morello_ldst.s: Likewise.
+
2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* config/tc-aarch64.c (parse_operands): Add FORM.
!= aarch64_get_qualifier_esize (*offset_qualifier)
&& (operand->type != AARCH64_OPND_SVE_ADDR_ZX
|| *base_qualifier != AARCH64_OPND_QLF_S_S
- || *offset_qualifier != AARCH64_OPND_QLF_X))
+ || *offset_qualifier != AARCH64_OPND_QLF_X)
+ /* Capabilities can have W as well as X registers as
+ offsets. */
+ && (*base_qualifier != AARCH64_OPND_QLF_CA))
{
set_syntax_error (_("offset has different size from base"));
return false;
base, REG_TYPE_R_Z, SHIFTED_NONE);
}
+/* Parse a base capability address. Return TRUE on success. */
+static bool
+parse_cap_address (char **str, aarch64_opnd_info *operand,
+ enum aarch64_insn_class class)
+{
+ aarch64_opnd_qualifier_t base_qualifier, offset_qualifier;
+ aarch64_reg_type base;
+
+ if (AARCH64_CPU_HAS_FEATURE (cpu_variant, AARCH64_FEATURE_C64)
+ && class != br_capaddr)
+ base = REG_TYPE_R64_SP;
+ else
+ base = REG_TYPE_CA_N_SP;
+
+ return parse_address_main (str, operand, &base_qualifier, &offset_qualifier,
+ base, REG_TYPE_R_Z, SHIFTED_NONE);
+}
+
/* Parse an address in which SVE vector registers and MUL VL are allowed.
The arguments have the same meaning as for parse_address_main.
Return TRUE on success. */
/* Qualifier to be deduced by libopcodes. */
break;
+ case AARCH64_OPND_CAPADDR_SIMPLE:
+ case AARCH64_OPND_CAPADDR_SIMM7:
+ {
+ /* A little hack to prevent the address parser from trying to
+ pretend that a BLR with a register may be a BLR with an
+ address. It fails the addressing mode test below, but still
+ ends up adding a symbol with the name of the register. */
+ char *start = str;
+ po_char_or_fail ('[');
+ str = start;
+
+ po_misc_or_fail (parse_cap_address (&str, info, opcode->iclass));
+ if (info->addr.pcrel || info->addr.offset.is_reg
+ || (!info->addr.preind && !info->addr.postind)
+ || info->addr.writeback)
+ {
+ set_syntax_error (_("invalid addressing mode"));
+ goto failure;
+ }
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
+ {
+ set_syntax_error (_("relocation not allowed"));
+ goto failure;
+ }
+ if (inst.reloc.exp.X_op == O_constant && !inst.gen_lit_pool)
+ info->addr.offset.imm = inst.reloc.exp.X_add_number;
+ else
+ {
+ set_syntax_error (_("Invalid offset constant"));
+ goto failure;
+ }
+ if (info->type == AARCH64_OPND_CAPADDR_SIMPLE
+ && info->addr.offset.imm != 0)
+ {
+ set_syntax_error (_("non-zero offset not allowed"));
+ goto failure;
+ }
+ break;
+ }
+
case AARCH64_OPND_ADDR_SIMM7:
po_misc_or_fail (parse_address (&str, info));
if (info->addr.pcrel || info->addr.offset.is_reg
.*: a2e483e2 swpal c4, c2, \[csp\]
.*: a22483e2 swp c4, c2, \[csp\]
.*: a26483e2 swpl c4, c2, \[csp\]
+.*: c2d813e1 blr \[csp, #-1024\]
+.*: c2d7f3e1 blr \[csp, #1008\]
+.*: c2d033e1 blr \[csp, #16\]
+.*: c2d013e1 blr \[csp\]
+.*: c2d813e0 br \[csp, #-1024\]
+.*: c2d7f3e0 br \[csp, #1008\]
+.*: c2d033e0 br \[csp, #16\]
+.*: c2d013e0 br \[csp\]
+.*: c2d81041 blr \[c2, #-1024\]
+.*: c2d7f041 blr \[c2, #1008\]
+.*: c2d03041 blr \[c2, #16\]
+.*: c2d01041 blr \[c2\]
+.*: c2d81040 br \[c2, #-1024\]
+.*: c2d7f040 br \[c2, #1008\]
+.*: c2d03040 br \[c2, #16\]
+.*: c2d01040 br \[c2\]
+.*: c2c433e2 ldpblr c2, \[csp\]
+.*: c2c413e2 ldpbr c2, \[csp\]
+.*: c2c43042 ldpblr c2, \[c2\]
+.*: c2c41042 ldpbr c2, \[c2\]
.*: a2e483e2 swpal c4, c2, \[sp\]
.*: a22483e2 swp c4, c2, \[sp\]
.*: a26483e2 swpl c4, c2, \[sp\]
+.*: c2d813e1 blr \[csp, #-1024\]
+.*: c2d7f3e1 blr \[csp, #1008\]
+.*: c2d033e1 blr \[csp, #16\]
+.*: c2d013e1 blr \[csp\]
+.*: c2d813e0 br \[csp, #-1024\]
+.*: c2d7f3e0 br \[csp, #1008\]
+.*: c2d033e0 br \[csp, #16\]
+.*: c2d013e0 br \[csp\]
+.*: c2d81041 blr \[c2, #-1024\]
+.*: c2d7f041 blr \[c2, #1008\]
+.*: c2d03041 blr \[c2, #16\]
+.*: c2d01041 blr \[c2\]
+.*: c2d81040 br \[c2, #-1024\]
+.*: c2d7f040 br \[c2, #1008\]
+.*: c2d03040 br \[c2, #16\]
+.*: c2d01040 br \[c2\]
+.*: c2c433e2 ldpblr c2, \[csp\]
+.*: c2c413e2 ldpbr c2, \[csp\]
+.*: c2c43042 ldpblr c2, \[c2\]
+.*: c2c41042 ldpbr c2, \[c2\]
.endm
morello_swp c4, c2, VAREG
morello_swp c4, c2, SP_
+
+// Branch and Load, Prefetch, etc.
+
+ .macro morello_branch_load cnsp
+ .irp op, blr, br
+ \op [\cnsp, #-1024]
+ \op [\cnsp, #1008]
+ \op [\cnsp, #16]
+ \op [\cnsp]
+ .endr
+ .endm
+morello_branch_load csp
+morello_branch_load c2
+
+ .macro morello_branch_load2 cnsp
+ .irp op, ldpblr, ldpbr
+ \op c2, [\cnsp]
+ .endr
+ .endm
+morello_branch_load2 csp
+morello_branch_load2 c2
+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * opcode/aarch64.h (aarch64_opnd): Add CAPADDR_SIMPLE and
+ CAPADDR_SIMM7.
+ (aarch64_insn_class): Add br_capaddr.
+
2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* config/aarch64.h (aarch64_operand_class): Add FORM.
AARCH64_OPND_A64C_IMM6_EXT, /* IMM6 for SCBNDS. */
AARCH64_OPND_PERM, /* 3-bit capability permission for e.g. CLRPERM. */
AARCH64_OPND_FORM, /* 2-bit capability form for e.g. SEAL. */
+ AARCH64_OPND_CAPADDR_SIMM7, /* Immediate offset with capability base for
+ BLR/BR. */
+ AARCH64_OPND_CAPADDR_SIMPLE, /* Simple base address with no offset. */
};
/* Qualifier constrains an operand. It either specifies a variant of an
bfloat16,
a64c,
br_sealed,
+ br_capaddr,
};
/* Opcode enumerators. */
+2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
+
+ * aarch64-asm.c (aarch64_ins_addr_simple): Fix comment.
+ (aarch64_ins_addr_simm): Support capability address operands.
+ * aarch64-dis.c (aarch64_ext_addr_simple): Fix comment.
+ (aarch64_ext_addr_simm): Support capability address operands.
+ * aarch64-opc.c (fields): Add capaddr_simm7.
+ (operand_general_constraint_met_p): Add CAPADDR_SIMM7.
+ (aarch64_print_operand): Add CAPADDR_SIMM7 and CAPADDR_SIMPLE.
+ * aarch64-opc.h (aarch64_field_kind): Add FLD_capaddr_simm7.
+ * aarch64-tbl.h (QL1_A64C_CAPADDR, QL2_A64C_CA_CAPADDR): New
+ macros.
+ (aarch64_opcode_table): New instructions.
+ (AARCH64_OPERANDS): New operands.
+ * aarch64-asm-2.c: Regenerate.
+ * aarch64-dis-2.c: Regenerate.
+ * aarch64-opc-2.c: Regenerate.
+
2020-10-20 Siddhesh Poyarekar <siddesh.poyarekar@arm.com>
* aarch64-asm.c (aarch64_ins_form): New function.
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
- /* Rn */
+ /* Rn/Can */
insert_field (FLD_Rn, code, info->addr.base_regno, 0);
return true;
}
{
int imm;
- /* Rn */
+ /* Rn/Can */
insert_field (FLD_Rn, code, info->addr.base_regno, 0);
/* simm (imm9 or imm7) */
imm = info->addr.offset.imm;
if (self->fields[0] == FLD_imm7
- || info->qualifier == AARCH64_OPND_QLF_imm_tag)
+ || self->fields[0] == FLD_capaddr_simm7
+ || info->qualifier == AARCH64_OPND_QLF_imm_tag)
/* scaled immediate in ld/st pair instructions.. */
imm >>= get_logsz (aarch64_get_qualifier_esize (info->qualifier));
insert_field (self->fields[0], code, imm, 0);
assert (inst->opcode->iclass != ldst_unscaled
&& inst->opcode->iclass != ldstnapair_offs
&& inst->opcode->iclass != ldstpair_off
- && inst->opcode->iclass != ldst_unpriv);
+ && inst->opcode->iclass != ldst_unpriv
+ && inst->opcode->iclass != br_capaddr);
assert (info->addr.preind != info->addr.postind);
if (info->addr.preind)
insert_field (self->fields[1], code, 1, 0);
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
- /* Rn */
+ /* Rn/Can */
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
return true;
}
aarch64_insn imm;
info->qualifier = get_expected_qualifier (inst, info->idx);
- /* Rn */
+ /* Rn/Can */
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
/* simm (imm9 or imm7) */
imm = extract_field (self->fields[0], code, 0);
info->addr.offset.imm = sign_extend (imm, fields[self->fields[0]].width - 1);
if (self->fields[0] == FLD_imm7
+ || self->fields[0] == FLD_capaddr_simm7
|| info->qualifier == AARCH64_OPND_QLF_imm_tag)
/* scaled immediate in ld/st pair instructions. */
info->addr.offset.imm *= aarch64_get_qualifier_esize (info->qualifier);
if (inst->opcode->iclass == ldst_unscaled
|| inst->opcode->iclass == ldstnapair_offs
|| inst->opcode->iclass == ldstpair_off
- || inst->opcode->iclass == ldst_unpriv)
+ || inst->opcode->iclass == ldst_unpriv
+ || inst->opcode->iclass == br_capaddr)
info->addr.writeback = 0;
else
{
{ 14, 1 }, /* a64c_shift: Shift bit in SCBNDS. */
{ 13, 3 }, /* perm: permission specifier in clrperm. */
{ 13, 2 }, /* form: form specifier in seal. */
+ { 13, 7 }, /* capaddr_simm7: Signed immediate for BLR/BR. */
};
enum aarch64_operand_class
}
switch (type)
{
+ case AARCH64_OPND_CAPADDR_SIMM7:
case AARCH64_OPND_ADDR_SIMM7:
/* Scaled signed 7 bits immediate offset. */
/* Get the size of the data element that is accessed, which may be
snprintf (buf, size, "#0x%" PRIx64, addr);
break;
+ case AARCH64_OPND_CAPADDR_SIMPLE:
+ snprintf (buf, size, "[%s]",
+ get_cap_reg_name (opnd->addr.base_regno, 1));
+ break;
+
case AARCH64_OPND_ADDR_SIMPLE:
case AARCH64_OPND_SIMD_ADDR_SIMPLE:
case AARCH64_OPND_SIMD_ADDR_POST:
get_addr_sve_reg_name (opnd->addr.offset.regno, opnd->qualifier));
break;
+ case AARCH64_OPND_CAPADDR_SIMM7:
+ print_immediate_offset_address
+ (buf, size, opnd, get_cap_reg_name (opnd->addr.base_regno, 1));
+ break;
+
case AARCH64_OPND_ADDR_SIMM7:
case AARCH64_OPND_ADDR_SIMM9:
case AARCH64_OPND_ADDR_SIMM9_2:
FLD_a64c_shift,
FLD_perm,
FLD_form,
+ FLD_capaddr_simm7,
};
/* Field description. */
QLF1(CA), \
}
+/* BLR [<Cn|CSP>, #<imm>] */
+#define QL1_A64C_CAPADDR \
+{ \
+ QLF1(S_Q), \
+}
+
#define QL2_A64C_CA_CA \
{ \
QLF2(CA, CA), \
QLF2(X, X), \
}
+/* LDPBLR Ct, [<Cn|CSP>, #<imm>] */
+#define QL2_A64C_CA_CAPADDR \
+{ \
+ QLF2(CA, S_Q), \
+}
+
#define QL3_A64C_CA_CA_NIL \
{ \
QLF3(CA, CA, NIL), \
A64C_INSN ("build", 0xc2c00400, 0xffe0fc00, a64c, 0, OP3 (Cad_SP, Can_SP, Cam_SP), QL3_A64C_CA_CA_CA, 0),
A64C_INSN ("bx", 0xc2c273e0, 0xffffffff, a64c, 0, OP1 (A64C_IMMV4), {}, 0),
+ /* Capability load and branch instructions */
+ A64C_INSN ("blr", 0xc2d01001, 0xfff01c1f, br_capaddr, 0, OP1 (CAPADDR_SIMM7), QL1_A64C_CAPADDR, 0),
+ A64C_INSN ("br", 0xc2d01000, 0xfff01c1f, br_capaddr, 0, OP1 (CAPADDR_SIMM7), QL1_A64C_CAPADDR, 0),
+ A64C_INSN ("ldpblr", 0xc2c43000, 0xfffffc00, br_capaddr, 0, OP2 (Cat, CAPADDR_SIMPLE), QL2_A64C_CA_CAPADDR, 0),
+ A64C_INSN ("ldpbr", 0xc2c41000, 0xfffffc00, br_capaddr, 0, OP2 (Cat, CAPADDR_SIMPLE), QL2_A64C_CA_CAPADDR, 0),
+
/* Compare and swap capabilities. */
A64C_INSN ("cas", 0xa2a07c00, 0xffe0fc00, a64c, 0, OP3 (Cas, Cat, ADDR_SIMPLE), QL3_A64C_CA_CA_ADDR, 0),
A64C_INSN ("casa", 0xa2e07c00, 0xffe0fc00, a64c, 0, OP3 (Cas, Cat, ADDR_SIMPLE), QL3_A64C_CA_CA_ADDR, 0),
F(FLD_a64c_shift, FLD_imm6_2), \
"6-bit unsigned immediate") \
Y(PERM, perm, "PERM", 0, F(), "a capability permission") \
- Y(FORM, form, "FORM", 0, F(), "a capability form")
+ Y(FORM, form, "FORM", 0, F(), "a capability form") \
+ Y(ADDRESS, addr_simm, "CAPADDR_SIMM7", 0, F(FLD_capaddr_simm7), \
+ "a capability based address with 7-bit signed immediate offset") \
+ Y(ADDRESS, addr_simple, "CAPADDR_SIMPLE", 0, F(), \
+ "a capability address with base register (no offset)")