]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
aarch64: use macro trickery to automate feature array size replication
authorRichard Earnshaw <rearnsha@arm.com>
Thu, 22 May 2025 15:18:11 +0000 (16:18 +0100)
committerRichard Earnshaw <rearnsha@arm.com>
Mon, 9 Jun 2025 14:42:35 +0000 (15:42 +0100)
There are quite a few macros that need to be changed when we need to
increase the number of words in the features data structure.  With
some macro trickery we can automate most of this so that a single
macro needs to be updated.

With C2X we could probably do even better by using recursion, but this
is still a much better situation than we had previously.

A static assertion is used to ensure that there is always enough space
in the flags macro for the number of feature bits we need to support.

include/opcode/aarch64.h

index 3bfdb94124d5b44e60d1e328cd183c1ad8555bb4..c90a6978bdf56dab3ce4d043fb5069c3513b24d1 100644 (file)
@@ -290,13 +290,48 @@ enum aarch64_feature_bit {
   AARCH64_NUM_FEATURES
 };
 
+typedef uint64_t aarch64_feature_word;
+#define AARCH64_BITS_PER_FEATURE_WORD 64
+
+#define AA64_REPLICATE(SEP, BODY, ...) \
+  BODY (0, __VA_ARGS__) SEP            \
+  BODY (1, __VA_ARGS__)
+
+/* Some useful SEP operators for use with replication.  */
+#define REP_COMMA ,
+#define REP_SEMICOLON ;
+#define REP_OR_OR ||
+#define REP_AND_AND &&
+#define REP_PLUS +
+
+/* Not currently needed, but if an empty SEP is required define:
+  #define REP_NO_SEP
+  Then use REP_NO_SEP in the SEP field.  */
+
+/* Used to generate one instance of VAL for each value of ELT (ELT is
+   not otherwise used).  */
+#define AA64_REPVAL(ELT, VAL) VAL
+
+/* static_assert requires C11 (or C++11) or later.  Support older
+   versions by disabling this check since compilers without this are
+   pretty uncommon these days.  */
+#if ((defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) \
+     || (defined __cplusplus && __cplusplus >= 201103L))
+static_assert ((AA64_REPLICATE (REP_PLUS, AA64_REPVAL,
+                               AARCH64_BITS_PER_FEATURE_WORD))
+              >= AARCH64_NUM_FEATURES,
+              "Insufficient repetitions in AA64_REPLICATE()");
+#endif
+
 /* These macros take an initial argument X that gives the index into
    an aarch64_feature_set.  The macros then return the bitmask for
    that array index.  */
 
 /* A mask in which feature bit BIT is set and all other bits are clear.  */
-#define AARCH64_UINT64_BIT(X, BIT) \
-  ((X) == (BIT) / 64 ? 1ULL << (BIT) % 64 : 0)
+#define AARCH64_UINT64_BIT(X, BIT)                     \
+  ((X) == (BIT) / AARCH64_BITS_PER_FEATURE_WORD                \
+   ? 1ULL << (BIT) % AARCH64_BITS_PER_FEATURE_WORD     \
+   : 0)
 
 /* A mask that includes only AARCH64_FEATURE_<NAME>.  */
 #define AARCH64_FEATBIT(X, NAME) \
@@ -431,60 +466,74 @@ enum aarch64_feature_bit {
 
 /* CPU-specific features.  */
 typedef struct {
-  uint64_t flags[(AARCH64_NUM_FEATURES + 63) / 64];
+  aarch64_feature_word flags[AA64_REPLICATE (REP_PLUS, AA64_REPVAL, 1)];
 } aarch64_feature_set;
 
-#define AARCH64_CPU_HAS_FEATURE(CPU,FEAT)      \
-  ((~(CPU).flags[0] & AARCH64_FEATBIT (0, FEAT)) == 0          \
-   && (~(CPU).flags[1] & AARCH64_FEATBIT (1, FEAT)) == 0)
+#define AARCH64_CPU_HAS_FEATURE_BODY(ELT, CPU, FEAT)   \
+  ((~(CPU).flags[ELT] & AARCH64_FEATBIT (ELT, FEAT)) == 0)
+#define AARCH64_CPU_HAS_FEATURE(CPU, FEAT)     \
+  (AA64_REPLICATE (REP_AND_AND, AARCH64_CPU_HAS_FEATURE_BODY, CPU, FEAT))
 
-#define AARCH64_CPU_HAS_ALL_FEATURES(CPU,FEAT) \
-  ((~(CPU).flags[0] & (FEAT).flags[0]) == 0    \
-   && (~(CPU).flags[1] & (FEAT).flags[1]) == 0)
+#define AARCH64_CPU_HAS_ALL_FEATURES_BODY(ELT, CPU, FEAT) \
+  ((~(CPU).flags[ELT] & (FEAT).flags[ELT]) == 0)
+#define AARCH64_CPU_HAS_ALL_FEATURES(CPU, FEAT)        \
+  (AA64_REPLICATE (REP_AND_AND, AARCH64_CPU_HAS_ALL_FEATURES_BODY, CPU, FEAT))
 
+#define AARCH64_CPU_HAS_ANY_FEATURES_BODY(ELT, CPU, FEAT)      \
+  (((CPU).flags[ELT] & (FEAT).flags[ELT]) != 0)
 #define AARCH64_CPU_HAS_ANY_FEATURES(CPU,FEAT) \
-  (((CPU).flags[0] & (FEAT).flags[0]) != 0     \
-   || ((CPU).flags[1] & (FEAT).flags[1]) != 0)
+  (AA64_REPLICATE (REP_OR_OR, AARCH64_CPU_HAS_ANY_FEATURES_BODY, CPU, FEAT))
 
+#define AARCH64_SET_FEATURE_BODY(ELT, DEST, FEAT)      \
+  (DEST).flags[ELT] = FEAT (ELT)
 #define AARCH64_SET_FEATURE(DEST, FEAT) \
-  ((DEST).flags[0] = FEAT (0),         \
-   (DEST).flags[1] = FEAT (1))
+  (AA64_REPLICATE (REP_COMMA, AARCH64_SET_FEATURE_BODY, DEST, FEAT))
 
+#define AARCH64_CLEAR_FEATURE_BODY(ELT, DEST, SRC, FEAT)       \
+  (DEST).flags[ELT] = ((SRC).flags[ELT]                        \
+                        & ~AARCH64_FEATBIT (ELT, FEAT))
 #define AARCH64_CLEAR_FEATURE(DEST, SRC, FEAT)         \
-  ((DEST).flags[0] = (SRC).flags[0] & ~AARCH64_FEATBIT (0, FEAT), \
-   (DEST).flags[1] = (SRC).flags[1] & ~AARCH64_FEATBIT (1, FEAT))
-
-#define AARCH64_MERGE_FEATURE_SETS(TARG,F1,F2)         \
-  do                                                   \
-    {                                                  \
-      (TARG).flags[0] = (F1).flags[0] | (F2).flags[0]; \
-      (TARG).flags[1] = (F1).flags[1] | (F2).flags[1]; \
-    }                                                  \
+  (AA64_REPLICATE (REP_COMMA, AARCH64_CLEAR_FEATURE_BODY, DEST, SRC, FEAT))
+
+#define AARCH64_MERGE_FEATURE_SETS_BODY(ELT, TARG, F1, F2)     \
+  (TARG).flags[ELT] = (F1).flags[ELT] | (F2).flags[ELT];
+#define AARCH64_MERGE_FEATURE_SETS(TARG, F1, F2)                       \
+  do                                                                   \
+    {                                                                  \
+      AA64_REPLICATE (REP_SEMICOLON,                                   \
+                     AARCH64_MERGE_FEATURE_SETS_BODY, TARG, F1, F2);   \
+    }                                                                  \
   while (0)
 
-#define AARCH64_CLEAR_FEATURES(TARG,F1,F2)             \
-  do                                                   \
-    {                                                  \
-      (TARG).flags[0] = (F1).flags[0] &~ (F2).flags[0];        \
-      (TARG).flags[1] = (F1).flags[1] &~ (F2).flags[1];        \
-    }                                                  \
+#define AARCH64_CLEAR_FEATURES_BODY(ELT, TARG, F1, F2) \
+  (TARG).flags[ELT] = (F1).flags[ELT] &~ (F2).flags[ELT];
+#define AARCH64_CLEAR_FEATURES(TARG,F1,F2)                             \
+  do                                                                   \
+    {                                                                  \
+      AA64_REPLICATE (REP_SEMICOLON,                                   \
+                     AARCH64_CLEAR_FEATURES_BODY, TARG, F1, F2);       \
+    }                                                                  \
   while (0)
 
 /* aarch64_feature_set initializers for no features and all features,
    respectively.  */
-#define AARCH64_NO_FEATURES { { 0, 0 } }
-#define AARCH64_ALL_FEATURES { { -1, -1 } }
+#define AARCH64_NO_FEATURES { { AA64_REPLICATE (REP_COMMA, AA64_REPVAL, 0) } }
+#define AARCH64_ALL_FEATURES { { AA64_REPLICATE (REP_COMMA, AA64_REPVAL, -1) } }
 
 /* An aarch64_feature_set initializer for a single feature,
    AARCH64_FEATURE_<FEAT>.  */
-#define AARCH64_FEATURE(FEAT) \
-  { { AARCH64_FEATBIT (0, FEAT), AARCH64_FEATBIT (1, FEAT) } }
+#define AARCH64_FEATURE_BODY(ELT, FEAT)                \
+  AARCH64_FEATBIT (ELT, FEAT)
+#define AARCH64_FEATURE(FEAT)                                  \
+  { { AA64_REPLICATE (REP_COMMA, AARCH64_FEATURE_BODY, FEAT) } }
 
 /* An aarch64_feature_set initializer for a specific architecture version,
    including all the features that are enabled by default for that architecture
    version.  */
-#define AARCH64_ARCH_FEATURES(ARCH) \
-  { { AARCH64_ARCH_##ARCH (0), AARCH64_ARCH_##ARCH (1) } }
+#define AARCH64_ARCH_FEATURES_BODY(ELT, ARCH)  \
+  AARCH64_ARCH_##ARCH (ELT)
+#define AARCH64_ARCH_FEATURES(ARCH)            \
+  { { AA64_REPLICATE (REP_COMMA, AARCH64_ARCH_FEATURES_BODY, ARCH) } }
 
 /* Used by AARCH64_CPU_FEATURES.  */
 #define AARCH64_OR_FEATURES_1(X, ARCH, F1) \
@@ -508,9 +557,11 @@ typedef struct {
 
 /* An aarch64_feature_set initializer for a CPU that implements architecture
    version ARCH, and additionally provides the N features listed in "...".  */
+#define AARCH64_CPU_FEATURES_BODY(ELT, ARCH, N, ...)           \
+  AARCH64_OR_FEATURES_##N (ELT, ARCH, __VA_ARGS__)
 #define AARCH64_CPU_FEATURES(ARCH, N, ...)                     \
-  { { AARCH64_OR_FEATURES_##N (0, ARCH, __VA_ARGS__),          \
-      AARCH64_OR_FEATURES_##N (1, ARCH, __VA_ARGS__) } }
+  { { AA64_REPLICATE (REP_COMMA, AARCH64_CPU_FEATURES_BODY,    \
+                     ARCH, N, __VA_ARGS__) } }
 
 /* An aarch64_feature_set initializer for the N features listed in "...".  */
 #define AARCH64_FEATURES(N, ...) \