aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob Bramley <jacob.bramley@arm.com>2020-07-06 19:38:59 +0100
committerJacob Bramley <jacob.bramley@arm.com>2020-07-16 09:50:25 +0000
commit3d8d39423a52b34cb3ca2aca9c1ba38db32e20f4 (patch)
tree85d7b1c4a3bbcc080b89d0b75d45fdec85fbd9cb /src
parent960606b686f59d468f97dfa93b5dba5b2b38cc8f (diff)
downloadvixl-3d8d39423a52b34cb3ca2aca9c1ba38db32e20f4.tar.gz
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
Diffstat (limited to 'src')
-rw-r--r--src/aarch64/cpu-aarch64.cc61
-rw-r--r--src/aarch64/cpu-aarch64.h42
-rw-r--r--src/cpu-features.h73
3 files changed, 157 insertions, 19 deletions
diff --git a/src/aarch64/cpu-aarch64.cc b/src/aarch64/cpu-aarch64.cc
index 85875a4b..86a6ce9c 100644
--- a/src/aarch64/cpu-aarch64.cc
+++ b/src/aarch64/cpu-aarch64.cc
@@ -42,8 +42,12 @@ const IDRegister::Field AA64PFR0::kAdvSIMD(20, Field::kSigned);
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::kSM4(40);
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::kLRCPC(20);
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 @@ CPUFeatures AA64PFR0::GetCPUFeatures() const {
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 @@ CPUFeatures AA64ISAR0::GetCPUFeatures() const {
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 @@ CPUFeatures AA64ISAR1::GetCPUFeatures() const {
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);
+
+ // 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(kAPI) >= 1) f.Combine(CPUFeatures::kPAuth);
- if (Get(kAPA) >= 1) f.Combine(CPUFeatures::kPAuth, CPUFeatures::kPAuthQARMA);
if (Get(kGPI) >= 1) f.Combine(CPUFeatures::kPAuthGeneric);
if (Get(kGPA) >= 1) {
f.Combine(CPUFeatures::kPAuthGeneric, CPUFeatures::kPAuthGenericQARMA);
@@ -141,6 +180,17 @@ CPUFeatures AA64MMFR2::GetCPUFeatures() const {
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 CPU::InferCPUFeaturesFromOS(
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 7290c652..74b23934 100644
--- a/src/aarch64/cpu-aarch64.h
+++ b/src/aarch64/cpu-aarch64.h
@@ -95,6 +95,8 @@ class AA64PFR0 : public IDRegister {
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 @@ class AA64PFR1 : public IDRegister {
private:
static const Field kBT;
+ static const Field kSSBS;
+ static const Field kMTE;
};
class AA64ISAR0 : public IDRegister {
@@ -126,6 +130,7 @@ class AA64ISAR0 : public IDRegister {
static const Field kDP;
static const Field kFHM;
static const Field kTS;
+ static const Field kRNDR;
};
class AA64ISAR1 : public IDRegister {
@@ -144,6 +149,11 @@ class AA64ISAR1 : public IDRegister {
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 @@ class AA64MMFR2 : public IDRegister {
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 @@ class CPU {
}
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 42eb4f44..cbec5658 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 @@ namespace vixl {
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 @@ namespace vixl {
/* 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