From: Siddhesh Poyarekar Date: Fri, 11 Sep 2020 03:48:07 +0000 (+0530) Subject: [Morello] Load and branch instructions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fadea6ae7ef55b304b7fc3ce9ec4ed6ad225b21f;p=thirdparty%2Fbinutils-gdb.git [Morello] Load and branch instructions - BR, BLR - LDPBR, LDPBLR This branch instructions take an address as their target operand. The important distinction between the address register usage between these instructions and other load and store instructions is that these instructions do not support 64-bit registers as addresses. gas/ChangeLog: 2020-10-20 Siddhesh Poyarekar * 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. include/ChangeLog: 2020-10-20 Siddhesh Poyarekar * opcode/aarch64.h (aarch64_opnd): Add CAPADDR_SIMPLE and CAPADDR_SIMM7. (aarch64_insn_class): Add br_capaddr. opcodes/ChangeLog: 2020-10-20 Siddhesh Poyarekar * 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. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index 18794ba29fd..5d2e9442f48 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +2020-10-20 Siddhesh Poyarekar + + * 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 * config/tc-aarch64.c (parse_operands): Add FORM. diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c index cc9fb6372ce..1a5451a9c02 100644 --- a/gas/config/tc-aarch64.c +++ b/gas/config/tc-aarch64.c @@ -3793,7 +3793,10 @@ parse_address_main (char **str, aarch64_opnd_info *operand, != 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; @@ -3975,6 +3978,24 @@ parse_address (char **str, aarch64_opnd_info *operand) 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. */ @@ -7273,6 +7294,46 @@ parse_operands (char *str, const aarch64_opcode *opcode) /* 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 diff --git a/gas/testsuite/gas/aarch64/morello_ldst-c64.d b/gas/testsuite/gas/aarch64/morello_ldst-c64.d index 34bf30753a6..1aaaa45ac40 100644 --- a/gas/testsuite/gas/aarch64/morello_ldst-c64.d +++ b/gas/testsuite/gas/aarch64/morello_ldst-c64.d @@ -24,3 +24,23 @@ Disassembly of section \.text: .*: 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\] diff --git a/gas/testsuite/gas/aarch64/morello_ldst.d b/gas/testsuite/gas/aarch64/morello_ldst.d index 6a4df1331ae..5cdbf0d743a 100644 --- a/gas/testsuite/gas/aarch64/morello_ldst.d +++ b/gas/testsuite/gas/aarch64/morello_ldst.d @@ -23,3 +23,23 @@ Disassembly of section \.text: .*: 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\] diff --git a/gas/testsuite/gas/aarch64/morello_ldst.s b/gas/testsuite/gas/aarch64/morello_ldst.s index faac5c057ed..058b7a4d632 100644 --- a/gas/testsuite/gas/aarch64/morello_ldst.s +++ b/gas/testsuite/gas/aarch64/morello_ldst.s @@ -26,3 +26,24 @@ morello_cas c4, c2, SP_ .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 diff --git a/include/ChangeLog b/include/ChangeLog index 595944bf70f..ad4c53c593c 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,9 @@ +2020-10-20 Siddhesh Poyarekar + + * opcode/aarch64.h (aarch64_opnd): Add CAPADDR_SIMPLE and + CAPADDR_SIMM7. + (aarch64_insn_class): Add br_capaddr. + 2020-10-20 Siddhesh Poyarekar * config/aarch64.h (aarch64_operand_class): Add FORM. diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h index 2b4182dd96f..848fe4d30f2 100644 --- a/include/opcode/aarch64.h +++ b/include/opcode/aarch64.h @@ -526,6 +526,9 @@ enum aarch64_opnd 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 @@ -722,6 +725,7 @@ enum aarch64_insn_class bfloat16, a64c, br_sealed, + br_capaddr, }; /* Opcode enumerators. */ diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index b9062b30f0b..28616004d9a 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,21 @@ +2020-10-20 Siddhesh Poyarekar + + * 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 * aarch64-asm.c (aarch64_ins_form): New function. diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c index 4ff92922d11..742e5265d33 100644 --- a/opcodes/aarch64-asm.c +++ b/opcodes/aarch64-asm.c @@ -626,7 +626,7 @@ aarch64_ins_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED, 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; } @@ -699,12 +699,13 @@ aarch64_ins_addr_simm (const aarch64_operand *self, { 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); @@ -714,7 +715,8 @@ aarch64_ins_addr_simm (const aarch64_operand *self, 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); diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c index 8a35e13393f..0ad4e3759a4 100644 --- a/opcodes/aarch64-dis.c +++ b/opcodes/aarch64-dis.c @@ -1064,7 +1064,7 @@ aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED, 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; } @@ -1146,12 +1146,13 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info, 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); @@ -1159,7 +1160,8 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info, 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 { diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c index 36ab438df6b..5b99050748f 100644 --- a/opcodes/aarch64-opc.c +++ b/opcodes/aarch64-opc.c @@ -357,6 +357,7 @@ const aarch64_field fields[] = { 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 @@ -1739,6 +1740,7 @@ operand_general_constraint_met_p (aarch64_feature_set features, } 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 @@ -3884,6 +3886,11 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, 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: @@ -3940,6 +3947,11 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc, 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: diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h index c10a7bc1e9d..ac37e273fb5 100644 --- a/opcodes/aarch64-opc.h +++ b/opcodes/aarch64-opc.h @@ -180,6 +180,7 @@ enum aarch64_field_kind FLD_a64c_shift, FLD_perm, FLD_form, + FLD_capaddr_simm7, }; /* Field description. */ diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h index e173afc4c8c..d10df9b148b 100644 --- a/opcodes/aarch64-tbl.h +++ b/opcodes/aarch64-tbl.h @@ -2395,6 +2395,12 @@ QLF1(CA), \ } +/* BLR [, #] */ +#define QL1_A64C_CAPADDR \ +{ \ + QLF1(S_Q), \ +} + #define QL2_A64C_CA_CA \ { \ QLF2(CA, CA), \ @@ -2415,6 +2421,12 @@ QLF2(X, X), \ } +/* LDPBLR Ct, [, #] */ +#define QL2_A64C_CA_CAPADDR \ +{ \ + QLF2(CA, S_Q), \ +} + #define QL3_A64C_CA_CA_NIL \ { \ QLF3(CA, CA, NIL), \ @@ -4104,6 +4116,12 @@ const struct aarch64_opcode aarch64_opcode_table[] = 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), @@ -6111,4 +6129,8 @@ const struct aarch64_opcode aarch64_opcode_table[] = 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)")