diff options
| author | 2016-10-26 09:30:21 +0100 | |
|---|---|---|
| committer | 2017-01-13 15:41:34 +0000 | |
| commit | d747c13e19763b295cde7dc29a2cc3ed8585e93d (patch) | |
| tree | e86d7f3fa6a351f6145bfa11c9018e8642245599 | |
| parent | 7e25123127b0b02678a5101d0faa18b65895d723 (diff) | |
ARM: Update `ArmInstructionSetFeatures` to track ARMv8-A.
Some instructions introduced in ARMv8-A will be useful to improve
the generated code.
Also add a HasAtLeast() method to the InstructionSetFeatures class.
(more info why this is needed in instruction_set_features.h).
Test: mma test-art-target && mma test-art-host
Change-Id: If42fa4f0b09d3255851c7b4d85271e7163f0b39c
Signed-off-by: Alexandre Rames <alexandre.rames@linaro.org>
Signed-off-by: Serban Constantinescu <serban.constantinescu@linaro.org>
| -rw-r--r-- | runtime/arch/arm/instruction_set_features_arm.cc | 155 | ||||
| -rw-r--r-- | runtime/arch/arm/instruction_set_features_arm.h | 18 | ||||
| -rw-r--r-- | runtime/arch/arm/instruction_set_features_arm_test.cc | 28 | ||||
| -rw-r--r-- | runtime/arch/arm/instruction_set_features_assembly_tests.S | 47 | ||||
| -rw-r--r-- | runtime/arch/instruction_set_features.h | 18 | ||||
| -rw-r--r-- | runtime/arch/instruction_set_features_test.cc | 12 |
6 files changed, 205 insertions, 73 deletions
diff --git a/runtime/arch/arm/instruction_set_features_arm.cc b/runtime/arch/arm/instruction_set_features_arm.cc index 6c2c81576e..8384460171 100644 --- a/runtime/arch/arm/instruction_set_features_arm.cc +++ b/runtime/arch/arm/instruction_set_features_arm.cc @@ -31,6 +31,7 @@ #if defined(__arm__) extern "C" bool artCheckForArmSdivInstruction(); +extern "C" bool artCheckForArmv8AInstructions(); #endif namespace art { @@ -39,22 +40,34 @@ using android::base::StringPrintf; ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant( const std::string& variant, std::string* error_msg) { + static const char* arm_variants_with_armv8a[] = { + "cortex-a32", + "cortex-a35", + "cortex-a53", + "cortex-a53.a57", + "cortex-a53.a72", + "cortex-a57", + "cortex-a72", + "cortex-a73", + "exynos-m1", + "denver", + "kryo" + }; + bool has_armv8a = FindVariantInArray(arm_variants_with_armv8a, + arraysize(arm_variants_with_armv8a), + variant); + // Look for variants that have divide support. static const char* arm_variants_with_div[] = { "cortex-a7", "cortex-a12", "cortex-a15", "cortex-a17", - "cortex-a53", - "cortex-a53.a57", - "cortex-a57", - "denver", "krait", }; - - bool has_div = FindVariantInArray(arm_variants_with_div, - arraysize(arm_variants_with_div), - variant); + bool has_div = has_armv8a || FindVariantInArray(arm_variants_with_div, + arraysize(arm_variants_with_div), + variant); // Look for variants that have LPAE support. static const char* arm_variants_with_lpae[] = { @@ -62,17 +75,13 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant( "cortex-a12", "cortex-a15", "cortex-a17", - "cortex-a53", - "cortex-a53.a57", - "cortex-a57", - "denver", "krait", }; - bool has_lpae = FindVariantInArray(arm_variants_with_lpae, - arraysize(arm_variants_with_lpae), - variant); + bool has_atomic_ldrd_strd = has_armv8a || FindVariantInArray(arm_variants_with_lpae, + arraysize(arm_variants_with_lpae), + variant); - if (has_div == false && has_lpae == false) { + if (has_armv8a == false && has_div == false && has_atomic_ldrd_strd == false) { static const char* arm_variants_with_default_features[] = { "cortex-a5", "cortex-a8", @@ -92,34 +101,48 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromVariant( << ") using conservative defaults"; } } - return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae)); + return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, + has_atomic_ldrd_strd, + has_armv8a)); } ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromBitmap(uint32_t bitmap) { bool has_div = (bitmap & kDivBitfield) != 0; bool has_atomic_ldrd_strd = (bitmap & kAtomicLdrdStrdBitfield) != 0; - return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_atomic_ldrd_strd)); + bool has_armv8a = (bitmap & kARMv8A) != 0; + return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, + has_atomic_ldrd_strd, + has_armv8a)); } ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromCppDefines() { -#if defined(__ARM_ARCH_EXT_IDIV__) +// Note: This will not work for now since we still build the 32-bit as __ARCH_ARM_7A__. +#if defined(__ARM_ARCH_8A__) + const bool has_armv8a = true; +#else + const bool has_armv8a = false; +#endif +#if defined (__ARM_ARCH_8A__) || defined(__ARM_ARCH_EXT_IDIV__) const bool has_div = true; #else const bool has_div = false; #endif -#if defined(__ARM_FEATURE_LPAE) - const bool has_lpae = true; +#if defined (__ARM_ARCH_8A__) || defined(__ARM_FEATURE_LPAE) + const bool has_atomic_ldrd_strd = true; #else - const bool has_lpae = false; + const bool has_atomic_ldrd_strd = false; #endif - return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae)); + return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, + has_atomic_ldrd_strd, + has_armv8a)); } ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromCpuInfo() { // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that // the kernel puts the appropriate feature flags in here. Sometimes it doesn't. - bool has_lpae = false; + bool has_atomic_ldrd_strd = false; bool has_div = false; + bool has_armv8a = false; std::ifstream in("/proc/cpuinfo"); if (!in.fail()) { @@ -137,21 +160,33 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromCpuInfo() { has_div = true; } if (line.find("lpae") != std::string::npos) { - has_lpae = true; + has_atomic_ldrd_strd = true; } } + if (line.find("architecture") != std::string::npos + && line.find(": 8") != std::string::npos) { + LOG(INFO) << "found architecture ARMv8"; + // Android is only run on A cores, so ARMv8 implies ARMv8-A. + has_armv8a = true; + // ARMv8 CPUs have LPAE and div support. + has_div = true; + has_atomic_ldrd_strd = true; + } } } in.close(); } else { LOG(ERROR) << "Failed to open /proc/cpuinfo"; } - return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae)); + return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, + has_atomic_ldrd_strd, + has_armv8a)); } ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromHwcap() { bool has_div = false; - bool has_lpae = false; + bool has_atomic_ldrd_strd = false; + bool has_armv8a = false; #if defined(ART_TARGET_ANDROID) && defined(__arm__) uint64_t hwcaps = getauxval(AT_HWCAP); @@ -163,18 +198,27 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromHwcap() { has_div = true; } if ((hwcaps & HWCAP_LPAE) != 0) { - has_lpae = true; + has_atomic_ldrd_strd = true; + } + // TODO: Fix this once FPMISC makes it upstream. + // For now we detect if we run on an ARMv8 CPU by looking for CRC32 and SHA1 + // (only available on ARMv8 CPUs). + if ((hwcaps & HWCAP2_CRC32) != 0 && (hwcaps & HWCAP2_SHA1) != 0) { + has_armv8a = true; } #endif - return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae)); + return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, + has_atomic_ldrd_strd, + has_armv8a)); } // A signal handler called by a fault for an illegal instruction. We record the fact in r0 // and then increment the PC in the signal context to return to the next instruction. We know the -// instruction is an sdiv (4 bytes long). -static void bad_divide_inst_handle(int signo ATTRIBUTE_UNUSED, siginfo_t* si ATTRIBUTE_UNUSED, - void* data) { +// instruction is 4 bytes long. +static void bad_instr_handle(int signo ATTRIBUTE_UNUSED, + siginfo_t* si ATTRIBUTE_UNUSED, + void* data) { #if defined(__arm__) struct ucontext *uc = (struct ucontext *)data; struct sigcontext *sc = &uc->uc_mcontext; @@ -190,15 +234,19 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromAssembly() { // instruction. If we get a SIGILL then it's not supported. struct sigaction sa, osa; sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; - sa.sa_sigaction = bad_divide_inst_handle; + sa.sa_sigaction = bad_instr_handle; sigemptyset(&sa.sa_mask); sigaction(SIGILL, &sa, &osa); bool has_div = false; + bool has_armv8a = false; #if defined(__arm__) if (artCheckForArmSdivInstruction()) { has_div = true; } + if (artCheckForArmv8AInstructions()) { + has_armv8a = true; + } #endif // Restore the signal handler. @@ -207,11 +255,13 @@ ArmFeaturesUniquePtr ArmInstructionSetFeatures::FromAssembly() { // Use compile time features to "detect" LPAE support. // TODO: write an assembly LPAE support test. #if defined(__ARM_FEATURE_LPAE) - const bool has_lpae = true; + const bool has_atomic_ldrd_strd = true; #else - const bool has_lpae = false; + const bool has_atomic_ldrd_strd = false; #endif - return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, has_lpae)); + return ArmFeaturesUniquePtr(new ArmInstructionSetFeatures(has_div, + has_atomic_ldrd_strd, + has_armv8a)); } bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const { @@ -219,13 +269,26 @@ bool ArmInstructionSetFeatures::Equals(const InstructionSetFeatures* other) cons return false; } const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures(); - return has_div_ == other_as_arm->has_div_ && - has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_; + return has_div_ == other_as_arm->has_div_ + && has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_ + && has_armv8a_ == other_as_arm->has_armv8a_; +} + +bool ArmInstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const { + if (kArm != other->GetInstructionSet()) { + return false; + } + const ArmInstructionSetFeatures* other_as_arm = other->AsArmInstructionSetFeatures(); + + return (has_div_ || (has_div_ == other_as_arm->has_div_)) + && (has_atomic_ldrd_strd_ || (has_atomic_ldrd_strd_ == other_as_arm->has_atomic_ldrd_strd_)) + && (has_armv8a_ || (has_armv8a_ == other_as_arm->has_armv8a_)); } uint32_t ArmInstructionSetFeatures::AsBitmap() const { - return (has_div_ ? kDivBitfield : 0) | - (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0); + return (has_div_ ? kDivBitfield : 0) + | (has_atomic_ldrd_strd_ ? kAtomicLdrdStrdBitfield : 0) + | (has_armv8a_ ? kARMv8A : 0); } std::string ArmInstructionSetFeatures::GetFeatureString() const { @@ -240,6 +303,11 @@ std::string ArmInstructionSetFeatures::GetFeatureString() const { } else { result += ",-atomic_ldrd_strd"; } + if (has_armv8a_) { + result += ",armv8a"; + } else { + result += ",-armv8a"; + } return result; } @@ -248,6 +316,7 @@ ArmInstructionSetFeatures::AddFeaturesFromSplitString( const std::vector<std::string>& features, std::string* error_msg) const { bool has_atomic_ldrd_strd = has_atomic_ldrd_strd_; bool has_div = has_div_; + bool has_armv8a = has_armv8a_; for (auto i = features.begin(); i != features.end(); i++) { std::string feature = android::base::Trim(*i); if (feature == "div") { @@ -258,13 +327,17 @@ ArmInstructionSetFeatures::AddFeaturesFromSplitString( has_atomic_ldrd_strd = true; } else if (feature == "-atomic_ldrd_strd") { has_atomic_ldrd_strd = false; + } else if (feature == "armv8a") { + has_armv8a = true; + } else if (feature == "-armv8a") { + has_armv8a = false; } else { *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str()); return nullptr; } } return std::unique_ptr<const InstructionSetFeatures>( - new ArmInstructionSetFeatures(has_div, has_atomic_ldrd_strd)); + new ArmInstructionSetFeatures(has_div, has_atomic_ldrd_strd, has_armv8a)); } } // namespace art diff --git a/runtime/arch/arm/instruction_set_features_arm.h b/runtime/arch/arm/instruction_set_features_arm.h index 11f8bf0117..f438a768a5 100644 --- a/runtime/arch/arm/instruction_set_features_arm.h +++ b/runtime/arch/arm/instruction_set_features_arm.h @@ -49,6 +49,8 @@ class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures { bool Equals(const InstructionSetFeatures* other) const OVERRIDE; + bool HasAtLeast(const InstructionSetFeatures* other) const OVERRIDE; + InstructionSet GetInstructionSet() const OVERRIDE { return kArm; } @@ -69,6 +71,11 @@ class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures { return has_atomic_ldrd_strd_; } + // Are ARMv8-A instructions available? + bool HasARMv8AInstructions() const { + return has_armv8a_; + } + virtual ~ArmInstructionSetFeatures() {} protected: @@ -78,19 +85,24 @@ class ArmInstructionSetFeatures FINAL : public InstructionSetFeatures { std::string* error_msg) const OVERRIDE; private: - ArmInstructionSetFeatures(bool has_div, bool has_atomic_ldrd_strd) + ArmInstructionSetFeatures(bool has_div, + bool has_atomic_ldrd_strd, + bool has_armv8a) : InstructionSetFeatures(), - has_div_(has_div), has_atomic_ldrd_strd_(has_atomic_ldrd_strd) { - } + has_div_(has_div), + has_atomic_ldrd_strd_(has_atomic_ldrd_strd), + has_armv8a_(has_armv8a) {} // Bitmap positions for encoding features as a bitmap. enum { kDivBitfield = 1 << 0, kAtomicLdrdStrdBitfield = 1 << 1, + kARMv8A = 1 << 2, }; const bool has_div_; const bool has_atomic_ldrd_strd_; + const bool has_armv8a_; DISALLOW_COPY_AND_ASSIGN(ArmInstructionSetFeatures); }; diff --git a/runtime/arch/arm/instruction_set_features_arm_test.cc b/runtime/arch/arm/instruction_set_features_arm_test.cc index 697ca9015e..6d5dd6d50d 100644 --- a/runtime/arch/arm/instruction_set_features_arm_test.cc +++ b/runtime/arch/arm/instruction_set_features_arm_test.cc @@ -31,7 +31,7 @@ TEST(ArmInstructionSetFeaturesTest, ArmFeaturesFromVariant) { EXPECT_TRUE(krait_features->Equals(krait_features.get())); EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction()); EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()); - EXPECT_STREQ("div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str()); + EXPECT_STREQ("div,atomic_ldrd_strd,-armv8a", krait_features->GetFeatureString().c_str()); EXPECT_EQ(krait_features->AsBitmap(), 3U); // Build features for a 32-bit ARM denver processor. @@ -40,12 +40,13 @@ TEST(ArmInstructionSetFeaturesTest, ArmFeaturesFromVariant) { ASSERT_TRUE(denver_features.get() != nullptr) << error_msg; EXPECT_TRUE(denver_features->Equals(denver_features.get())); - EXPECT_TRUE(denver_features->Equals(krait_features.get())); - EXPECT_TRUE(krait_features->Equals(denver_features.get())); + EXPECT_TRUE(denver_features->HasAtLeast(krait_features.get())); + EXPECT_FALSE(krait_features->Equals(denver_features.get())); + EXPECT_FALSE(krait_features->HasAtLeast(denver_features.get())); EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction()); EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()); - EXPECT_STREQ("div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str()); - EXPECT_EQ(denver_features->AsBitmap(), 3U); + EXPECT_STREQ("div,atomic_ldrd_strd,armv8a", denver_features->GetFeatureString().c_str()); + EXPECT_EQ(denver_features->AsBitmap(), 7U); // Build features for a 32-bit ARMv7 processor. std::unique_ptr<const InstructionSetFeatures> generic_features( @@ -57,7 +58,7 @@ TEST(ArmInstructionSetFeaturesTest, ArmFeaturesFromVariant) { EXPECT_FALSE(krait_features->Equals(generic_features.get())); EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasDivideInstruction()); EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()); - EXPECT_STREQ("-div,-atomic_ldrd_strd", generic_features->GetFeatureString().c_str()); + EXPECT_STREQ("-div,-atomic_ldrd_strd,-armv8a", generic_features->GetFeatureString().c_str()); EXPECT_EQ(generic_features->AsBitmap(), 0U); // ARM6 is not a supported architecture variant. @@ -82,21 +83,22 @@ TEST(ArmInstructionSetFeaturesTest, ArmAddFeaturesFromString) { EXPECT_TRUE(krait_features->Equals(krait_features.get())); EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasDivideInstruction()); EXPECT_TRUE(krait_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()); - EXPECT_STREQ("div,atomic_ldrd_strd", krait_features->GetFeatureString().c_str()); + EXPECT_STREQ("div,atomic_ldrd_strd,-armv8a", krait_features->GetFeatureString().c_str()); EXPECT_EQ(krait_features->AsBitmap(), 3U); // Build features for a 32-bit ARM processor with LPAE and div flipped. std::unique_ptr<const InstructionSetFeatures> denver_features( - base_features->AddFeaturesFromString("div,atomic_ldrd_strd", &error_msg)); + base_features->AddFeaturesFromString("div,atomic_ldrd_strd,armv8a", &error_msg)); ASSERT_TRUE(denver_features.get() != nullptr) << error_msg; EXPECT_TRUE(denver_features->Equals(denver_features.get())); - EXPECT_TRUE(denver_features->Equals(krait_features.get())); - EXPECT_TRUE(krait_features->Equals(denver_features.get())); + EXPECT_FALSE(denver_features->Equals(krait_features.get())); + EXPECT_TRUE(denver_features->HasAtLeast(krait_features.get())); + EXPECT_FALSE(krait_features->Equals(denver_features.get())); EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasDivideInstruction()); EXPECT_TRUE(denver_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()); - EXPECT_STREQ("div,atomic_ldrd_strd", denver_features->GetFeatureString().c_str()); - EXPECT_EQ(denver_features->AsBitmap(), 3U); + EXPECT_STREQ("div,atomic_ldrd_strd,armv8a", denver_features->GetFeatureString().c_str()); + EXPECT_EQ(denver_features->AsBitmap(), 7U); // Build features for a 32-bit default ARM processor. std::unique_ptr<const InstructionSetFeatures> generic_features( @@ -108,7 +110,7 @@ TEST(ArmInstructionSetFeaturesTest, ArmAddFeaturesFromString) { EXPECT_FALSE(krait_features->Equals(generic_features.get())); EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasDivideInstruction()); EXPECT_FALSE(generic_features->AsArmInstructionSetFeatures()->HasAtomicLdrdAndStrd()); - EXPECT_STREQ("-div,-atomic_ldrd_strd", generic_features->GetFeatureString().c_str()); + EXPECT_STREQ("-div,-atomic_ldrd_strd,-armv8a", generic_features->GetFeatureString().c_str()); EXPECT_EQ(generic_features->AsBitmap(), 0U); } diff --git a/runtime/arch/arm/instruction_set_features_assembly_tests.S b/runtime/arch/arm/instruction_set_features_assembly_tests.S index c1086df0f6..5c7f2025c2 100644 --- a/runtime/arch/arm/instruction_set_features_assembly_tests.S +++ b/runtime/arch/arm/instruction_set_features_assembly_tests.S @@ -17,22 +17,49 @@ #include "asm_support_arm.S" .section .text -// This function is used to check for the CPU's support for the sdiv -// instruction at runtime. It will either return the value 1 or -// will cause an invalid instruction trap (SIGILL signal). The -// caller must arrange for the signal handler to set the r0 -// register to 0 and move the pc forward by 4 bytes (to skip -// the invalid instruction). +// These functions are used to check for the CPU's support for the sdiv and +// ARMv8-A instructions at runtime. They will either return the value 1 or will +// cause an invalid instruction trap (SIGILL signal), for which the signal handler +// (bad_instr_handle(), in instruction_set_features_arm.cc) must arrange to set +// the r0 register to 0 and move the pc forward by 4 bytes (to skip the invalid +// instruction). +// Note: For ARM T32, instructions can be either 16b or 32b, but bad_instr_handle() +// deals only with 32b instructions for now. + ENTRY artCheckForArmSdivInstruction mov r1,#1 - // depending on the architecture, the assembler will not allow an + // Depending on the architecture, the assembler will not allow an // sdiv instruction, so we will have to output the bytes directly. - // sdiv r0,r1,r1 is two words: 0xfb91 0xf1f0. We need little endian. - .byte 0x91,0xfb,0xf1,0xf0 + // The T32 encoding for sdiv r0,r1,r1 is two 16bit words: 0xfb91 0xf0f1, with little endianness. + .byte 0x91,0xfb + .byte 0xf1,0xf0 - // if the divide worked, r0 will have the value #1 (result of sdiv). + // If the divide worked, r0 will have the value #1 (result of sdiv). // It will have 0 otherwise (set by the signal handler) // the value is just returned from this function. bx lr END artCheckForArmSdivInstruction + +ENTRY artCheckForArmv8AInstructions + // Depending on the architecture, the assembler will not allow a + // `vrint` instruction, so we will have to output the bytes directly. + + // Move `true` into the result register. The signal handler will set it to 0 + // if execution of the instruction below fails + mov r0,#1 + + // Store S0 in the caller saved R1. If the instruction below succeeds, S0 will + // be clobbered but it will not be caller saved (ARM still uses soft FP). + vmov r1, s0 + + // The T32 encoding for vrinta.f32.f32 s0,s0 is two 16bit words: 0xfeb8,0x0a40, with little + // endianness. + .byte 0xb8,0xfe + .byte 0x40,0x0a + + // Restore S0 (see above comment). + vmov s0, r1 + + bx lr +END artCheckForArmv8AInstructions diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h index b6c5c71818..5f1a507f7a 100644 --- a/runtime/arch/instruction_set_features.h +++ b/runtime/arch/instruction_set_features.h @@ -67,6 +67,24 @@ class InstructionSetFeatures { // Are these features the same as the other given features? virtual bool Equals(const InstructionSetFeatures* other) const = 0; + // For testing purposes we want to make sure that the system we run on has at + // least the options we claim it has. In this cases Equals() does not + // suffice and will cause the test to fail, since the runtime cpu feature + // detection claims more capabilities then statically specified from the + // build system. + // + // A good example of this is the armv8 ART test target that declares + // "CPU_VARIANT=generic". If the generic target is specified and the code + // is run on a platform with enhanced capabilities, the + // instruction_set_features test will fail if we resort to using Equals() + // between statically defined cpu features and runtime cpu features. + // + // For now we default this to Equals() in case the architecture does not + // provide it. + virtual bool HasAtLeast(const InstructionSetFeatures* other) const { + return Equals(other); + } + // Return the ISA these features relate to. virtual InstructionSet GetInstructionSet() const = 0; diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc index d4893923d6..67e2f358c8 100644 --- a/runtime/arch/instruction_set_features_test.cc +++ b/runtime/arch/instruction_set_features_test.cc @@ -52,7 +52,7 @@ TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyVariant) { InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg)); ASSERT_TRUE(property_features.get() != nullptr) << error_msg; - EXPECT_TRUE(property_features->Equals(instruction_set_features.get())) + EXPECT_TRUE(property_features->HasAtLeast(instruction_set_features.get())) << "System property features: " << *property_features.get() << "\nFeatures from build: " << *instruction_set_features.get(); } @@ -89,7 +89,7 @@ TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyString) { base_features->AddFeaturesFromString(dex2oat_isa_features, &error_msg)); ASSERT_TRUE(property_features.get() != nullptr) << error_msg; - EXPECT_TRUE(property_features->Equals(instruction_set_features.get())) + EXPECT_TRUE(property_features->HasAtLeast(instruction_set_features.get())) << "System property features: " << *property_features.get() << "\nFeatures from build: " << *instruction_set_features.get(); } @@ -109,7 +109,7 @@ TEST(InstructionSetFeaturesTest, FeaturesFromCpuInfo) { // Check we get the same instruction set features using /proc/cpuinfo. std::unique_ptr<const InstructionSetFeatures> cpuinfo_features( InstructionSetFeatures::FromCpuInfo()); - EXPECT_TRUE(cpuinfo_features->Equals(instruction_set_features.get())) + EXPECT_TRUE(cpuinfo_features->HasAtLeast(instruction_set_features.get())) << "CPU Info features: " << *cpuinfo_features.get() << "\nFeatures from build: " << *instruction_set_features.get(); } @@ -124,7 +124,7 @@ TEST(InstructionSetFeaturesTest, HostFeaturesFromCppDefines) { std::unique_ptr<const InstructionSetFeatures> cpp_features( InstructionSetFeatures::FromCppDefines()); - EXPECT_TRUE(default_features->Equals(cpp_features.get())) + EXPECT_TRUE(cpp_features->HasAtLeast(default_features.get())) << "Default variant features: " << *default_features.get() << "\nFeatures from build: " << *cpp_features.get(); } @@ -143,7 +143,7 @@ TEST(InstructionSetFeaturesTest, FeaturesFromHwcap) { // Check we get the same instruction set features using AT_HWCAP. std::unique_ptr<const InstructionSetFeatures> hwcap_features( InstructionSetFeatures::FromHwcap()); - EXPECT_TRUE(hwcap_features->Equals(instruction_set_features.get())) + EXPECT_TRUE(hwcap_features->HasAtLeast(instruction_set_features.get())) << "Hwcap features: " << *hwcap_features.get() << "\nFeatures from build: " << *instruction_set_features.get(); } @@ -156,7 +156,7 @@ TEST(InstructionSetFeaturesTest, FeaturesFromAssembly) { // Check we get the same instruction set features using assembly tests. std::unique_ptr<const InstructionSetFeatures> assembly_features( InstructionSetFeatures::FromAssembly()); - EXPECT_TRUE(assembly_features->Equals(instruction_set_features.get())) + EXPECT_TRUE(assembly_features->HasAtLeast(instruction_set_features.get())) << "Assembly features: " << *assembly_features.get() << "\nFeatures from build: " << *instruction_set_features.get(); } |