diff options
author | Jacob Bramley <jacob.bramley@arm.com> | 2020-07-06 19:38:59 +0100 |
---|---|---|
committer | Jacob Bramley <jacob.bramley@arm.com> | 2020-07-16 09:50:25 +0000 |
commit | 3d8d39423a52b34cb3ca2aca9c1ba38db32e20f4 (patch) | |
tree | 85d7b1c4a3bbcc080b89d0b75d45fdec85fbd9cb /src | |
parent | 960606b686f59d468f97dfa93b5dba5b2b38cc8f (diff) | |
download | vixl-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.cc | 61 | ||||
-rw-r--r-- | src/aarch64/cpu-aarch64.h | 42 | ||||
-rw-r--r-- | src/cpu-features.h | 73 |
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 |