gas: Implement categorization of Morello-specific instructions

While the concept of a core instruction relates to the idea of
instructions that are available irrespective of the presence of
architectural extensions, this concept breaks down with the
introduction of the Morello architecture.

Rather, what is observed in Morello is that when PSTATE.C64 == 1,
the A64C_INSN variant becomes the ONLY valid aarch64_opcode variant,
with the CORE_INSN variant becoming illegal.  Therefore, some way of
ruling out the use of such CORE_INSNs is needed.

Similarly, some A64C_INSN instructions are only valid for
PSTATE.C64 == 1 and are not valid when compiling for Morello A64
mode.

At the assembly level, the CORE_INSN and A64C_INSN variants share the
same mnemonic, differing only by whether they are passed a general-
purpose register argument or its capability counterpart, e.g.

  * CORE_INSN: adr x0, #0
  * A64C_INSN: adr c0, #0

This makes the prospect of combining both insn variants in binutils
into a single insn entry in aarch64_opcode_table[], resolving the
appropriate operand code (e.g. AARCH64_OPND_Can versus
AARCH64_OPND_Rn) at compile time by analyzing the -march and -mabi
flags.

This approach falls short when dealing with instructions such as `bl'
where the core and morello instructions share the same mnemonic but
have distinct encodings.

A more flexible approach is therefore presented here.  Special
restrictions to instructions are encoded in the FLAGS field, which
can then be used in checks carried out in `md_assemble'.

This fixes two issues:
  1. Wrong fix suggestions in `output_operand_error_record':
     - attempting to assemble `adr w0, #0' at present, for example,
     results in a suggestion that `w0' be changed to `x0' as opposed
     to `c0'.
  2. Purecap only instructions being accepted when assembling without
  the C64 extension:
     - `adr c0, #0' is currently accepted when assembling for
     Hybrid mode.

This patch defines the F_NONC64 and F_C64ONLY flags for labellig these
instructions in aarch64_opcode.flags, such that unavailable instructions
could be identified by cross-referencing this field along with whether
C64 is set in the `cpu_variant' aarch64_feature_set variable.  When
the conditions set by the flag is not met by `cpu_variant', the
instruction can be attributed a AARCH64_OPDE_SYNTAX_ERROR, allowing
for correct error handling in md_assemble.

ChangeLog:
  * include/opcode/aarch64.h (F_NONC64): New flag.
  * include/opcode/aarch64.h (F_C64ONLY): Likewise.

opcodes/ChangeLog:
  * aarch64-tbl.h (aarch64_opcode_table): Add F_NONC64 and F_C64ONLY
  to relevant aarch64_opcodes

gas/ChangeLog:
  * config/tc-aarch64.c (validate_opcode_for_feature): New.
  (md_assemble): Use `validate_opcode_for_feature' in template
  selection.
  * gas/testsuite/gas/aarch64/morello-exclude.l: New testcase.
  * gas/testsuite/gas/aarch64/morello-exclude.s: Likewise.
  * gas/testsuite/gas/aarch64/morello-exclude.l: Likewise.
  * gas/testsuite/gas/aarch64/morello_insn.s: Fix hybrid codegen.
This commit is contained in:
Victor Do Nascimento 2023-04-13 12:15:16 +01:00
parent f103ba71c7
commit 459784def0
7 changed files with 72 additions and 9 deletions

View File

@ -7642,6 +7642,36 @@ dump_opcode_operands (const aarch64_opcode *opcode)
}
#endif /* DEBUG_AARCH64 */
/* With the introduction of Morello, some CORE_INSNs are no longer
valid if IS_C64 is true. It is important that such instructions
are no longer treated as core in such contexts and are
disconsidered, rather being treated as belonging to any other
unavailable architectural extension. Likewise, reject purecap-specific
instructions when assembling for hybrid (or any other) tartgets. */
static bfd_boolean
validate_opcode_for_feature (const aarch64_opcode *opcode,
aarch64_feature_set features)
{
/* If opcode is memory-related, Ensure this CPU does not impose any
restriction on allowed operands. */
if (opcode->flags & F_NONC64
&& AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_C64))
{
set_default_error ();
return FALSE;
}
/* Reject purecap-specific instructions when assembling for any other
target. */
if (opcode->flags & F_C64ONLY
&& !(AARCH64_CPU_HAS_FEATURE (features, AARCH64_FEATURE_C64)))
{
set_default_error ();
return FALSE;
}
return TRUE;
}
/* This is the guts of the machine-dependent assembler. STR points to a
machine dependent instruction. This function is supposed to emit
the frags/bytes it assembles to. */
@ -7736,7 +7766,8 @@ md_assemble (char *str)
continue;
}
if (parse_operands (p, opcode)
if (validate_opcode_for_feature (opcode, cpu_variant)
&& parse_operands (p, opcode)
&& programmer_friendly_fixup (&inst)
&& do_encode (inst_base->opcode, &inst.base, &inst_base->value))
{

View File

@ -0,0 +1,4 @@
#name: Morello opcode filter
#as: -march=morello+c64 -mabi=purecap
#source: morello-exclude.s
#error_output: morello-exclude.l

View File

@ -0,0 +1,9 @@
[^:]+: Assembler messages:
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `adr w0,#0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `adr x0,#0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `adrp w0,#0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `adrp x0,#0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `blr w0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `blr x0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `ret w0'
[^:]+:[0-9]+: Error: operand 1 must be a Capability register -- `ret x0'

View File

@ -0,0 +1,8 @@
adr w0, #0
adr x0, #0
adrp w0, #0
adrp x0, #0
blr w0
blr x0
ret w0
ret x0

View File

@ -72,7 +72,12 @@ Label:
\op \cd, Label
.endr
.endm
morello_adrx c0
.ifdef C64MODE
morello_adrx c0
.else
morello_adrx x0
.endif
.ifdef C64MODE
adrdp c0, #4096

View File

@ -969,7 +969,13 @@ extern aarch64_opcode aarch64_opcode_table[];
#define F_SCAN (1ULL << 31)
/* Do no shift immediate operand. */
#define F_NOSHIFT (1ULL << 32)
/* Next bit is 33. */
/* Opcode variant is invalidated by PSTATE.C64. When PSTATE.C64 == 1, operation
requires use of capability operands. */
#define F_NONC64 (1ULL << 33)
/* Opcode vatiant not suitable for morello hybrid mode and will fail unless
PSTATE.C64 == 1. */
#define F_C64ONLY (1ULL << 34)
/* Next bit is 35. */
/* Instruction constraints. */
/* This instruction has a predication constraint on the instruction at PC+4. */

View File

@ -3395,9 +3395,9 @@ struct aarch64_opcode aarch64_opcode_table[] =
CORE_INSN ("b", 0x14000000, 0xfc000000, branch_imm, OP_B, OP1 (ADDR_PCREL26), QL_PCREL_26, 0),
CORE_INSN ("bl", 0x94000000, 0xfc000000, branch_imm, OP_BL, OP1 (ADDR_PCREL26), QL_PCREL_26, 0),
/* Unconditional branch (register). */
CORE_INSN ("br", 0xd61f0000, 0xfffffc1f, branch_reg, 0, OP1 (Rn), QL_I1X, 0),
CORE_INSN ("blr", 0xd63f0000, 0xfffffc1f, branch_reg, 0, OP1 (Rn), QL_I1X, 0),
CORE_INSN ("ret", 0xd65f0000, 0xfffffc1f, branch_reg, 0, OP1 (Rn), QL_I1X, F_OPD0_OPT | F_DEFAULT (30)),
CORE_INSN ("br", 0xd61f0000, 0xfffffc1f, branch_reg, 0, OP1 (Rn), QL_I1X, F_NONC64),
CORE_INSN ("blr", 0xd63f0000, 0xfffffc1f, branch_reg, 0, OP1 (Rn), QL_I1X, F_NONC64),
CORE_INSN ("ret", 0xd65f0000, 0xfffffc1f, branch_reg, 0, OP1 (Rn), QL_I1X, F_OPD0_OPT | F_DEFAULT (30) | F_NONC64),
CORE_INSN ("eret", 0xd69f03e0, 0xffffffff, branch_reg, 0, OP0 (), {}, 0),
CORE_INSN ("drps", 0xd6bf03e0, 0xffffffff, branch_reg, 0, OP0 (), {}, 0),
V8_3_INSN ("braa", 0xd71f0800, 0xfffffc00, branch_reg, OP2 (Rn, Rd_SP), QL_I2SAMEX, 0),
@ -3986,10 +3986,10 @@ struct aarch64_opcode aarch64_opcode_table[] =
CORE_INSN ("mov", 0x52800000, 0x7f800000, movewide, OP_MOV_IMM_WIDE, OP2 (Rd, IMM_MOV), QL_DST_R, F_SF | F_ALIAS | F_CONV),
CORE_INSN ("movk", 0x72800000, 0x7f800000, movewide, OP_MOVK, OP2 (Rd, HALF), QL_DST_R, F_SF),
/* PC-rel. addressing. */
CORE_INSN ("adr", 0x10000000, 0x9f000000, pcreladdr, 0, OP2 (Rd, ADDR_PCREL21), QL_ADRP, 0),
CORE_INSN ("adrp", 0x90000000, 0x9f000000, pcreladdr, 0, OP2 (Rd, ADDR_ADRP), QL_ADRP, 0),
CORE_INSN ("adr", 0x10000000, 0x9f000000, pcreladdr, 0, OP2 (Rd, ADDR_PCREL21), QL_ADRP,F_NONC64),
CORE_INSN ("adrp", 0x90000000, 0x9f000000, pcreladdr, 0, OP2 (Rd, ADDR_ADRP), QL_ADRP, F_NONC64),
/* Pc-rel. addressing with capabilities. */
A64C_INSN ("adr", 0x10000000, 0x9f000000, pcreladdr, 0, OP2 (Cad, ADDR_PCREL21), QL2_A64C_CA_NIL, 0),
A64C_INSN ("adr", 0x10000000, 0x9f000000, pcreladdr, 0, OP2 (Cad, ADDR_PCREL21), QL2_A64C_CA_NIL, F_C64ONLY),
A64C_INSN ("adrp", 0x90000000, 0x9f000000, pcreladdr, 0, OP2 (Cad, ADDR_ADRP), QL2_A64C_CA_NIL, 0),
A64C_INSN ("adrdp", 0x90000000, 0x9f800000, pcreladdr, 0, OP2 (Cad, A64C_ADDR_ADRDP), QL2_A64C_CA_NIL, 0),
/* A64C Instructions. */