Add CPUFeatures up to Armv8.6.

This adds support for all relevant features described in the latest
Armv8.6 XML.

Note that this removes the CPUFeatures::All() part of the
`API_CPUFeatures_format` test. It added little value to the test, and
was a burden to update when new features are added.

Change-Id: I276a0970be94c3adf2d0100874df0b82c7424a9b
diff --git a/src/aarch64/cpu-aarch64.cc b/src/aarch64/cpu-aarch64.cc
index 85875a4..86a6ce9 100644
--- a/src/aarch64/cpu-aarch64.cc
+++ b/src/aarch64/cpu-aarch64.cc
@@ -42,8 +42,12 @@
 const IDRegister::Field AA64PFR0::kRAS(28);
 const IDRegister::Field AA64PFR0::kSVE(32);
 const IDRegister::Field AA64PFR0::kDIT(48);
+const IDRegister::Field AA64PFR0::kCSV2(56);
+const IDRegister::Field AA64PFR0::kCSV3(60);
 
 const IDRegister::Field AA64PFR1::kBT(0);
+const IDRegister::Field AA64PFR1::kSSBS(4);
+const IDRegister::Field AA64PFR1::kMTE(8);
 
 const IDRegister::Field AA64ISAR0::kAES(4);
 const IDRegister::Field AA64ISAR0::kSHA1(8);
@@ -57,6 +61,7 @@
 const IDRegister::Field AA64ISAR0::kDP(44);
 const IDRegister::Field AA64ISAR0::kFHM(48);
 const IDRegister::Field AA64ISAR0::kTS(52);
+const IDRegister::Field AA64ISAR0::kRNDR(60);
 
 const IDRegister::Field AA64ISAR1::kDPB(0);
 const IDRegister::Field AA64ISAR1::kAPA(4);
@@ -67,11 +72,21 @@
 const IDRegister::Field AA64ISAR1::kGPA(24);
 const IDRegister::Field AA64ISAR1::kGPI(28);
 const IDRegister::Field AA64ISAR1::kFRINTTS(32);
+const IDRegister::Field AA64ISAR1::kSB(36);
+const IDRegister::Field AA64ISAR1::kSPECRES(40);
+const IDRegister::Field AA64ISAR1::kBF16(44);
+const IDRegister::Field AA64ISAR1::kDGH(48);
+const IDRegister::Field AA64ISAR1::kI8MM(52);
 
 const IDRegister::Field AA64MMFR1::kLO(16);
 
 const IDRegister::Field AA64MMFR2::kAT(32);
 
+const IDRegister::Field AA64ZFR0::kBF16(20);
+const IDRegister::Field AA64ZFR0::kI8MM(44);
+const IDRegister::Field AA64ZFR0::kF32MM(52);
+const IDRegister::Field AA64ZFR0::kF64MM(56);
+
 CPUFeatures AA64PFR0::GetCPUFeatures() const {
   CPUFeatures f;
   if (Get(kFP) >= 0) f.Combine(CPUFeatures::kFP);
@@ -81,12 +96,19 @@
   if (Get(kRAS) >= 1) f.Combine(CPUFeatures::kRAS);
   if (Get(kSVE) >= 1) f.Combine(CPUFeatures::kSVE);
   if (Get(kDIT) >= 1) f.Combine(CPUFeatures::kDIT);
+  if (Get(kCSV2) >= 1) f.Combine(CPUFeatures::kCSV2);
+  if (Get(kCSV2) >= 2) f.Combine(CPUFeatures::kSCXTNUM);
+  if (Get(kCSV3) >= 1) f.Combine(CPUFeatures::kCSV3);
   return f;
 }
 
 CPUFeatures AA64PFR1::GetCPUFeatures() const {
   CPUFeatures f;
   if (Get(kBT) >= 1) f.Combine(CPUFeatures::kBTI);
+  if (Get(kSSBS) >= 1) f.Combine(CPUFeatures::kSSBS);
+  if (Get(kSSBS) >= 2) f.Combine(CPUFeatures::kSSBSControl);
+  if (Get(kMTE) >= 1) f.Combine(CPUFeatures::kMTEInstructions);
+  if (Get(kMTE) >= 2) f.Combine(CPUFeatures::kMTE);
   return f;
 }
 
@@ -107,6 +129,7 @@
   if (Get(kFHM) >= 1) f.Combine(CPUFeatures::kFHM);
   if (Get(kTS) >= 1) f.Combine(CPUFeatures::kFlagM);
   if (Get(kTS) >= 2) f.Combine(CPUFeatures::kAXFlag);
+  if (Get(kRNDR) >= 1) f.Combine(CPUFeatures::kRNG);
   return f;
 }
 
@@ -119,9 +142,25 @@
   if (Get(kLRCPC) >= 1) f.Combine(CPUFeatures::kRCpc);
   if (Get(kLRCPC) >= 2) f.Combine(CPUFeatures::kRCpcImm);
   if (Get(kFRINTTS) >= 1) f.Combine(CPUFeatures::kFrintToFixedSizedInt);
+  if (Get(kSB) >= 1) f.Combine(CPUFeatures::kSB);
+  if (Get(kSPECRES) >= 1) f.Combine(CPUFeatures::kSPECRES);
+  if (Get(kBF16) >= 1) f.Combine(CPUFeatures::kBF16);
+  if (Get(kDGH) >= 1) f.Combine(CPUFeatures::kDGH);
+  if (Get(kI8MM) >= 1) f.Combine(CPUFeatures::kI8MM);
 
-  if (Get(kAPI) >= 1) f.Combine(CPUFeatures::kPAuth);
-  if (Get(kAPA) >= 1) f.Combine(CPUFeatures::kPAuth, CPUFeatures::kPAuthQARMA);
+  // Only one of these fields should be non-zero, but they have the same
+  // encodings, so merge the logic.
+  int apx = std::max(Get(kAPI), Get(kAPA));
+  if (apx >= 1) {
+    f.Combine(CPUFeatures::kPAuth);
+    // APA (rather than API) indicates QARMA.
+    if (Get(kAPA) >= 1) f.Combine(CPUFeatures::kPAuthQARMA);
+    if (apx == 0b0010) f.Combine(CPUFeatures::kPAuthEnhancedPAC);
+    if (apx >= 0b0011) f.Combine(CPUFeatures::kPAuthEnhancedPAC2);
+    if (apx >= 0b0100) f.Combine(CPUFeatures::kPAuthFPAC);
+    if (apx >= 0b0101) f.Combine(CPUFeatures::kPAuthFPACCombined);
+  }
+
   if (Get(kGPI) >= 1) f.Combine(CPUFeatures::kPAuthGeneric);
   if (Get(kGPA) >= 1) {
     f.Combine(CPUFeatures::kPAuthGeneric, CPUFeatures::kPAuthGenericQARMA);
@@ -141,6 +180,17 @@
   return f;
 }
 
+CPUFeatures AA64ZFR0::GetCPUFeatures() const {
+  // This register is only available with SVE, but reads-as-zero in its absence,
+  // so it's always safe to read it.
+  CPUFeatures f;
+  if (Get(kF64MM) >= 1) f.Combine(CPUFeatures::kSVEF64MM);
+  if (Get(kF32MM) >= 1) f.Combine(CPUFeatures::kSVEF32MM);
+  if (Get(kI8MM) >= 1) f.Combine(CPUFeatures::kSVEI8MM);
+  if (Get(kBF16) >= 1) f.Combine(CPUFeatures::kSVEBF16);
+  return f;
+}
+
 int IDRegister::Get(IDRegister::Field field) const {
   int msb = field.GetMsb();
   int lsb = field.GetLsb();
@@ -201,14 +251,13 @@
        CPUFeatures::kSHA512,
        CPUFeatures::kSVE,
        CPUFeatures::kFHM,
-       // Bits 24-27
+       // Bits 24-31
        CPUFeatures::kDIT,
        CPUFeatures::kUSCAT,
        CPUFeatures::kRCpcImm,
        CPUFeatures::kFlagM,
-       // Bits 28-31
-       CPUFeatures::kNone,  // "ssbs"
-       CPUFeatures::kNone,  // "sb"
+       CPUFeatures::kSSBSControl,
+       CPUFeatures::kSB,
        CPUFeatures::kPAuth,
        CPUFeatures::kPAuthGeneric};
   static const size_t kFeatureBitCount =
diff --git a/src/aarch64/cpu-aarch64.h b/src/aarch64/cpu-aarch64.h
index 7290c65..74b2393 100644
--- a/src/aarch64/cpu-aarch64.h
+++ b/src/aarch64/cpu-aarch64.h
@@ -95,6 +95,8 @@
   static const Field kRAS;
   static const Field kSVE;
   static const Field kDIT;
+  static const Field kCSV2;
+  static const Field kCSV3;
 };
 
 class AA64PFR1 : public IDRegister {
@@ -105,6 +107,8 @@
 
  private:
   static const Field kBT;
+  static const Field kSSBS;
+  static const Field kMTE;
 };
 
 class AA64ISAR0 : public IDRegister {
@@ -126,6 +130,7 @@
   static const Field kDP;
   static const Field kFHM;
   static const Field kTS;
+  static const Field kRNDR;
 };
 
 class AA64ISAR1 : public IDRegister {
@@ -144,6 +149,11 @@
   static const Field kGPA;
   static const Field kGPI;
   static const Field kFRINTTS;
+  static const Field kSB;
+  static const Field kSPECRES;
+  static const Field kBF16;
+  static const Field kDGH;
+  static const Field kI8MM;
 };
 
 class AA64MMFR1 : public IDRegister {
@@ -166,6 +176,19 @@
   static const Field kAT;
 };
 
+class AA64ZFR0 : public IDRegister {
+ public:
+  explicit AA64ZFR0(uint64_t value) : IDRegister(value) {}
+
+  CPUFeatures GetCPUFeatures() const;
+
+ private:
+  static const Field kBF16;
+  static const Field kI8MM;
+  static const Field kF32MM;
+  static const Field kF64MM;
+};
+
 class CPU {
  public:
   // Initialise CPU support.
@@ -223,15 +246,16 @@
   }
 
  private:
-#define VIXL_AARCH64_ID_REG_LIST(V)                                         \
-  V(AA64PFR0, "ID_AA64PFR0_EL1")                                            \
-  V(AA64PFR1, "ID_AA64PFR1_EL1")                                            \
-  V(AA64ISAR0, "ID_AA64ISAR0_EL1")                                          \
-  V(AA64ISAR1, "ID_AA64ISAR1_EL1")                                          \
-  V(AA64MMFR1, "ID_AA64MMFR1_EL1")                                          \
-  /* AA64MMFR2 is RES0 before Armv8.2. We can always safely read it, but */ \
-  /* some compilers don't accept its symbolic name for Arm8.0 targets. */   \
-  V(AA64MMFR2, "S3_0_C0_C7_2")
+#define VIXL_AARCH64_ID_REG_LIST(V)                                           \
+  V(AA64PFR0, "ID_AA64PFR0_EL1")                                              \
+  V(AA64PFR1, "ID_AA64PFR1_EL1")                                              \
+  V(AA64ISAR0, "ID_AA64ISAR0_EL1")                                            \
+  V(AA64ISAR1, "ID_AA64ISAR1_EL1")                                            \
+  V(AA64MMFR1, "ID_AA64MMFR1_EL1")                                            \
+  /* These registers are RES0 in the baseline Arm8.0. We can always safely */ \
+  /* read them, but some compilers don't accept the symbolic names. */        \
+  V(AA64MMFR2, "S3_0_C0_C7_2")                                                \
+  V(AA64ZFR0, "S3_0_C0_C4_4")
 
 #define VIXL_READ_ID_REG(NAME, MRS_ARG) static NAME Read##NAME();
   // On native AArch64 platforms, read the named CPU ID registers. These require
diff --git a/src/cpu-features.h b/src/cpu-features.h
index 42eb4f4..cbec565 100644
--- a/src/cpu-features.h
+++ b/src/cpu-features.h
@@ -34,16 +34,65 @@
 namespace vixl {
 
 
+// VIXL aims to handle and detect all architectural features that are likely to
+// influence code-generation decisions at EL0 (user-space).
+//
+// - There may be multiple VIXL feature flags for a given architectural
+//   extension. This occurs where the extension allow components to be
+//   implemented independently, or where kernel support is needed, and is likely
+//   to be fragmented.
+//
+//   For example, Pointer Authentication (kPAuth*) has a separate feature flag
+//   for access to PACGA, and to indicate that the QARMA algorithm is
+//   implemented.
+//
+// - Conversely, some extensions have configuration options that do not affect
+//   EL0, so these are presented as a single VIXL feature.
+//
+//   For example, the RAS extension (kRAS) has several variants, but the only
+//   feature relevant to VIXL is the addition of the ESB instruction so we only
+//   need a single flag.
+//
+// - VIXL offers separate flags for separate features even if they're
+//   architecturally linked.
+//
+//   For example, the architecture requires kFPHalf and kNEONHalf to be equal,
+//   but they have separate hardware ID register fields so VIXL presents them as
+//   separate features.
+//
+// - VIXL can detect every feature for which it can generate code.
+//
+// - VIXL can detect some features for which it cannot generate code.
+//
+// The CPUFeatures::Feature enum — derived from the macro list below — is
+// frequently extended. New features may be added to the list at any point, and
+// no assumptions should be made about the numerical values assigned to each
+// enum constant. The symbolic names can be considered to be stable.
+//
+// The debug descriptions are used only for debug output. The 'cpuinfo' strings
+// are informative; VIXL does not use /proc/cpuinfo for feature detection.
+
 // clang-format off
 #define VIXL_CPU_FEATURE_LIST(V)                                               \
   /* If set, the OS traps and emulates MRS accesses to relevant (EL1) ID_*  */ \
   /* registers, so that the detailed feature registers can be read          */ \
   /* directly.                                                              */ \
+                                                                               \
+  /* Constant name        Debug description         Linux 'cpuinfo' string. */ \
   V(kIDRegisterEmulation, "ID register emulation",  "cpuid")                   \
                                                                                \
   V(kFP,                  "FP",                     "fp")                      \
   V(kNEON,                "NEON",                   "asimd")                   \
   V(kCRC32,               "CRC32",                  "crc32")                   \
+  V(kDGH,                 "DGH",                    "dgh")                     \
+  /* Speculation control features.                                          */ \
+  V(kCSV2,                "CSV2",                   NULL)                      \
+  V(kSCXTNUM,             "SCXTNUM",                NULL)                      \
+  V(kCSV3,                "CSV3",                   NULL)                      \
+  V(kSB,                  "SB",                     "sb")                      \
+  V(kSPECRES,             "SPECRES",                NULL)                      \
+  V(kSSBS,                "SSBS",                   NULL)                      \
+  V(kSSBSControl,         "SSBS (PSTATE control)",  "ssbs")                    \
   /* Cryptographic support instructions.                                    */ \
   V(kAES,                 "AES",                    "aes")                     \
   V(kSHA1,                "SHA1",                   "sha1")                    \
@@ -58,11 +107,19 @@
   V(kRDM,                 "RDM",                    "asimdrdm")                \
   /* Scalable Vector Extension.                                             */ \
   V(kSVE,                 "SVE",                    "sve")                     \
+  V(kSVEF64MM,            "SVE F64MM",              "svef64mm")                \
+  V(kSVEF32MM,            "SVE F32MM",              "svef32mm")                \
+  V(kSVEI8MM,             "SVE I8MM",               "svei8imm")                \
+  V(kSVEBF16,             "SVE BFloat16",           "svebf16")                 \
   /* SDOT and UDOT support (in NEON).                                       */ \
   V(kDotProduct,          "DotProduct",             "asimddp")                 \
+  /* Int8 matrix multiplication (in NEON).                                  */ \
+  V(kI8MM,                "NEON I8MM",              "i8mm")                    \
   /* Half-precision (FP16) support for FP and NEON, respectively.           */ \
   V(kFPHalf,              "FPHalf",                 "fphp")                    \
   V(kNEONHalf,            "NEONHalf",               "asimdhp")                 \
+  /* BFloat16 support (in both FP and NEON.)                                */ \
+  V(kBF16,                "FP/NEON BFloat 16",      "bf16")                    \
   /* The RAS extension, including the ESB instruction.                      */ \
   V(kRAS,                 "RAS",                    NULL)                      \
   /* Data cache clean to the point of persistence: DC CVAP.                 */ \
@@ -98,13 +155,21 @@
   /* Data-independent timing (for selected instructions).                   */ \
   V(kDIT,                 "DIT",                    "dit")                     \
   /* Branch target identification.                                          */ \
-  V(kBTI,                 "BTI",                    NULL)                      \
+  V(kBTI,                 "BTI",                    "bti")                     \
   /* Flag manipulation instructions: {AX,XA}FLAG                            */ \
-  V(kAXFlag,              "AXFlag",                 NULL)                      \
+  V(kAXFlag,              "AXFlag",                 "flagm2")                  \
   /* Random number generation extension,                                    */ \
-  V(kRNG,                 "RNG",                    NULL)                      \
+  V(kRNG,                 "RNG",                    "rng")                     \
   /* Floating-point round to {32,64}-bit integer.                           */ \
-  V(kFrintToFixedSizedInt,"Frint (bounded)",        NULL)
+  V(kFrintToFixedSizedInt,"Frint (bounded)",        "frint")                   \
+  /* Memory Tagging Extension.                                              */ \
+  V(kMTEInstructions,     "MTE (EL0 instructions)", NULL)                      \
+  V(kMTE,                 "MTE",                    NULL)                      \
+  /* PAuth extensions.                                                      */ \
+  V(kPAuthEnhancedPAC,    "PAuth EnhancedPAC",      NULL)                      \
+  V(kPAuthEnhancedPAC2,   "PAuth EnhancedPAC2",     NULL)                      \
+  V(kPAuthFPAC,           "PAuth FPAC",             NULL)                      \
+  V(kPAuthFPACCombined,   "PAuth FPACCombined",     NULL)
 // clang-format on