]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gas: Implement categorization of Morello-specific instructions
authorVictor Do Nascimento <victor.donascimento@arm.com>
Thu, 13 Apr 2023 11:15:16 +0000 (12:15 +0100)
committerVictor Do Nascimento <victor.donascimento@arm.com>
Wed, 17 May 2023 11:44:32 +0000 (12:44 +0100)
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.

gas/config/tc-aarch64.c
gas/testsuite/gas/aarch64/morello-exclude.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello-exclude.l [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello-exclude.s [new file with mode: 0644]
gas/testsuite/gas/aarch64/morello_insn.s
include/opcode/aarch64.h
opcodes/aarch64-tbl.h

index c8373b311dd14f3c53ce4099ab1ffee28d360e8a..66c93248c2a4c8a56790cefeb22ebdf2717c2869 100644 (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))
        {
diff --git a/gas/testsuite/gas/aarch64/morello-exclude.d b/gas/testsuite/gas/aarch64/morello-exclude.d
new file mode 100644 (file)
index 0000000..df137cc
--- /dev/null
@@ -0,0 +1,4 @@
+#name: Morello opcode filter
+#as: -march=morello+c64 -mabi=purecap
+#source: morello-exclude.s
+#error_output: morello-exclude.l
\ No newline at end of file
diff --git a/gas/testsuite/gas/aarch64/morello-exclude.l b/gas/testsuite/gas/aarch64/morello-exclude.l
new file mode 100644 (file)
index 0000000..5502e9c
--- /dev/null
@@ -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'
diff --git a/gas/testsuite/gas/aarch64/morello-exclude.s b/gas/testsuite/gas/aarch64/morello-exclude.s
new file mode 100644 (file)
index 0000000..b920ba3
--- /dev/null
@@ -0,0 +1,8 @@
+       adr w0, #0
+       adr x0, #0
+       adrp w0, #0
+       adrp x0, #0
+       blr w0
+       blr x0
+       ret w0
+       ret x0
index e9fc24d22fd61f1ae6b90e4264530fcd1c9a9830..4a9f9b0ff0206d63437e1cdecc224e165a7d0c4a 100644 (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
index 9c8127bb15734560ac2e140707c710602e3a4d30..6297d3138fab3e180fbe6b9b69d08fcd3bf367ff 100644 (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.  */
index a8f7fe047cdc8b5180909cca03539ce9053cf6cf..bda6ea589366cc70ceac35664a9e3af579010a60 100644 (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.  */