[AArch64] Fix +nofp16 handling
authorSzabolcs Nagy <szabolcs.nagy@arm.com>
Fri, 1 Jul 2016 15:20:50 +0000 (16:20 +0100)
committerSzabolcs Nagy <szabolcs.nagy@arm.com>
Fri, 1 Jul 2016 15:50:59 +0000 (16:50 +0100)
Feature flag handling was not perfect, +nofp16 disabled fp
instructions too.

New feature flag macros were added to check features with multiple
bits set (matters for FP_F16 and SIMD_F16 opcode feature tests).
The unused AARCH64_OPCODE_HAS_FEATURE was removed, all checks should
use one of the AARCH64_CPU_HAS_* macros.  AARCH64_CPU_HAS_FEATURE
now checks all feature bits.

The aarch64_features table now contains the dependencies as
a separate field (so when the feature is enabled all dependencies
are enabled and when it is disabled everything that depends on it
is disabled).

Note that armv8-a+foo+nofoo is not equivalent to armv8-a if
+foo turns on dependent features that nofoo does not turn off.

gas/
* config/tc-aarch64.c (struct aarch64_option_cpu_value_table): Add
require field.
(aarch64_features): Initialize require fields.
(aarch64_parse_features): Handle dependencies.
(aarch64_feature_enable_set, aarch64_feature_disable_set): New.
(md_assemble): Use AARCH64_CPU_HAS_ALL_FEATURES.
* testsuite/gas/aarch64/illegal-nofp16.s: New.
* testsuite/gas/aarch64/illegal-nofp16.l: New.
* testsuite/gas/aarch64/illegal-nofp16.d: New.

include/
* opcode/aarch64.h (AARCH64_CPU_HAS_ALL_FEATURES): New.
(AARCH64_CPU_HAS_ANY_FEATURES): New.
(AARCH64_CPU_HAS_FEATURE): Define as AARCH64_CPU_HAS_ALL_FEATURES.
(AARCH64_OPCODE_HAS_FEATURE): Remove.

gas/ChangeLog
gas/config/tc-aarch64.c
gas/testsuite/gas/aarch64/illegal-nofp16.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/illegal-nofp16.l [new file with mode: 0644]
gas/testsuite/gas/aarch64/illegal-nofp16.s [new file with mode: 0644]
include/ChangeLog
include/opcode/aarch64.h

index 40a9a2b88aba86a59dd64032e1d1c271fc7e5eba..5cb62e2aa3200c7ca8309a11f4f83bc4f77e0bf9 100644 (file)
@@ -1,3 +1,15 @@
+2016-07-01  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+       * config/tc-aarch64.c (struct aarch64_option_cpu_value_table): Add
+       require field.
+       (aarch64_features): Initialize require fields.
+       (aarch64_parse_features): Handle dependencies.
+       (aarch64_feature_enable_set, aarch64_feature_disable_set): New.
+       (md_assemble): Use AARCH64_CPU_HAS_ALL_FEATURES.
+       * testsuite/gas/aarch64/illegal-nofp16.s: New.
+       * testsuite/gas/aarch64/illegal-nofp16.l: New.
+       * testsuite/gas/aarch64/illegal-nofp16.d: New.
+
 2016-07-01  Nick Clifton  <nickc@redhat.com>
 
        * macro.c (macro_expand_body): Use a buffer big enough to hold an
index ddc40f28f26ce712cf1393c4476bf1fca23a6845..2d491f6ab251ed9cd32026bf5433e0326bc88c3b 100644 (file)
@@ -6080,7 +6080,7 @@ md_assemble (char *str)
        {
          /* Check that this instruction is supported for this CPU.  */
          if (!opcode->avariant
-             || !AARCH64_CPU_HAS_FEATURE (cpu_variant, *opcode->avariant))
+             || !AARCH64_CPU_HAS_ALL_FEATURES (cpu_variant, *opcode->avariant))
            {
              as_bad (_("selected processor does not support `%s'"), str);
              return;
@@ -7801,23 +7801,33 @@ struct aarch64_option_cpu_value_table
 {
   const char *name;
   const aarch64_feature_set value;
+  const aarch64_feature_set require; /* Feature dependencies.  */
 };
 
 static const struct aarch64_option_cpu_value_table aarch64_features[] = {
-  {"crc",              AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0)},
-  {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0)},
-  {"fp",               AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
-  {"lse",              AARCH64_FEATURE (AARCH64_FEATURE_LSE, 0)},
-  {"simd",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
-  {"pan",              AARCH64_FEATURE (AARCH64_FEATURE_PAN, 0)},
-  {"lor",              AARCH64_FEATURE (AARCH64_FEATURE_LOR, 0)},
-  {"ras",              AARCH64_FEATURE (AARCH64_FEATURE_RAS, 0)},
-  {"rdma",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD
-                                        | AARCH64_FEATURE_RDMA, 0)},
-  {"fp16",             AARCH64_FEATURE (AARCH64_FEATURE_F16
-                                        | AARCH64_FEATURE_FP, 0)},
-  {"profile",          AARCH64_FEATURE (AARCH64_FEATURE_PROFILE, 0)},
-  {NULL,               AARCH64_ARCH_NONE}
+  {"crc",              AARCH64_FEATURE (AARCH64_FEATURE_CRC, 0),
+                       AARCH64_ARCH_NONE},
+  {"crypto",           AARCH64_FEATURE (AARCH64_FEATURE_CRYPTO, 0),
+                       AARCH64_ARCH_NONE},
+  {"fp",               AARCH64_FEATURE (AARCH64_FEATURE_FP, 0),
+                       AARCH64_ARCH_NONE},
+  {"lse",              AARCH64_FEATURE (AARCH64_FEATURE_LSE, 0),
+                       AARCH64_ARCH_NONE},
+  {"simd",             AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0),
+                       AARCH64_ARCH_NONE},
+  {"pan",              AARCH64_FEATURE (AARCH64_FEATURE_PAN, 0),
+                       AARCH64_ARCH_NONE},
+  {"lor",              AARCH64_FEATURE (AARCH64_FEATURE_LOR, 0),
+                       AARCH64_ARCH_NONE},
+  {"ras",              AARCH64_FEATURE (AARCH64_FEATURE_RAS, 0),
+                       AARCH64_ARCH_NONE},
+  {"rdma",             AARCH64_FEATURE (AARCH64_FEATURE_RDMA, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_SIMD, 0)},
+  {"fp16",             AARCH64_FEATURE (AARCH64_FEATURE_F16, 0),
+                       AARCH64_FEATURE (AARCH64_FEATURE_FP, 0)},
+  {"profile",          AARCH64_FEATURE (AARCH64_FEATURE_PROFILE, 0),
+                       AARCH64_ARCH_NONE},
+  {NULL,               AARCH64_ARCH_NONE, AARCH64_ARCH_NONE},
 };
 
 struct aarch64_long_option_table
@@ -7828,6 +7838,38 @@ struct aarch64_long_option_table
   char *deprecated;            /* If non-null, print this message.  */
 };
 
+/* Transitive closure of features depending on set.  */
+static aarch64_feature_set
+aarch64_feature_disable_set (aarch64_feature_set set)
+{
+  const struct aarch64_option_cpu_value_table *opt;
+  aarch64_feature_set prev = 0;
+
+  while (prev != set) {
+    prev = set;
+    for (opt = aarch64_features; opt->name != NULL; opt++)
+      if (AARCH64_CPU_HAS_ANY_FEATURES (opt->require, set))
+        AARCH64_MERGE_FEATURE_SETS (set, set, opt->value);
+  }
+  return set;
+}
+
+/* Transitive closure of dependencies of set.  */
+static aarch64_feature_set
+aarch64_feature_enable_set (aarch64_feature_set set)
+{
+  const struct aarch64_option_cpu_value_table *opt;
+  aarch64_feature_set prev = 0;
+
+  while (prev != set) {
+    prev = set;
+    for (opt = aarch64_features; opt->name != NULL; opt++)
+      if (AARCH64_CPU_HAS_FEATURE (set, opt->value))
+        AARCH64_MERGE_FEATURE_SETS (set, set, opt->require);
+  }
+  return set;
+}
+
 static int
 aarch64_parse_features (const char *str, const aarch64_feature_set **opt_p,
                        bfd_boolean ext_only)
@@ -7895,11 +7937,19 @@ aarch64_parse_features (const char *str, const aarch64_feature_set **opt_p,
       for (opt = aarch64_features; opt->name != NULL; opt++)
        if (strncmp (opt->name, str, optlen) == 0)
          {
+           aarch64_feature_set set;
+
            /* Add or remove the extension.  */
            if (adding_value)
-             AARCH64_MERGE_FEATURE_SETS (*ext_set, *ext_set, opt->value);
+             {
+               set = aarch64_feature_enable_set (opt->value);
+               AARCH64_MERGE_FEATURE_SETS (*ext_set, *ext_set, set);
+             }
            else
-             AARCH64_CLEAR_FEATURE (*ext_set, *ext_set, opt->value);
+             {
+               set = aarch64_feature_disable_set (opt->value);
+               AARCH64_CLEAR_FEATURE (*ext_set, *ext_set, set);
+             }
            break;
          }
 
diff --git a/gas/testsuite/gas/aarch64/illegal-nofp16.d b/gas/testsuite/gas/aarch64/illegal-nofp16.d
new file mode 100644 (file)
index 0000000..669e85d
--- /dev/null
@@ -0,0 +1,2 @@
+#as: -march=armv8.2-a+nofp16 -mno-verbose-error
+#error-output: illegal-nofp16.l
diff --git a/gas/testsuite/gas/aarch64/illegal-nofp16.l b/gas/testsuite/gas/aarch64/illegal-nofp16.l
new file mode 100644 (file)
index 0000000..99d586b
--- /dev/null
@@ -0,0 +1,3 @@
+[^:]*: Assembler messages:
+^[^:]+:4: Error: selected processor does not support `fneg h0,h1'
+^[^:]+:6: Error: selected processor does not support `fneg v0\.8h,v1\.8h'
diff --git a/gas/testsuite/gas/aarch64/illegal-nofp16.s b/gas/testsuite/gas/aarch64/illegal-nofp16.s
new file mode 100644 (file)
index 0000000..7718444
--- /dev/null
@@ -0,0 +1,7 @@
+// Test -march=armv8.2-a+nofp16 to only disable fp16, not fp.
+.text
+       fneg s0, s1
+       fneg h0, h1
+       fneg v0.4s, v1.4s
+       fneg v0.8h, v1.8h
+       neg v0.16b, v1.16b
index a766ecf9dc3246d69456fef5a7cd4adb3d64c96a..e4db8b8aea9d5d391528fd8a7e9fc01c4ef1dac2 100644 (file)
@@ -1,3 +1,10 @@
+2016-07-01  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+       * opcode/aarch64.h (AARCH64_CPU_HAS_ALL_FEATURES): New.
+       (AARCH64_CPU_HAS_ANY_FEATURES): New.
+       (AARCH64_CPU_HAS_FEATURE): Define as AARCH64_CPU_HAS_ALL_FEATURES.
+       (AARCH64_OPCODE_HAS_FEATURE): Remove.
+
 2016-06-30  Matthew Wahab  <matthew.wahab@arm.com>
 
        * opcode/arm.h (ARM_ARCH_V8_2a): Add FPU_NEON_EXT_RDMA to the set
index b35a818a6576145676df0f95cfe18d461f311f33..1e38749c3019b0d7f8803044a2a91c8b1029c54d 100644 (file)
@@ -84,9 +84,15 @@ typedef uint32_t aarch64_insn;
 /* CPU-specific features.  */
 typedef unsigned long aarch64_feature_set;
 
-#define AARCH64_CPU_HAS_FEATURE(CPU,FEAT)      \
+#define AARCH64_CPU_HAS_ALL_FEATURES(CPU,FEAT) \
+  ((~(CPU) & (FEAT)) == 0)
+
+#define AARCH64_CPU_HAS_ANY_FEATURES(CPU,FEAT) \
   (((CPU) & (FEAT)) != 0)
 
+#define AARCH64_CPU_HAS_FEATURE(CPU,FEAT)      \
+  AARCH64_CPU_HAS_ALL_FEATURES (CPU,FEAT)
+
 #define AARCH64_MERGE_FEATURE_SETS(TARG,F1,F2) \
   do                                           \
     {                                          \
@@ -103,9 +109,6 @@ typedef unsigned long aarch64_feature_set;
 
 #define AARCH64_FEATURE(core,coproc) ((core) | (coproc))
 
-#define AARCH64_OPCODE_HAS_FEATURE(OPC,FEAT)   \
-  (((OPC) & (FEAT)) != 0)
-
 enum aarch64_operand_class
 {
   AARCH64_OPND_CLASS_NIL,