diff --git a/llvm/lib/MC/MCSubtargetInfo.cpp b/llvm/lib/MC/MCSubtargetInfo.cpp --- a/llvm/lib/MC/MCSubtargetInfo.cpp +++ b/llvm/lib/MC/MCSubtargetInfo.cpp @@ -56,7 +56,7 @@ } } -static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature, +static bool ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature, ArrayRef FeatureTable) { assert(SubtargetFeatures::hasFlag(Feature) && "Feature flags should start with '+' or '-'"); @@ -64,24 +64,27 @@ // Find feature in table. const SubtargetFeatureKV *FeatureEntry = Find(SubtargetFeatures::StripFlag(Feature), FeatureTable); - // If there is a match - if (FeatureEntry) { - // Enable/disable feature in bits - if (SubtargetFeatures::isEnabled(Feature)) { - Bits.set(FeatureEntry->Value); + // If there is no match + if (!FeatureEntry) { + errs() << "'" << Feature << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + return false; + } - // For each feature that this implies, set it. - SetImpliedBits(Bits, FeatureEntry->Implies.getAsBitset(), FeatureTable); - } else { - Bits.reset(FeatureEntry->Value); + // Enable/disable feature in bits + if (SubtargetFeatures::isEnabled(Feature)) { + Bits.set(FeatureEntry->Value); - // For each feature that implies this, clear it. - ClearImpliedBits(Bits, FeatureEntry->Value, FeatureTable); - } + // For each feature that this implies, set it. + SetImpliedBits(Bits, FeatureEntry->Implies.getAsBitset(), FeatureTable); } else { - errs() << "'" << Feature << "' is not a recognized feature for this target" - << " (ignoring feature)\n"; + Bits.reset(FeatureEntry->Value); + + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, FeatureEntry->Value, FeatureTable); } + + return true; } /// Return the length of the longest entry in the table. @@ -299,11 +302,17 @@ SubtargetFeatures T(FS); FeatureBitset Set, All; for (std::string F : T.getFeatures()) { - ::ApplyFeatureFlag(Set, F, ProcFeatures); + if (!::ApplyFeatureFlag(Set, F, ProcFeatures)) + continue; if (F[0] == '-') F[0] = '+'; - ::ApplyFeatureFlag(All, F, ProcFeatures); + (void)::ApplyFeatureFlag(All, F, ProcFeatures); } + + // Input features are either empty or unknown. + if (Set.none() && All.none()) + return false; + return (FeatureBits & All) == Set; } diff --git a/llvm/unittests/CodeGen/TargetOptionsTest.cpp b/llvm/unittests/CodeGen/TargetOptionsTest.cpp --- a/llvm/unittests/CodeGen/TargetOptionsTest.cpp +++ b/llvm/unittests/CodeGen/TargetOptionsTest.cpp @@ -3,6 +3,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/InitializePasses.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Target/TargetMachine.h" @@ -39,8 +40,8 @@ TargetOptions Options; Options.EnableIPRA = EnableIPRA; return std::unique_ptr( - T->createTargetMachine("X86", "", "", Options, std::nullopt, std::nullopt, - CodeGenOpt::Aggressive)); + T->createTargetMachine("X86", "", "+avx", Options, std::nullopt, + std::nullopt, CodeGenOpt::Aggressive)); } typedef std::function TargetOptionsTest; @@ -61,6 +62,17 @@ delete TPC; } +static void targetFeaturesTest(StringRef F) { + std::unique_ptr TM = createTargetMachine(false); + // This test is designed for the X86 backend; stop if it is not available. + if (!TM) + GTEST_SKIP(); + + ASSERT_NE(TM->getMCSubtargetInfo(), nullptr); + + ASSERT_FALSE(TM->getMCSubtargetInfo()->checkFeatures(F)); +} + } // End of anonymous namespace. TEST(TargetOptionsTest, IPRASetToOff) { @@ -71,6 +83,12 @@ targetOptionsTest(true); } +TEST(TargetOptionsTest, EmptyFeatures) { targetFeaturesTest(""); } + +TEST(TargetOptionsTest, KnownFeature) { targetFeaturesTest("-avx"); } + +TEST(TargetOptionsTest, UnknownFeature) { targetFeaturesTest("+relax"); } + int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); initLLVM();