diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1333,12 +1333,16 @@ } /// Returns true if feature has an impact on target code - /// generation and get its dependent options in second argument. - virtual bool getFeatureDepOptions(StringRef Feature, - std::string &Options) const { + /// generation + virtual bool doesFeatureAffectCodeGen(StringRef Feature) const { return true; } + /// For given feature return dependent ones. + virtual StringRef getFeatureDependencies(StringRef Feature) const { + return StringRef(); + } + struct BranchProtectionInfo { LangOptions::SignReturnAddressScopeKind SignReturnAddr = LangOptions::SignReturnAddressScopeKind::None; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13456,6 +13456,7 @@ TV->getFeatures(Feats); for (auto &Feature : Feats) if (Target->validateCpuSupports(Feature.str())) + // Use '?' to mark features that came from TargetVersion ResFeats.push_back("?" + Feature.str()); return ResFeats; } @@ -13525,6 +13526,7 @@ VersionStr.split(VersionFeatures, "+"); for (auto &VFeature : VersionFeatures) { VFeature = VFeature.trim(); + // Use '?' to mark features that came from AArch64 TargetClones Features.push_back((StringRef{"?"} + VFeature).str()); } } diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -143,9 +143,8 @@ std::optional> getVScaleRange(const LangOptions &LangOpts) const override; - - bool getFeatureDepOptions(StringRef Feature, - std::string &Options) const override; + bool doesFeatureAffectCodeGen(StringRef Name) const override; + StringRef getFeatureDependencies(StringRef Name) const override; bool validateCpuSupports(StringRef FeatureStr) const override; bool hasFeature(StringRef Feature) const override; void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -606,16 +606,18 @@ return llvm::AArch64::ExtensionInfo::MaxFMVPriority; } -bool AArch64TargetInfo::getFeatureDepOptions(StringRef Name, - std::string &FeatureVec) const { - FeatureVec = ""; - for (const auto &E : llvm::AArch64::Extensions) { - if (Name == E.Name) { - FeatureVec = E.DependentFeatures; - break; - } - } - return FeatureVec != ""; +bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const { + for (const auto &E : llvm::AArch64::Extensions) + if (Name == E.Name) + return !E.DependentFeatures.empty(); + return false; +} + +StringRef AArch64TargetInfo::getFeatureDependencies(StringRef Name) const { + for (const auto &E : llvm::AArch64::Extensions) + if (Name == E.Name) + return E.DependentFeatures; + return StringRef(); } bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const { @@ -962,18 +964,18 @@ } // Process target and dependent features. This is done in two loops collecting - // them into UpdatedFeaturesVec: first to add dependent '+'features, - // second to add target '+/-'features that can later disable some of - // features added on the first loop. + // them into UpdatedFeaturesVec: first to add dependent '+'features, second to + // add target '+/-'features that can later disable some of features added on + // the first loop. Function Multi Versioning features begin with '?'. for (const auto &Feature : FeaturesVec) - if ((Feature[0] == '?' || Feature[0] == '+')) { - std::string Options; - if (AArch64TargetInfo::getFeatureDepOptions(Feature.substr(1), Options)) { - SmallVector AttrFeatures; - StringRef(Options).split(AttrFeatures, ","); - for (auto F : AttrFeatures) - UpdatedFeaturesVec.push_back(F.str()); - } + if (((Feature[0] == '?' || Feature[0] == '+')) && + AArch64TargetInfo::doesFeatureAffectCodeGen(Feature.substr(1))) { + StringRef DepFeatures = + AArch64TargetInfo::getFeatureDependencies(Feature.substr(1)); + SmallVector AttrFeatures; + DepFeatures.split(AttrFeatures, ","); + for (auto F : AttrFeatures) + UpdatedFeaturesVec.push_back(F.str()); } for (const auto &Feature : FeaturesVec) if (Feature[0] != '?') { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3508,6 +3508,7 @@ enum SecondParam { None, CPU, Tune }; enum ThirdParam { Target, TargetClones }; HasCommas = HasCommas || Str.contains(','); + const TargetInfo &TInfo = Context.getTargetInfo(); // Warn on empty at the beginning of a string. if (Str.size() == 0) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) @@ -3517,9 +3518,9 @@ while (!Parts.second.empty()) { Parts = Parts.second.split(','); StringRef Cur = Parts.first.trim(); - SourceLocation CurLoc = Literal->getLocationOfByte( - Cur.data() - Literal->getString().data(), getSourceManager(), - getLangOpts(), Context.getTargetInfo()); + SourceLocation CurLoc = + Literal->getLocationOfByte(Cur.data() - Literal->getString().data(), + getSourceManager(), getLangOpts(), TInfo); bool DefaultIsDupe = false; bool HasCodeGenImpact = false; @@ -3527,7 +3528,7 @@ return Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; - if (Context.getTargetInfo().getTriple().isAArch64()) { + if (TInfo.getTriple().isAArch64()) { // AArch64 target clones specific if (Cur == "default") { DefaultIsDupe = HasDefault; @@ -3542,13 +3543,12 @@ while (!CurParts.second.empty()) { CurParts = CurParts.second.split('+'); StringRef CurFeature = CurParts.first.trim(); - if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) { + if (!TInfo.validateCpuSupports(CurFeature)) { Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << CurFeature << TargetClones; continue; } - std::string Options; - if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options)) + if (TInfo.doesFeatureAffectCodeGen(CurFeature)) HasCodeGenImpact = true; CurFeatures.push_back(CurFeature); } diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h --- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h +++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h @@ -25,6 +25,9 @@ class Triple; namespace AArch64 { +// Function Multi Versioning CPU features. They must be kept in sync with +// compiler-rt enum CPUFeatures in lib/builtins/cpu_model.c with FEAT_MAX as +// sentinel. enum CPUFeatures { FEAT_RNG, FEAT_FLAGM, @@ -155,17 +158,18 @@ // SubtargetFeature which may represent either an actual extension or some // internal LLVM property. struct ExtensionInfo { - StringRef Name; // Human readable name, e.g. "profile". - ArchExtKind ID; // Corresponding to the ArchExtKind, this extensions - // representation in the bitfield. - StringRef Feature; // -mattr enable string, e.g. "+spe" - StringRef NegFeature; // -mattr disable string, e.g. "-spe" - - // FIXME These were added by D127812 FMV support and need documenting: - CPUFeatures CPUFeature; // Bitfield value set in __aarch64_cpu_features - StringRef DependentFeatures; - unsigned FmvPriority; - static constexpr unsigned MaxFMVPriority = 1000; + StringRef Name; // Human readable name, e.g. "profile". + ArchExtKind ID; // Corresponding to the ArchExtKind, this + // extensions representation in the bitfield. + StringRef Feature; // -mattr enable string, e.g. "+spe" + StringRef NegFeature; // -mattr disable string, e.g. "-spe" + CPUFeatures CPUFeature; // Function Multi Versioning (FMV) bitfield value + // set in __aarch64_cpu_features + StringRef DependentFeatures; // FMV enabled features string, + // e.g. "+dotprod,+fp-armv8,+neon" + unsigned FmvPriority; // FMV feature priority + static constexpr unsigned MaxFMVPriority = + 1000; // Maximum priority for FMV feature }; // clang-format off @@ -559,6 +563,9 @@ void fillValidCPUArchList(SmallVectorImpl &Values); bool isX18ReservedByDefault(const Triple &TT); + +// For given features returns a mask to check if CPU support them. The mask is +// used in Function Multi Versioning resolver conditions code generation. uint64_t getCpuSupportsMask(ArrayRef FeatureStrs); } // namespace AArch64