diff --git a/clang/docs/ClangCommandLineReference.rst b/clang/docs/ClangCommandLineReference.rst --- a/clang/docs/ClangCommandLineReference.rst +++ b/clang/docs/ClangCommandLineReference.rst @@ -1083,6 +1083,10 @@ Generate local calls to out-of-line atomic operations +.. option:: -mno-fmv + +Turn off function multiversioning + .. option:: --param , --param= .. option:: -print-supported-cpus, --print-supported-cpus, -mcpu=?, -mtune=? diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3087,6 +3087,9 @@ /// valid feature names. ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const; + std::vector + filterFunctionTargetVersionAttrs(const TargetVersionAttr *TV) const; + void getFunctionFeatureMap(llvm::StringMap &FeatureMap, const FunctionDecl *) const; void getFunctionFeatureMap(llvm::StringMap &FeatureMap, diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1856,7 +1856,8 @@ Target, CPUSpecific, CPUDispatch, - TargetClones + TargetClones, + TargetVersion }; /// Represents a function declaration or definition. diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2729,6 +2729,31 @@ }]; } +def TargetVersion : InheritableAttr { + let Spellings = [GCC<"target_version">]; + let Args = [StringArgument<"NamesStr">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [TargetVersionDocs]; + let AdditionalMembers = [{ + StringRef getTVName() const { return getNamesStr().trim(); } + bool isDefaultVersion() const { + return getTVName() == "default"; + } + void getFeatures(llvm::SmallVectorImpl &Out) const { + if (isDefaultVersion()) return; + StringRef Features = getTVName(); + + SmallVector AttrFeatures; + Features.split(AttrFeatures, "+"); + + for (auto &Feature : AttrFeatures) { + Feature = Feature.trim(); + Out.push_back(Feature); + } + } + }]; +} + def TargetClones : InheritableAttr { let Spellings = [GCC<"target_clones">]; let Args = [VariadicStringArgument<"featuresStrs">]; @@ -2762,11 +2787,12 @@ return 0 == std::count_if( featuresStrs_begin(), featuresStrs_begin() + Index, [FeatureStr](StringRef S) { return S == FeatureStr; }); + } }]; } -def : MutualExclusions<[TargetClones, Target, CPUDispatch, CPUSpecific]>; +def : MutualExclusions<[TargetClones, TargetVersion, Target, CPUDispatch, CPUSpecific]>; def MinVectorWidth : InheritableAttr { let Spellings = [Clang<"min_vector_width">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2348,6 +2348,19 @@ }]; } +def TargetVersionDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +For AArch64 target clang supports function multiversioning by +``__attribute__((target_version("OPTIONS")))`` attribute. When applied to a +function it instructs compiler to emit multiple function versions based on +``target_version`` attribute strings, which resolved at runtime depend on their +priority and target features availability. One of the versions is always +( implicitly or explicitly ) the ``default`` (fallback). Attribute strings can +contain dependent features names joined by the "+" sign. +}]; +} + def TargetClonesDocs : Documentation { let Category = DocCatFunction; let Content = [{ @@ -2358,6 +2371,19 @@ based on the priority of their attribute options. All ``target_clone`` functions are considered multiversioned functions. +For AArch64 target: +The attribute contains comma-separated strings of target features joined by "+" +sign. For example: + + .. code-block:: c++ + + __attribute__((target_clones("sha256+mte2", "fcma+sve_bitperm"))) + void foo() {} + +For every multiversioned function a ``default`` (fallback) implementation +always generated if not specified directly. + +For x86/x86-64 targets: All multiversioned functions must contain a ``default`` (fallback) implementation, otherwise usages of the function are considered invalid. Additionally, a function may not become multiversioned after its first use. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3040,8 +3040,8 @@ def warn_unsupported_target_attribute : Warning<"%select{unsupported|duplicate|unknown}0%select{| architecture|" - " tune CPU}1 '%2' in the '%select{target|target_clones}3' " - "attribute string; '%select{target|target_clones}3' " + " tune CPU}1 '%2' in the '%select{target|target_clones|target_version}3' " + "attribute string; '%select{target|target_clones|target_version}3' " "attribute ignored">, InGroup; def err_attribute_unsupported @@ -11420,7 +11420,7 @@ def err_multiversion_required_in_redecl : Error< "function declaration is missing %select{'target'|'cpu_specific' or " - "'cpu_dispatch'}0 attribute in a multiversioned function">; + "'cpu_dispatch'|'target_version'}0 attribute in a multiversioned function">; def note_multiversioning_caused_here : Note< "function multiversioning caused by this declaration">; def err_multiversion_after_used : Error< @@ -11435,7 +11435,7 @@ "multiversioned function must have a prototype">; def err_multiversion_disallowed_other_attr : Error<"attribute " - "'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' " + "'%select{|target|cpu_specific|cpu_dispatch|target_clones|target_version}0' " "multiversioning cannot be combined" " with attribute %1">; def err_multiversion_diff : Error< @@ -11444,7 +11444,7 @@ "language linkage}0">; def err_multiversion_doesnt_support : Error<"attribute " - "'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' " + "'%select{|target|cpu_specific|cpu_dispatch|target_clones|target_version}0' " "multiversioned functions do not " "yet support %select{function templates|virtual functions|" "deduced return types|constructors|destructors|deleted functions|" @@ -11479,6 +11479,9 @@ def warn_target_clone_duplicate_options : Warning<"version list contains duplicate entries">, InGroup; +def warn_target_clone_no_impact_options + : Warning<"version list contains no code impact entries">, + InGroup; // three-way comparison operator diagnostics def err_implied_comparison_category_type_not_found : Error< 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 @@ -1306,6 +1306,10 @@ return true; } + /// Determine where this feature has impact on Target code + /// generation. + virtual bool isCodeImpactFeatureName(StringRef Feature) const { return true; } + struct BranchProtectionInfo { LangOptions::SignReturnAddressScopeKind SignReturnAddr = LangOptions::SignReturnAddressScopeKind::None; @@ -1352,7 +1356,9 @@ /// Identify whether this target supports multiversioning of functions, /// which requires support for cpu_supports and cpu_is functionality. - bool supportsMultiVersioning() const { return getTriple().isX86(); } + bool supportsMultiVersioning() const { + return getTriple().isX86() || getTriple().isAArch64(); + } /// Identify whether this target supports IFuncs. bool supportsIFunc() const { return getTriple().isOSBinFormatELF(); } @@ -1367,6 +1373,10 @@ return 0; } + // Return the target-specific cost for feature + // that taken into account in priority sorting. + virtual unsigned multiVersionFeatureCost() const { return 0; } + // Validate the contents of the __builtin_cpu_is(const char*) // argument. virtual bool validateCpuIs(StringRef Name) const { return false; } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3743,6 +3743,8 @@ def msoft_float : Flag<["-"], "msoft-float">, Group, Flags<[CC1Option]>, HelpText<"Use software floating point">, MarshallingInfoFlag>; +def mno_fmv : Flag<["-"], "mno-fmv">, Group, Flags<[CC1Option]>, + HelpText<"Disable function multiversioning">; def moutline_atomics : Flag<["-"], "moutline-atomics">, Group, Flags<[CC1Option]>, HelpText<"Generate local calls to out-of-line atomic operations">; def mno_outline_atomics : Flag<["-"], "mno-outline-atomics">, Group, Flags<[CC1Option]>, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4465,10 +4465,14 @@ llvm::Error isValidSectionSpecifier(StringRef Str); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); - bool checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, - const StringLiteral *Literal, - bool &HasDefault, bool &HasCommas, - SmallVectorImpl &Strings); + bool checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &Str, + bool &isDefault); + bool + checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, + const StringLiteral *Literal, bool &HasDefault, + bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl &Strings, + SmallVectorImpl> &StringsBuffer); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceModel SemanticSpelling); 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 @@ -12233,6 +12233,20 @@ } } +std::vector ASTContext::filterFunctionTargetVersionAttrs( + const TargetVersionAttr *TV) const { + assert(TV != nullptr); + llvm::SmallVector Feats; + std::vector ResFeats; + TV->getFeatures(Feats); + for (auto &Feature : Feats) { + if (Target->isValidFeatureName(Feature.str())) { + ResFeats.push_back("+" + Feature.str()); + } + } + return ResFeats; +} + ParsedTargetAttr ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const { assert(TD != nullptr); @@ -12292,12 +12306,32 @@ } else if (const auto *TC = FD->getAttr()) { std::vector Features; StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); - if (VersionStr.startswith("arch=")) - TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); - else if (VersionStr != "default") - Features.push_back((StringRef{"+"} + VersionStr).str()); - + if (Target->getTriple().isAArch64()) { + // TargetClones for AArch64 + if (VersionStr != "default") { + SmallVector VersionFeatures; + VersionStr.split(VersionFeatures, "+"); + for (auto &VFeature : VersionFeatures) { + VFeature = VFeature.trim(); + Features.push_back((StringRef{"+"} + VFeature).str()); + } + } + Features.insert(Features.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + } else { + if (VersionStr.startswith("arch=")) + TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); + else if (VersionStr != "default") + Features.push_back((StringRef{"+"} + VersionStr).str()); + } Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); + } else if (const auto *TV = FD->getAttr()) { + std::vector Feats = filterFunctionTargetVersionAttrs(TV); + Feats.insert(Feats.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats); } else { FeatureMap = Target->getTargetOpts().FeatureMap; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3325,6 +3325,8 @@ MultiVersionKind FunctionDecl::getMultiVersionKind() const { if (hasAttr()) return MultiVersionKind::Target; + if (hasAttr()) + return MultiVersionKind::TargetVersion; if (hasAttr()) return MultiVersionKind::CPUDispatch; if (hasAttr()) @@ -3343,7 +3345,8 @@ } bool FunctionDecl::isTargetMultiVersion() const { - return isMultiVersion() && hasAttr(); + return isMultiVersion() && + (hasAttr() || hasAttr()); } bool FunctionDecl::isTargetClonesMultiVersion() const { 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 @@ -54,6 +54,7 @@ bool HasLSE; bool HasFlagM; bool HasMOPS; + bool HasFMV; llvm::AArch64::ArchKind ArchKind; @@ -76,6 +77,14 @@ void fillValidCPUList(SmallVectorImpl &Values) const override; bool setCPU(const std::string &Name) override; + unsigned multiVersionSortPriority(StringRef Name) const override; + unsigned multiVersionFeatureCost() const override; + + bool + initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, + StringRef CPU, + const std::vector &FeaturesVec) const override; + bool useFP16ConversionIntrinsics() const override { return false; } @@ -112,6 +121,9 @@ Optional> getVScaleRange(const LangOptions &LangOpts) const override; + bool isValidFeatureName(StringRef Name) const override; + bool isCodeImpactFeatureName(StringRef Name) const override; + bool validateCpuSupports(StringRef FeatureStr) const override; bool hasFeature(StringRef Feature) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; 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 @@ -341,6 +341,9 @@ if (HasCRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); + if (HasFMV) + Builder.defineMacro("__ARM_FEATURE_FUNCTION_MULTI_VERSIONING", "1"); + // The __ARM_FEATURE_CRYPTO is deprecated in favor of finer grained feature // macros for AES, SHA2, SHA3 and SM4 if (HasAES && HasSHA2) @@ -508,13 +511,77 @@ return None; } +unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const { + if (Name == "default") + return 0; + return llvm::StringSwitch(Name) +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) .Case(NAME, PRIORITY) +#include "llvm/Support/AArch64TargetParser.def" + ; +} + +unsigned AArch64TargetInfo::multiVersionFeatureCost() const { + // Take the maximum priority as per feature cost, + // so more features win. + return multiVersionSortPriority("ls64_accdata"); +} + +bool AArch64TargetInfo::isCodeImpactFeatureName(StringRef Name) const { + std::string FeatureVec = llvm::StringSwitch(Name) +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) .Case(NAME, OPTION) +#include "llvm/Support/AArch64TargetParser.def" + .Default(""); + if (FeatureVec == "") + return false; + return true; +} + +bool AArch64TargetInfo::isValidFeatureName(StringRef Name) const { + return llvm::StringSwitch(Name) +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) .Case(NAME, true) +#include "llvm/Support/AArch64TargetParser.def" + .Default(false); +} + +bool AArch64TargetInfo::validateCpuSupports(StringRef FeatureStr) const { + return llvm::StringSwitch(FeatureStr) +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) .Case(NAME, true) +#include "llvm/Support/AArch64TargetParser.def" + .Default(false); +} + +bool AArch64TargetInfo::initFeatureMap( + llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, + const std::vector &FeaturesVec) const { + + std::vector UpdatedFeaturesVec; + for (const auto &Feature : FeaturesVec) { + std::string FeatureVec = llvm::StringSwitch(Feature.substr(1)) +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) .Case(NAME, OPTION) +#include "llvm/Support/AArch64TargetParser.def" + .Default(""); + if (FeatureVec == "") { + UpdatedFeaturesVec.push_back(Feature); + } else if (FeatureVec != "") { + // Add only supported features + UpdatedFeaturesVec.push_back(FeatureVec); + } + } + + if (!TargetInfo::initFeatureMap(Features, Diags, CPU, UpdatedFeaturesVec)) + return false; + return true; +} + bool AArch64TargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) - .Cases("aarch64", "arm64", "arm", true) - .Case("neon", FPU & NeonMode) - .Cases("sve", "sve2", "sve2-bitperm", "sve2-aes", "sve2-sha3", "sve2-sm4", "f64mm", "f32mm", "i8mm", "bf16", FPU & SveMode) - .Case("ls64", HasLS64) - .Default(false); + .Cases("aarch64", "arm64", "arm", true) + .Case("neon", FPU & NeonMode) + .Cases("sve", "sve2", "sve2-bitperm", "sve2-aes", "sve2-sha3", "sve2-sm4", + "f64mm", "f32mm", "i8mm", "bf16", FPU & SveMode) + .Case("ls64", HasLS64) + .Case("fmv", HasFMV) + .Default(false); } bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, @@ -544,6 +611,7 @@ HasMatmulFP32 = false; HasLSE = false; HasMOPS = false; + HasFMV = true; ArchKind = llvm::AArch64::ArchKind::INVALID; @@ -591,6 +659,9 @@ FPU |= SveMode; HasMatmulFP64 = true; } + if (Feature == "-fmv") { + HasFMV = false; + } if (Feature == "+crc") HasCRC = true; if (Feature == "+aes") diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -50,6 +50,7 @@ #include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/MatrixBuilder.h" +#include "llvm/Support/AArch64TargetParser.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/X86TargetParser.h" @@ -1169,141 +1170,141 @@ switch (BuiltinID) { default: return None; - case ARM::BI_BitScanForward: - case ARM::BI_BitScanForward64: + case clang::ARM::BI_BitScanForward: + case clang::ARM::BI_BitScanForward64: return MSVCIntrin::_BitScanForward; - case ARM::BI_BitScanReverse: - case ARM::BI_BitScanReverse64: + case clang::ARM::BI_BitScanReverse: + case clang::ARM::BI_BitScanReverse64: return MSVCIntrin::_BitScanReverse; - case ARM::BI_InterlockedAnd64: + case clang::ARM::BI_InterlockedAnd64: return MSVCIntrin::_InterlockedAnd; - case ARM::BI_InterlockedExchange64: + case clang::ARM::BI_InterlockedExchange64: return MSVCIntrin::_InterlockedExchange; - case ARM::BI_InterlockedExchangeAdd64: + case clang::ARM::BI_InterlockedExchangeAdd64: return MSVCIntrin::_InterlockedExchangeAdd; - case ARM::BI_InterlockedExchangeSub64: + case clang::ARM::BI_InterlockedExchangeSub64: return MSVCIntrin::_InterlockedExchangeSub; - case ARM::BI_InterlockedOr64: + case clang::ARM::BI_InterlockedOr64: return MSVCIntrin::_InterlockedOr; - case ARM::BI_InterlockedXor64: + case clang::ARM::BI_InterlockedXor64: return MSVCIntrin::_InterlockedXor; - case ARM::BI_InterlockedDecrement64: + case clang::ARM::BI_InterlockedDecrement64: return MSVCIntrin::_InterlockedDecrement; - case ARM::BI_InterlockedIncrement64: + case clang::ARM::BI_InterlockedIncrement64: return MSVCIntrin::_InterlockedIncrement; - case ARM::BI_InterlockedExchangeAdd8_acq: - case ARM::BI_InterlockedExchangeAdd16_acq: - case ARM::BI_InterlockedExchangeAdd_acq: - case ARM::BI_InterlockedExchangeAdd64_acq: + case clang::ARM::BI_InterlockedExchangeAdd8_acq: + case clang::ARM::BI_InterlockedExchangeAdd16_acq: + case clang::ARM::BI_InterlockedExchangeAdd_acq: + case clang::ARM::BI_InterlockedExchangeAdd64_acq: return MSVCIntrin::_InterlockedExchangeAdd_acq; - case ARM::BI_InterlockedExchangeAdd8_rel: - case ARM::BI_InterlockedExchangeAdd16_rel: - case ARM::BI_InterlockedExchangeAdd_rel: - case ARM::BI_InterlockedExchangeAdd64_rel: + case clang::ARM::BI_InterlockedExchangeAdd8_rel: + case clang::ARM::BI_InterlockedExchangeAdd16_rel: + case clang::ARM::BI_InterlockedExchangeAdd_rel: + case clang::ARM::BI_InterlockedExchangeAdd64_rel: return MSVCIntrin::_InterlockedExchangeAdd_rel; - case ARM::BI_InterlockedExchangeAdd8_nf: - case ARM::BI_InterlockedExchangeAdd16_nf: - case ARM::BI_InterlockedExchangeAdd_nf: - case ARM::BI_InterlockedExchangeAdd64_nf: + case clang::ARM::BI_InterlockedExchangeAdd8_nf: + case clang::ARM::BI_InterlockedExchangeAdd16_nf: + case clang::ARM::BI_InterlockedExchangeAdd_nf: + case clang::ARM::BI_InterlockedExchangeAdd64_nf: return MSVCIntrin::_InterlockedExchangeAdd_nf; - case ARM::BI_InterlockedExchange8_acq: - case ARM::BI_InterlockedExchange16_acq: - case ARM::BI_InterlockedExchange_acq: - case ARM::BI_InterlockedExchange64_acq: + case clang::ARM::BI_InterlockedExchange8_acq: + case clang::ARM::BI_InterlockedExchange16_acq: + case clang::ARM::BI_InterlockedExchange_acq: + case clang::ARM::BI_InterlockedExchange64_acq: return MSVCIntrin::_InterlockedExchange_acq; - case ARM::BI_InterlockedExchange8_rel: - case ARM::BI_InterlockedExchange16_rel: - case ARM::BI_InterlockedExchange_rel: - case ARM::BI_InterlockedExchange64_rel: + case clang::ARM::BI_InterlockedExchange8_rel: + case clang::ARM::BI_InterlockedExchange16_rel: + case clang::ARM::BI_InterlockedExchange_rel: + case clang::ARM::BI_InterlockedExchange64_rel: return MSVCIntrin::_InterlockedExchange_rel; - case ARM::BI_InterlockedExchange8_nf: - case ARM::BI_InterlockedExchange16_nf: - case ARM::BI_InterlockedExchange_nf: - case ARM::BI_InterlockedExchange64_nf: + case clang::ARM::BI_InterlockedExchange8_nf: + case clang::ARM::BI_InterlockedExchange16_nf: + case clang::ARM::BI_InterlockedExchange_nf: + case clang::ARM::BI_InterlockedExchange64_nf: return MSVCIntrin::_InterlockedExchange_nf; - case ARM::BI_InterlockedCompareExchange8_acq: - case ARM::BI_InterlockedCompareExchange16_acq: - case ARM::BI_InterlockedCompareExchange_acq: - case ARM::BI_InterlockedCompareExchange64_acq: + case clang::ARM::BI_InterlockedCompareExchange8_acq: + case clang::ARM::BI_InterlockedCompareExchange16_acq: + case clang::ARM::BI_InterlockedCompareExchange_acq: + case clang::ARM::BI_InterlockedCompareExchange64_acq: return MSVCIntrin::_InterlockedCompareExchange_acq; - case ARM::BI_InterlockedCompareExchange8_rel: - case ARM::BI_InterlockedCompareExchange16_rel: - case ARM::BI_InterlockedCompareExchange_rel: - case ARM::BI_InterlockedCompareExchange64_rel: + case clang::ARM::BI_InterlockedCompareExchange8_rel: + case clang::ARM::BI_InterlockedCompareExchange16_rel: + case clang::ARM::BI_InterlockedCompareExchange_rel: + case clang::ARM::BI_InterlockedCompareExchange64_rel: return MSVCIntrin::_InterlockedCompareExchange_rel; - case ARM::BI_InterlockedCompareExchange8_nf: - case ARM::BI_InterlockedCompareExchange16_nf: - case ARM::BI_InterlockedCompareExchange_nf: - case ARM::BI_InterlockedCompareExchange64_nf: + case clang::ARM::BI_InterlockedCompareExchange8_nf: + case clang::ARM::BI_InterlockedCompareExchange16_nf: + case clang::ARM::BI_InterlockedCompareExchange_nf: + case clang::ARM::BI_InterlockedCompareExchange64_nf: return MSVCIntrin::_InterlockedCompareExchange_nf; - case ARM::BI_InterlockedOr8_acq: - case ARM::BI_InterlockedOr16_acq: - case ARM::BI_InterlockedOr_acq: - case ARM::BI_InterlockedOr64_acq: + case clang::ARM::BI_InterlockedOr8_acq: + case clang::ARM::BI_InterlockedOr16_acq: + case clang::ARM::BI_InterlockedOr_acq: + case clang::ARM::BI_InterlockedOr64_acq: return MSVCIntrin::_InterlockedOr_acq; - case ARM::BI_InterlockedOr8_rel: - case ARM::BI_InterlockedOr16_rel: - case ARM::BI_InterlockedOr_rel: - case ARM::BI_InterlockedOr64_rel: + case clang::ARM::BI_InterlockedOr8_rel: + case clang::ARM::BI_InterlockedOr16_rel: + case clang::ARM::BI_InterlockedOr_rel: + case clang::ARM::BI_InterlockedOr64_rel: return MSVCIntrin::_InterlockedOr_rel; - case ARM::BI_InterlockedOr8_nf: - case ARM::BI_InterlockedOr16_nf: - case ARM::BI_InterlockedOr_nf: - case ARM::BI_InterlockedOr64_nf: + case clang::ARM::BI_InterlockedOr8_nf: + case clang::ARM::BI_InterlockedOr16_nf: + case clang::ARM::BI_InterlockedOr_nf: + case clang::ARM::BI_InterlockedOr64_nf: return MSVCIntrin::_InterlockedOr_nf; - case ARM::BI_InterlockedXor8_acq: - case ARM::BI_InterlockedXor16_acq: - case ARM::BI_InterlockedXor_acq: - case ARM::BI_InterlockedXor64_acq: + case clang::ARM::BI_InterlockedXor8_acq: + case clang::ARM::BI_InterlockedXor16_acq: + case clang::ARM::BI_InterlockedXor_acq: + case clang::ARM::BI_InterlockedXor64_acq: return MSVCIntrin::_InterlockedXor_acq; - case ARM::BI_InterlockedXor8_rel: - case ARM::BI_InterlockedXor16_rel: - case ARM::BI_InterlockedXor_rel: - case ARM::BI_InterlockedXor64_rel: + case clang::ARM::BI_InterlockedXor8_rel: + case clang::ARM::BI_InterlockedXor16_rel: + case clang::ARM::BI_InterlockedXor_rel: + case clang::ARM::BI_InterlockedXor64_rel: return MSVCIntrin::_InterlockedXor_rel; - case ARM::BI_InterlockedXor8_nf: - case ARM::BI_InterlockedXor16_nf: - case ARM::BI_InterlockedXor_nf: - case ARM::BI_InterlockedXor64_nf: + case clang::ARM::BI_InterlockedXor8_nf: + case clang::ARM::BI_InterlockedXor16_nf: + case clang::ARM::BI_InterlockedXor_nf: + case clang::ARM::BI_InterlockedXor64_nf: return MSVCIntrin::_InterlockedXor_nf; - case ARM::BI_InterlockedAnd8_acq: - case ARM::BI_InterlockedAnd16_acq: - case ARM::BI_InterlockedAnd_acq: - case ARM::BI_InterlockedAnd64_acq: + case clang::ARM::BI_InterlockedAnd8_acq: + case clang::ARM::BI_InterlockedAnd16_acq: + case clang::ARM::BI_InterlockedAnd_acq: + case clang::ARM::BI_InterlockedAnd64_acq: return MSVCIntrin::_InterlockedAnd_acq; - case ARM::BI_InterlockedAnd8_rel: - case ARM::BI_InterlockedAnd16_rel: - case ARM::BI_InterlockedAnd_rel: - case ARM::BI_InterlockedAnd64_rel: + case clang::ARM::BI_InterlockedAnd8_rel: + case clang::ARM::BI_InterlockedAnd16_rel: + case clang::ARM::BI_InterlockedAnd_rel: + case clang::ARM::BI_InterlockedAnd64_rel: return MSVCIntrin::_InterlockedAnd_rel; - case ARM::BI_InterlockedAnd8_nf: - case ARM::BI_InterlockedAnd16_nf: - case ARM::BI_InterlockedAnd_nf: - case ARM::BI_InterlockedAnd64_nf: + case clang::ARM::BI_InterlockedAnd8_nf: + case clang::ARM::BI_InterlockedAnd16_nf: + case clang::ARM::BI_InterlockedAnd_nf: + case clang::ARM::BI_InterlockedAnd64_nf: return MSVCIntrin::_InterlockedAnd_nf; - case ARM::BI_InterlockedIncrement16_acq: - case ARM::BI_InterlockedIncrement_acq: - case ARM::BI_InterlockedIncrement64_acq: + case clang::ARM::BI_InterlockedIncrement16_acq: + case clang::ARM::BI_InterlockedIncrement_acq: + case clang::ARM::BI_InterlockedIncrement64_acq: return MSVCIntrin::_InterlockedIncrement_acq; - case ARM::BI_InterlockedIncrement16_rel: - case ARM::BI_InterlockedIncrement_rel: - case ARM::BI_InterlockedIncrement64_rel: + case clang::ARM::BI_InterlockedIncrement16_rel: + case clang::ARM::BI_InterlockedIncrement_rel: + case clang::ARM::BI_InterlockedIncrement64_rel: return MSVCIntrin::_InterlockedIncrement_rel; - case ARM::BI_InterlockedIncrement16_nf: - case ARM::BI_InterlockedIncrement_nf: - case ARM::BI_InterlockedIncrement64_nf: + case clang::ARM::BI_InterlockedIncrement16_nf: + case clang::ARM::BI_InterlockedIncrement_nf: + case clang::ARM::BI_InterlockedIncrement64_nf: return MSVCIntrin::_InterlockedIncrement_nf; - case ARM::BI_InterlockedDecrement16_acq: - case ARM::BI_InterlockedDecrement_acq: - case ARM::BI_InterlockedDecrement64_acq: + case clang::ARM::BI_InterlockedDecrement16_acq: + case clang::ARM::BI_InterlockedDecrement_acq: + case clang::ARM::BI_InterlockedDecrement64_acq: return MSVCIntrin::_InterlockedDecrement_acq; - case ARM::BI_InterlockedDecrement16_rel: - case ARM::BI_InterlockedDecrement_rel: - case ARM::BI_InterlockedDecrement64_rel: + case clang::ARM::BI_InterlockedDecrement16_rel: + case clang::ARM::BI_InterlockedDecrement_rel: + case clang::ARM::BI_InterlockedDecrement64_rel: return MSVCIntrin::_InterlockedDecrement_rel; - case ARM::BI_InterlockedDecrement16_nf: - case ARM::BI_InterlockedDecrement_nf: - case ARM::BI_InterlockedDecrement64_nf: + case clang::ARM::BI_InterlockedDecrement16_nf: + case clang::ARM::BI_InterlockedDecrement_nf: + case clang::ARM::BI_InterlockedDecrement64_nf: return MSVCIntrin::_InterlockedDecrement_nf; } llvm_unreachable("must return from switch"); @@ -1315,149 +1316,149 @@ switch (BuiltinID) { default: return None; - case AArch64::BI_BitScanForward: - case AArch64::BI_BitScanForward64: + case clang::AArch64::BI_BitScanForward: + case clang::AArch64::BI_BitScanForward64: return MSVCIntrin::_BitScanForward; - case AArch64::BI_BitScanReverse: - case AArch64::BI_BitScanReverse64: + case clang::AArch64::BI_BitScanReverse: + case clang::AArch64::BI_BitScanReverse64: return MSVCIntrin::_BitScanReverse; - case AArch64::BI_InterlockedAnd64: + case clang::AArch64::BI_InterlockedAnd64: return MSVCIntrin::_InterlockedAnd; - case AArch64::BI_InterlockedExchange64: + case clang::AArch64::BI_InterlockedExchange64: return MSVCIntrin::_InterlockedExchange; - case AArch64::BI_InterlockedExchangeAdd64: + case clang::AArch64::BI_InterlockedExchangeAdd64: return MSVCIntrin::_InterlockedExchangeAdd; - case AArch64::BI_InterlockedExchangeSub64: + case clang::AArch64::BI_InterlockedExchangeSub64: return MSVCIntrin::_InterlockedExchangeSub; - case AArch64::BI_InterlockedOr64: + case clang::AArch64::BI_InterlockedOr64: return MSVCIntrin::_InterlockedOr; - case AArch64::BI_InterlockedXor64: + case clang::AArch64::BI_InterlockedXor64: return MSVCIntrin::_InterlockedXor; - case AArch64::BI_InterlockedDecrement64: + case clang::AArch64::BI_InterlockedDecrement64: return MSVCIntrin::_InterlockedDecrement; - case AArch64::BI_InterlockedIncrement64: + case clang::AArch64::BI_InterlockedIncrement64: return MSVCIntrin::_InterlockedIncrement; - case AArch64::BI_InterlockedExchangeAdd8_acq: - case AArch64::BI_InterlockedExchangeAdd16_acq: - case AArch64::BI_InterlockedExchangeAdd_acq: - case AArch64::BI_InterlockedExchangeAdd64_acq: + case clang::AArch64::BI_InterlockedExchangeAdd8_acq: + case clang::AArch64::BI_InterlockedExchangeAdd16_acq: + case clang::AArch64::BI_InterlockedExchangeAdd_acq: + case clang::AArch64::BI_InterlockedExchangeAdd64_acq: return MSVCIntrin::_InterlockedExchangeAdd_acq; - case AArch64::BI_InterlockedExchangeAdd8_rel: - case AArch64::BI_InterlockedExchangeAdd16_rel: - case AArch64::BI_InterlockedExchangeAdd_rel: - case AArch64::BI_InterlockedExchangeAdd64_rel: + case clang::AArch64::BI_InterlockedExchangeAdd8_rel: + case clang::AArch64::BI_InterlockedExchangeAdd16_rel: + case clang::AArch64::BI_InterlockedExchangeAdd_rel: + case clang::AArch64::BI_InterlockedExchangeAdd64_rel: return MSVCIntrin::_InterlockedExchangeAdd_rel; - case AArch64::BI_InterlockedExchangeAdd8_nf: - case AArch64::BI_InterlockedExchangeAdd16_nf: - case AArch64::BI_InterlockedExchangeAdd_nf: - case AArch64::BI_InterlockedExchangeAdd64_nf: + case clang::AArch64::BI_InterlockedExchangeAdd8_nf: + case clang::AArch64::BI_InterlockedExchangeAdd16_nf: + case clang::AArch64::BI_InterlockedExchangeAdd_nf: + case clang::AArch64::BI_InterlockedExchangeAdd64_nf: return MSVCIntrin::_InterlockedExchangeAdd_nf; - case AArch64::BI_InterlockedExchange8_acq: - case AArch64::BI_InterlockedExchange16_acq: - case AArch64::BI_InterlockedExchange_acq: - case AArch64::BI_InterlockedExchange64_acq: + case clang::AArch64::BI_InterlockedExchange8_acq: + case clang::AArch64::BI_InterlockedExchange16_acq: + case clang::AArch64::BI_InterlockedExchange_acq: + case clang::AArch64::BI_InterlockedExchange64_acq: return MSVCIntrin::_InterlockedExchange_acq; - case AArch64::BI_InterlockedExchange8_rel: - case AArch64::BI_InterlockedExchange16_rel: - case AArch64::BI_InterlockedExchange_rel: - case AArch64::BI_InterlockedExchange64_rel: + case clang::AArch64::BI_InterlockedExchange8_rel: + case clang::AArch64::BI_InterlockedExchange16_rel: + case clang::AArch64::BI_InterlockedExchange_rel: + case clang::AArch64::BI_InterlockedExchange64_rel: return MSVCIntrin::_InterlockedExchange_rel; - case AArch64::BI_InterlockedExchange8_nf: - case AArch64::BI_InterlockedExchange16_nf: - case AArch64::BI_InterlockedExchange_nf: - case AArch64::BI_InterlockedExchange64_nf: + case clang::AArch64::BI_InterlockedExchange8_nf: + case clang::AArch64::BI_InterlockedExchange16_nf: + case clang::AArch64::BI_InterlockedExchange_nf: + case clang::AArch64::BI_InterlockedExchange64_nf: return MSVCIntrin::_InterlockedExchange_nf; - case AArch64::BI_InterlockedCompareExchange8_acq: - case AArch64::BI_InterlockedCompareExchange16_acq: - case AArch64::BI_InterlockedCompareExchange_acq: - case AArch64::BI_InterlockedCompareExchange64_acq: + case clang::AArch64::BI_InterlockedCompareExchange8_acq: + case clang::AArch64::BI_InterlockedCompareExchange16_acq: + case clang::AArch64::BI_InterlockedCompareExchange_acq: + case clang::AArch64::BI_InterlockedCompareExchange64_acq: return MSVCIntrin::_InterlockedCompareExchange_acq; - case AArch64::BI_InterlockedCompareExchange8_rel: - case AArch64::BI_InterlockedCompareExchange16_rel: - case AArch64::BI_InterlockedCompareExchange_rel: - case AArch64::BI_InterlockedCompareExchange64_rel: + case clang::AArch64::BI_InterlockedCompareExchange8_rel: + case clang::AArch64::BI_InterlockedCompareExchange16_rel: + case clang::AArch64::BI_InterlockedCompareExchange_rel: + case clang::AArch64::BI_InterlockedCompareExchange64_rel: return MSVCIntrin::_InterlockedCompareExchange_rel; - case AArch64::BI_InterlockedCompareExchange8_nf: - case AArch64::BI_InterlockedCompareExchange16_nf: - case AArch64::BI_InterlockedCompareExchange_nf: - case AArch64::BI_InterlockedCompareExchange64_nf: + case clang::AArch64::BI_InterlockedCompareExchange8_nf: + case clang::AArch64::BI_InterlockedCompareExchange16_nf: + case clang::AArch64::BI_InterlockedCompareExchange_nf: + case clang::AArch64::BI_InterlockedCompareExchange64_nf: return MSVCIntrin::_InterlockedCompareExchange_nf; - case AArch64::BI_InterlockedCompareExchange128: + case clang::AArch64::BI_InterlockedCompareExchange128: return MSVCIntrin::_InterlockedCompareExchange128; - case AArch64::BI_InterlockedCompareExchange128_acq: + case clang::AArch64::BI_InterlockedCompareExchange128_acq: return MSVCIntrin::_InterlockedCompareExchange128_acq; - case AArch64::BI_InterlockedCompareExchange128_nf: + case clang::AArch64::BI_InterlockedCompareExchange128_nf: return MSVCIntrin::_InterlockedCompareExchange128_nf; - case AArch64::BI_InterlockedCompareExchange128_rel: + case clang::AArch64::BI_InterlockedCompareExchange128_rel: return MSVCIntrin::_InterlockedCompareExchange128_rel; - case AArch64::BI_InterlockedOr8_acq: - case AArch64::BI_InterlockedOr16_acq: - case AArch64::BI_InterlockedOr_acq: - case AArch64::BI_InterlockedOr64_acq: + case clang::AArch64::BI_InterlockedOr8_acq: + case clang::AArch64::BI_InterlockedOr16_acq: + case clang::AArch64::BI_InterlockedOr_acq: + case clang::AArch64::BI_InterlockedOr64_acq: return MSVCIntrin::_InterlockedOr_acq; - case AArch64::BI_InterlockedOr8_rel: - case AArch64::BI_InterlockedOr16_rel: - case AArch64::BI_InterlockedOr_rel: - case AArch64::BI_InterlockedOr64_rel: + case clang::AArch64::BI_InterlockedOr8_rel: + case clang::AArch64::BI_InterlockedOr16_rel: + case clang::AArch64::BI_InterlockedOr_rel: + case clang::AArch64::BI_InterlockedOr64_rel: return MSVCIntrin::_InterlockedOr_rel; - case AArch64::BI_InterlockedOr8_nf: - case AArch64::BI_InterlockedOr16_nf: - case AArch64::BI_InterlockedOr_nf: - case AArch64::BI_InterlockedOr64_nf: + case clang::AArch64::BI_InterlockedOr8_nf: + case clang::AArch64::BI_InterlockedOr16_nf: + case clang::AArch64::BI_InterlockedOr_nf: + case clang::AArch64::BI_InterlockedOr64_nf: return MSVCIntrin::_InterlockedOr_nf; - case AArch64::BI_InterlockedXor8_acq: - case AArch64::BI_InterlockedXor16_acq: - case AArch64::BI_InterlockedXor_acq: - case AArch64::BI_InterlockedXor64_acq: + case clang::AArch64::BI_InterlockedXor8_acq: + case clang::AArch64::BI_InterlockedXor16_acq: + case clang::AArch64::BI_InterlockedXor_acq: + case clang::AArch64::BI_InterlockedXor64_acq: return MSVCIntrin::_InterlockedXor_acq; - case AArch64::BI_InterlockedXor8_rel: - case AArch64::BI_InterlockedXor16_rel: - case AArch64::BI_InterlockedXor_rel: - case AArch64::BI_InterlockedXor64_rel: + case clang::AArch64::BI_InterlockedXor8_rel: + case clang::AArch64::BI_InterlockedXor16_rel: + case clang::AArch64::BI_InterlockedXor_rel: + case clang::AArch64::BI_InterlockedXor64_rel: return MSVCIntrin::_InterlockedXor_rel; - case AArch64::BI_InterlockedXor8_nf: - case AArch64::BI_InterlockedXor16_nf: - case AArch64::BI_InterlockedXor_nf: - case AArch64::BI_InterlockedXor64_nf: + case clang::AArch64::BI_InterlockedXor8_nf: + case clang::AArch64::BI_InterlockedXor16_nf: + case clang::AArch64::BI_InterlockedXor_nf: + case clang::AArch64::BI_InterlockedXor64_nf: return MSVCIntrin::_InterlockedXor_nf; - case AArch64::BI_InterlockedAnd8_acq: - case AArch64::BI_InterlockedAnd16_acq: - case AArch64::BI_InterlockedAnd_acq: - case AArch64::BI_InterlockedAnd64_acq: + case clang::AArch64::BI_InterlockedAnd8_acq: + case clang::AArch64::BI_InterlockedAnd16_acq: + case clang::AArch64::BI_InterlockedAnd_acq: + case clang::AArch64::BI_InterlockedAnd64_acq: return MSVCIntrin::_InterlockedAnd_acq; - case AArch64::BI_InterlockedAnd8_rel: - case AArch64::BI_InterlockedAnd16_rel: - case AArch64::BI_InterlockedAnd_rel: - case AArch64::BI_InterlockedAnd64_rel: + case clang::AArch64::BI_InterlockedAnd8_rel: + case clang::AArch64::BI_InterlockedAnd16_rel: + case clang::AArch64::BI_InterlockedAnd_rel: + case clang::AArch64::BI_InterlockedAnd64_rel: return MSVCIntrin::_InterlockedAnd_rel; - case AArch64::BI_InterlockedAnd8_nf: - case AArch64::BI_InterlockedAnd16_nf: - case AArch64::BI_InterlockedAnd_nf: - case AArch64::BI_InterlockedAnd64_nf: + case clang::AArch64::BI_InterlockedAnd8_nf: + case clang::AArch64::BI_InterlockedAnd16_nf: + case clang::AArch64::BI_InterlockedAnd_nf: + case clang::AArch64::BI_InterlockedAnd64_nf: return MSVCIntrin::_InterlockedAnd_nf; - case AArch64::BI_InterlockedIncrement16_acq: - case AArch64::BI_InterlockedIncrement_acq: - case AArch64::BI_InterlockedIncrement64_acq: + case clang::AArch64::BI_InterlockedIncrement16_acq: + case clang::AArch64::BI_InterlockedIncrement_acq: + case clang::AArch64::BI_InterlockedIncrement64_acq: return MSVCIntrin::_InterlockedIncrement_acq; - case AArch64::BI_InterlockedIncrement16_rel: - case AArch64::BI_InterlockedIncrement_rel: - case AArch64::BI_InterlockedIncrement64_rel: + case clang::AArch64::BI_InterlockedIncrement16_rel: + case clang::AArch64::BI_InterlockedIncrement_rel: + case clang::AArch64::BI_InterlockedIncrement64_rel: return MSVCIntrin::_InterlockedIncrement_rel; - case AArch64::BI_InterlockedIncrement16_nf: - case AArch64::BI_InterlockedIncrement_nf: - case AArch64::BI_InterlockedIncrement64_nf: + case clang::AArch64::BI_InterlockedIncrement16_nf: + case clang::AArch64::BI_InterlockedIncrement_nf: + case clang::AArch64::BI_InterlockedIncrement64_nf: return MSVCIntrin::_InterlockedIncrement_nf; - case AArch64::BI_InterlockedDecrement16_acq: - case AArch64::BI_InterlockedDecrement_acq: - case AArch64::BI_InterlockedDecrement64_acq: + case clang::AArch64::BI_InterlockedDecrement16_acq: + case clang::AArch64::BI_InterlockedDecrement_acq: + case clang::AArch64::BI_InterlockedDecrement64_acq: return MSVCIntrin::_InterlockedDecrement_acq; - case AArch64::BI_InterlockedDecrement16_rel: - case AArch64::BI_InterlockedDecrement_rel: - case AArch64::BI_InterlockedDecrement64_rel: + case clang::AArch64::BI_InterlockedDecrement16_rel: + case clang::AArch64::BI_InterlockedDecrement_rel: + case clang::AArch64::BI_InterlockedDecrement64_rel: return MSVCIntrin::_InterlockedDecrement_rel; - case AArch64::BI_InterlockedDecrement16_nf: - case AArch64::BI_InterlockedDecrement_nf: - case AArch64::BI_InterlockedDecrement64_nf: + case clang::AArch64::BI_InterlockedDecrement16_nf: + case clang::AArch64::BI_InterlockedDecrement_nf: + case clang::AArch64::BI_InterlockedDecrement64_nf: return MSVCIntrin::_InterlockedDecrement_nf; } llvm_unreachable("must return from switch"); @@ -7309,27 +7310,27 @@ switch (BuiltinID) { default: return nullptr; - case ARM::BI__builtin_arm_nop: + case clang::ARM::BI__builtin_arm_nop: Value = 0; break; - case ARM::BI__builtin_arm_yield: - case ARM::BI__yield: + case clang::ARM::BI__builtin_arm_yield: + case clang::ARM::BI__yield: Value = 1; break; - case ARM::BI__builtin_arm_wfe: - case ARM::BI__wfe: + case clang::ARM::BI__builtin_arm_wfe: + case clang::ARM::BI__wfe: Value = 2; break; - case ARM::BI__builtin_arm_wfi: - case ARM::BI__wfi: + case clang::ARM::BI__builtin_arm_wfi: + case clang::ARM::BI__wfi: Value = 3; break; - case ARM::BI__builtin_arm_sev: - case ARM::BI__sev: + case clang::ARM::BI__builtin_arm_sev: + case clang::ARM::BI__sev: Value = 4; break; - case ARM::BI__builtin_arm_sevl: - case ARM::BI__sevl: + case clang::ARM::BI__builtin_arm_sevl: + case clang::ARM::BI__sevl: Value = 5; break; } @@ -7462,7 +7463,7 @@ if (auto Hint = GetValueForARMHint(BuiltinID)) return Hint; - if (BuiltinID == ARM::BI__emit) { + if (BuiltinID == clang::ARM::BI__emit) { bool IsThumb = getTarget().getTriple().getArch() == llvm::Triple::thumb; llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, /*Variadic=*/false); @@ -7483,12 +7484,12 @@ return Builder.CreateCall(Emit); } - if (BuiltinID == ARM::BI__builtin_arm_dbg) { + if (BuiltinID == clang::ARM::BI__builtin_arm_dbg) { Value *Option = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_dbg), Option); } - if (BuiltinID == ARM::BI__builtin_arm_prefetch) { + if (BuiltinID == clang::ARM::BI__builtin_arm_prefetch) { Value *Address = EmitScalarExpr(E->getArg(0)); Value *RW = EmitScalarExpr(E->getArg(1)); Value *IsData = EmitScalarExpr(E->getArg(2)); @@ -7500,23 +7501,23 @@ return Builder.CreateCall(F, {Address, RW, Locality, IsData}); } - if (BuiltinID == ARM::BI__builtin_arm_rbit) { + if (BuiltinID == clang::ARM::BI__builtin_arm_rbit) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall( CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit"); } - if (BuiltinID == ARM::BI__builtin_arm_cls) { + if (BuiltinID == clang::ARM::BI__builtin_arm_cls) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_cls), Arg, "cls"); } - if (BuiltinID == ARM::BI__builtin_arm_cls64) { + if (BuiltinID == clang::ARM::BI__builtin_arm_cls64) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_cls64), Arg, "cls"); } - if (BuiltinID == ARM::BI__clear_cache) { + if (BuiltinID == clang::ARM::BI__clear_cache) { assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments"); const FunctionDecl *FD = E->getDirectCallee(); Value *Ops[2]; @@ -7528,16 +7529,16 @@ return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops); } - if (BuiltinID == ARM::BI__builtin_arm_mcrr || - BuiltinID == ARM::BI__builtin_arm_mcrr2) { + if (BuiltinID == clang::ARM::BI__builtin_arm_mcrr || + BuiltinID == clang::ARM::BI__builtin_arm_mcrr2) { Function *F; switch (BuiltinID) { default: llvm_unreachable("unexpected builtin"); - case ARM::BI__builtin_arm_mcrr: + case clang::ARM::BI__builtin_arm_mcrr: F = CGM.getIntrinsic(Intrinsic::arm_mcrr); break; - case ARM::BI__builtin_arm_mcrr2: + case clang::ARM::BI__builtin_arm_mcrr2: F = CGM.getIntrinsic(Intrinsic::arm_mcrr2); break; } @@ -7562,16 +7563,16 @@ return Builder.CreateCall(F, {Coproc, Opc1, Rt, Rt2, CRm}); } - if (BuiltinID == ARM::BI__builtin_arm_mrrc || - BuiltinID == ARM::BI__builtin_arm_mrrc2) { + if (BuiltinID == clang::ARM::BI__builtin_arm_mrrc || + BuiltinID == clang::ARM::BI__builtin_arm_mrrc2) { Function *F; switch (BuiltinID) { default: llvm_unreachable("unexpected builtin"); - case ARM::BI__builtin_arm_mrrc: + case clang::ARM::BI__builtin_arm_mrrc: F = CGM.getIntrinsic(Intrinsic::arm_mrrc); break; - case ARM::BI__builtin_arm_mrrc2: + case clang::ARM::BI__builtin_arm_mrrc2: F = CGM.getIntrinsic(Intrinsic::arm_mrrc2); break; } @@ -7596,21 +7597,21 @@ return Builder.CreateBitCast(RtAndRt2, ConvertType(E->getType())); } - if (BuiltinID == ARM::BI__builtin_arm_ldrexd || - ((BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex) && + if (BuiltinID == clang::ARM::BI__builtin_arm_ldrexd || + ((BuiltinID == clang::ARM::BI__builtin_arm_ldrex || + BuiltinID == clang::ARM::BI__builtin_arm_ldaex) && getContext().getTypeSize(E->getType()) == 64) || - BuiltinID == ARM::BI__ldrexd) { + BuiltinID == clang::ARM::BI__ldrexd) { Function *F; switch (BuiltinID) { default: llvm_unreachable("unexpected builtin"); - case ARM::BI__builtin_arm_ldaex: + case clang::ARM::BI__builtin_arm_ldaex: F = CGM.getIntrinsic(Intrinsic::arm_ldaexd); break; - case ARM::BI__builtin_arm_ldrexd: - case ARM::BI__builtin_arm_ldrex: - case ARM::BI__ldrexd: + case clang::ARM::BI__builtin_arm_ldrexd: + case clang::ARM::BI__builtin_arm_ldrex: + case clang::ARM::BI__ldrexd: F = CGM.getIntrinsic(Intrinsic::arm_ldrexd); break; } @@ -7630,8 +7631,8 @@ return Builder.CreateBitCast(Val, ConvertType(E->getType())); } - if (BuiltinID == ARM::BI__builtin_arm_ldrex || - BuiltinID == ARM::BI__builtin_arm_ldaex) { + if (BuiltinID == clang::ARM::BI__builtin_arm_ldrex || + BuiltinID == clang::ARM::BI__builtin_arm_ldaex) { Value *LoadAddr = EmitScalarExpr(E->getArg(0)); QualType Ty = E->getType(); @@ -7641,10 +7642,10 @@ llvm::Type *PtrTy = IntTy->getPointerTo(); LoadAddr = Builder.CreateBitCast(LoadAddr, PtrTy); - Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_ldaex - ? Intrinsic::arm_ldaex - : Intrinsic::arm_ldrex, - PtrTy); + Function *F = CGM.getIntrinsic( + BuiltinID == clang::ARM::BI__builtin_arm_ldaex ? Intrinsic::arm_ldaex + : Intrinsic::arm_ldrex, + PtrTy); CallInst *Val = Builder.CreateCall(F, LoadAddr, "ldrex"); Val->addParamAttr( 0, Attribute::get(getLLVMContext(), Attribute::ElementType, IntTy)); @@ -7659,13 +7660,13 @@ } } - if (BuiltinID == ARM::BI__builtin_arm_strexd || - ((BuiltinID == ARM::BI__builtin_arm_stlex || - BuiltinID == ARM::BI__builtin_arm_strex) && + if (BuiltinID == clang::ARM::BI__builtin_arm_strexd || + ((BuiltinID == clang::ARM::BI__builtin_arm_stlex || + BuiltinID == clang::ARM::BI__builtin_arm_strex) && getContext().getTypeSize(E->getArg(0)->getType()) == 64)) { - Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex - ? Intrinsic::arm_stlexd - : Intrinsic::arm_strexd); + Function *F = CGM.getIntrinsic( + BuiltinID == clang::ARM::BI__builtin_arm_stlex ? Intrinsic::arm_stlexd + : Intrinsic::arm_strexd); llvm::Type *STy = llvm::StructType::get(Int32Ty, Int32Ty); Address Tmp = CreateMemTemp(E->getArg(0)->getType()); @@ -7681,8 +7682,8 @@ return Builder.CreateCall(F, {Arg0, Arg1, StPtr}, "strexd"); } - if (BuiltinID == ARM::BI__builtin_arm_strex || - BuiltinID == ARM::BI__builtin_arm_stlex) { + if (BuiltinID == clang::ARM::BI__builtin_arm_strex || + BuiltinID == clang::ARM::BI__builtin_arm_stlex) { Value *StoreVal = EmitScalarExpr(E->getArg(0)); Value *StoreAddr = EmitScalarExpr(E->getArg(1)); @@ -7701,10 +7702,10 @@ StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int32Ty); } - Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI__builtin_arm_stlex - ? Intrinsic::arm_stlex - : Intrinsic::arm_strex, - StoreAddr->getType()); + Function *F = CGM.getIntrinsic( + BuiltinID == clang::ARM::BI__builtin_arm_stlex ? Intrinsic::arm_stlex + : Intrinsic::arm_strex, + StoreAddr->getType()); CallInst *CI = Builder.CreateCall(F, {StoreVal, StoreAddr}, "strex"); CI->addParamAttr( @@ -7712,7 +7713,7 @@ return CI; } - if (BuiltinID == ARM::BI__builtin_arm_clrex) { + if (BuiltinID == clang::ARM::BI__builtin_arm_clrex) { Function *F = CGM.getIntrinsic(Intrinsic::arm_clrex); return Builder.CreateCall(F); } @@ -7720,19 +7721,19 @@ // CRC32 Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic; switch (BuiltinID) { - case ARM::BI__builtin_arm_crc32b: + case clang::ARM::BI__builtin_arm_crc32b: CRCIntrinsicID = Intrinsic::arm_crc32b; break; - case ARM::BI__builtin_arm_crc32cb: + case clang::ARM::BI__builtin_arm_crc32cb: CRCIntrinsicID = Intrinsic::arm_crc32cb; break; - case ARM::BI__builtin_arm_crc32h: + case clang::ARM::BI__builtin_arm_crc32h: CRCIntrinsicID = Intrinsic::arm_crc32h; break; - case ARM::BI__builtin_arm_crc32ch: + case clang::ARM::BI__builtin_arm_crc32ch: CRCIntrinsicID = Intrinsic::arm_crc32ch; break; - case ARM::BI__builtin_arm_crc32w: - case ARM::BI__builtin_arm_crc32d: + case clang::ARM::BI__builtin_arm_crc32w: + case clang::ARM::BI__builtin_arm_crc32d: CRCIntrinsicID = Intrinsic::arm_crc32w; break; - case ARM::BI__builtin_arm_crc32cw: - case ARM::BI__builtin_arm_crc32cd: + case clang::ARM::BI__builtin_arm_crc32cw: + case clang::ARM::BI__builtin_arm_crc32cd: CRCIntrinsicID = Intrinsic::arm_crc32cw; break; } @@ -7742,8 +7743,8 @@ // crc32{c,}d intrinsics are implemnted as two calls to crc32{c,}w // intrinsics, hence we need different codegen for these cases. - if (BuiltinID == ARM::BI__builtin_arm_crc32d || - BuiltinID == ARM::BI__builtin_arm_crc32cd) { + if (BuiltinID == clang::ARM::BI__builtin_arm_crc32d || + BuiltinID == clang::ARM::BI__builtin_arm_crc32cd) { Value *C1 = llvm::ConstantInt::get(Int64Ty, 32); Value *Arg1a = Builder.CreateTruncOrBitCast(Arg1, Int32Ty); Value *Arg1b = Builder.CreateLShr(Arg1, C1); @@ -7760,24 +7761,24 @@ } } - if (BuiltinID == ARM::BI__builtin_arm_rsr || - BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_rsrp || - BuiltinID == ARM::BI__builtin_arm_wsr || - BuiltinID == ARM::BI__builtin_arm_wsr64 || - BuiltinID == ARM::BI__builtin_arm_wsrp) { + if (BuiltinID == clang::ARM::BI__builtin_arm_rsr || + BuiltinID == clang::ARM::BI__builtin_arm_rsr64 || + BuiltinID == clang::ARM::BI__builtin_arm_rsrp || + BuiltinID == clang::ARM::BI__builtin_arm_wsr || + BuiltinID == clang::ARM::BI__builtin_arm_wsr64 || + BuiltinID == clang::ARM::BI__builtin_arm_wsrp) { SpecialRegisterAccessKind AccessKind = Write; - if (BuiltinID == ARM::BI__builtin_arm_rsr || - BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_rsrp) + if (BuiltinID == clang::ARM::BI__builtin_arm_rsr || + BuiltinID == clang::ARM::BI__builtin_arm_rsr64 || + BuiltinID == clang::ARM::BI__builtin_arm_rsrp) AccessKind = VolatileRead; - bool IsPointerBuiltin = BuiltinID == ARM::BI__builtin_arm_rsrp || - BuiltinID == ARM::BI__builtin_arm_wsrp; + bool IsPointerBuiltin = BuiltinID == clang::ARM::BI__builtin_arm_rsrp || + BuiltinID == clang::ARM::BI__builtin_arm_wsrp; - bool Is64Bit = BuiltinID == ARM::BI__builtin_arm_rsr64 || - BuiltinID == ARM::BI__builtin_arm_wsr64; + bool Is64Bit = BuiltinID == clang::ARM::BI__builtin_arm_rsr64 || + BuiltinID == clang::ARM::BI__builtin_arm_wsr64; llvm::Type *ValueType; llvm::Type *RegisterType; @@ -7957,10 +7958,11 @@ // The ARM _MoveToCoprocessor builtins put the input register value as // the first argument, but the LLVM intrinsic expects it as the third one. - case ARM::BI_MoveToCoprocessor: - case ARM::BI_MoveToCoprocessor2: { - Function *F = CGM.getIntrinsic(BuiltinID == ARM::BI_MoveToCoprocessor ? - Intrinsic::arm_mcr : Intrinsic::arm_mcr2); + case clang::ARM::BI_MoveToCoprocessor: + case clang::ARM::BI_MoveToCoprocessor2: { + Function *F = CGM.getIntrinsic(BuiltinID == clang::ARM::BI_MoveToCoprocessor + ? Intrinsic::arm_mcr + : Intrinsic::arm_mcr2); return Builder.CreateCall(F, {Ops[1], Ops[2], Ops[0], Ops[3], Ops[4], Ops[5]}); } @@ -7973,11 +7975,11 @@ if (!Result) return nullptr; - if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f || - BuiltinID == ARM::BI__builtin_arm_vcvtr_d) { + if (BuiltinID == clang::ARM::BI__builtin_arm_vcvtr_f || + BuiltinID == clang::ARM::BI__builtin_arm_vcvtr_d) { // Determine the overloaded type of this builtin. llvm::Type *Ty; - if (BuiltinID == ARM::BI__builtin_arm_vcvtr_f) + if (BuiltinID == clang::ARM::BI__builtin_arm_vcvtr_f) Ty = FloatTy; else Ty = DoubleTy; @@ -9410,34 +9412,34 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E, llvm::Triple::ArchType Arch) { - if (BuiltinID >= AArch64::FirstSVEBuiltin && - BuiltinID <= AArch64::LastSVEBuiltin) + if (BuiltinID >= clang::AArch64::FirstSVEBuiltin && + BuiltinID <= clang::AArch64::LastSVEBuiltin) return EmitAArch64SVEBuiltinExpr(BuiltinID, E); unsigned HintID = static_cast(-1); switch (BuiltinID) { default: break; - case AArch64::BI__builtin_arm_nop: + case clang::AArch64::BI__builtin_arm_nop: HintID = 0; break; - case AArch64::BI__builtin_arm_yield: - case AArch64::BI__yield: + case clang::AArch64::BI__builtin_arm_yield: + case clang::AArch64::BI__yield: HintID = 1; break; - case AArch64::BI__builtin_arm_wfe: - case AArch64::BI__wfe: + case clang::AArch64::BI__builtin_arm_wfe: + case clang::AArch64::BI__wfe: HintID = 2; break; - case AArch64::BI__builtin_arm_wfi: - case AArch64::BI__wfi: + case clang::AArch64::BI__builtin_arm_wfi: + case clang::AArch64::BI__wfi: HintID = 3; break; - case AArch64::BI__builtin_arm_sev: - case AArch64::BI__sev: + case clang::AArch64::BI__builtin_arm_sev: + case clang::AArch64::BI__sev: HintID = 4; break; - case AArch64::BI__builtin_arm_sevl: - case AArch64::BI__sevl: + case clang::AArch64::BI__builtin_arm_sevl: + case clang::AArch64::BI__sevl: HintID = 5; break; } @@ -9447,7 +9449,7 @@ return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID)); } - if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_prefetch) { Value *Address = EmitScalarExpr(E->getArg(0)); Value *RW = EmitScalarExpr(E->getArg(1)); Value *CacheLevel = EmitScalarExpr(E->getArg(2)); @@ -9470,14 +9472,14 @@ return Builder.CreateCall(F, {Address, RW, Locality, IsData}); } - if (BuiltinID == AArch64::BI__builtin_arm_rbit) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit) { assert((getContext().getTypeSize(E->getType()) == 32) && "rbit of unusual size!"); llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall( CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit"); } - if (BuiltinID == AArch64::BI__builtin_arm_rbit64) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit64) { assert((getContext().getTypeSize(E->getType()) == 64) && "rbit of unusual size!"); llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); @@ -9485,50 +9487,50 @@ CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit"); } - if (BuiltinID == AArch64::BI__builtin_arm_cls) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_cls) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_cls), Arg, "cls"); } - if (BuiltinID == AArch64::BI__builtin_arm_cls64) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_cls64) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_cls64), Arg, "cls"); } - if (BuiltinID == AArch64::BI__builtin_arm_frint32zf || - BuiltinID == AArch64::BI__builtin_arm_frint32z) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_frint32zf || + BuiltinID == clang::AArch64::BI__builtin_arm_frint32z) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); llvm::Type *Ty = Arg->getType(); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint32z, Ty), Arg, "frint32z"); } - if (BuiltinID == AArch64::BI__builtin_arm_frint64zf || - BuiltinID == AArch64::BI__builtin_arm_frint64z) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_frint64zf || + BuiltinID == clang::AArch64::BI__builtin_arm_frint64z) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); llvm::Type *Ty = Arg->getType(); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint64z, Ty), Arg, "frint64z"); } - if (BuiltinID == AArch64::BI__builtin_arm_frint32xf || - BuiltinID == AArch64::BI__builtin_arm_frint32x) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_frint32xf || + BuiltinID == clang::AArch64::BI__builtin_arm_frint32x) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); llvm::Type *Ty = Arg->getType(); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint32x, Ty), Arg, "frint32x"); } - if (BuiltinID == AArch64::BI__builtin_arm_frint64xf || - BuiltinID == AArch64::BI__builtin_arm_frint64x) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_frint64xf || + BuiltinID == clang::AArch64::BI__builtin_arm_frint64x) { llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); llvm::Type *Ty = Arg->getType(); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_frint64x, Ty), Arg, "frint64x"); } - if (BuiltinID == AArch64::BI__builtin_arm_jcvt) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_jcvt) { assert((getContext().getTypeSize(E->getType()) == 32) && "__jcvt of unusual size!"); llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); @@ -9536,14 +9538,14 @@ CGM.getIntrinsic(Intrinsic::aarch64_fjcvtzs), Arg); } - if (BuiltinID == AArch64::BI__builtin_arm_ld64b || - BuiltinID == AArch64::BI__builtin_arm_st64b || - BuiltinID == AArch64::BI__builtin_arm_st64bv || - BuiltinID == AArch64::BI__builtin_arm_st64bv0) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_ld64b || + BuiltinID == clang::AArch64::BI__builtin_arm_st64b || + BuiltinID == clang::AArch64::BI__builtin_arm_st64bv || + BuiltinID == clang::AArch64::BI__builtin_arm_st64bv0) { llvm::Value *MemAddr = EmitScalarExpr(E->getArg(0)); llvm::Value *ValPtr = EmitScalarExpr(E->getArg(1)); - if (BuiltinID == AArch64::BI__builtin_arm_ld64b) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_ld64b) { // Load from the address via an LLVM intrinsic, receiving a // tuple of 8 i64 words, and store each one to ValPtr. Function *F = CGM.getIntrinsic(Intrinsic::aarch64_ld64b); @@ -9570,20 +9572,20 @@ Args.push_back(Builder.CreateLoad(Addr)); } - auto Intr = (BuiltinID == AArch64::BI__builtin_arm_st64b + auto Intr = (BuiltinID == clang::AArch64::BI__builtin_arm_st64b ? Intrinsic::aarch64_st64b - : BuiltinID == AArch64::BI__builtin_arm_st64bv - ? Intrinsic::aarch64_st64bv - : Intrinsic::aarch64_st64bv0); + : BuiltinID == clang::AArch64::BI__builtin_arm_st64bv + ? Intrinsic::aarch64_st64bv + : Intrinsic::aarch64_st64bv0); Function *F = CGM.getIntrinsic(Intr); return Builder.CreateCall(F, Args); } } - if (BuiltinID == AArch64::BI__builtin_arm_rndr || - BuiltinID == AArch64::BI__builtin_arm_rndrrs) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_rndr || + BuiltinID == clang::AArch64::BI__builtin_arm_rndrrs) { - auto Intr = (BuiltinID == AArch64::BI__builtin_arm_rndr + auto Intr = (BuiltinID == clang::AArch64::BI__builtin_arm_rndr ? Intrinsic::aarch64_rndr : Intrinsic::aarch64_rndrrs); Function *F = CGM.getIntrinsic(Intr); @@ -9597,7 +9599,7 @@ return Status; } - if (BuiltinID == AArch64::BI__clear_cache) { + if (BuiltinID == clang::AArch64::BI__clear_cache) { assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments"); const FunctionDecl *FD = E->getDirectCallee(); Value *Ops[2]; @@ -9609,12 +9611,13 @@ return EmitNounwindRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name), Ops); } - if ((BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex) && + if ((BuiltinID == clang::AArch64::BI__builtin_arm_ldrex || + BuiltinID == clang::AArch64::BI__builtin_arm_ldaex) && getContext().getTypeSize(E->getType()) == 128) { - Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex - ? Intrinsic::aarch64_ldaxp - : Intrinsic::aarch64_ldxp); + Function *F = + CGM.getIntrinsic(BuiltinID == clang::AArch64::BI__builtin_arm_ldaex + ? Intrinsic::aarch64_ldaxp + : Intrinsic::aarch64_ldxp); Value *LdPtr = EmitScalarExpr(E->getArg(0)); Value *Val = Builder.CreateCall(F, Builder.CreateBitCast(LdPtr, Int8PtrTy), @@ -9630,8 +9633,8 @@ Val = Builder.CreateShl(Val0, ShiftCst, "shl", true /* nuw */); Val = Builder.CreateOr(Val, Val1); return Builder.CreateBitCast(Val, ConvertType(E->getType())); - } else if (BuiltinID == AArch64::BI__builtin_arm_ldrex || - BuiltinID == AArch64::BI__builtin_arm_ldaex) { + } else if (BuiltinID == clang::AArch64::BI__builtin_arm_ldrex || + BuiltinID == clang::AArch64::BI__builtin_arm_ldaex) { Value *LoadAddr = EmitScalarExpr(E->getArg(0)); QualType Ty = E->getType(); @@ -9641,10 +9644,11 @@ llvm::Type *PtrTy = IntTy->getPointerTo(); LoadAddr = Builder.CreateBitCast(LoadAddr, PtrTy); - Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_ldaex - ? Intrinsic::aarch64_ldaxr - : Intrinsic::aarch64_ldxr, - PtrTy); + Function *F = + CGM.getIntrinsic(BuiltinID == clang::AArch64::BI__builtin_arm_ldaex + ? Intrinsic::aarch64_ldaxr + : Intrinsic::aarch64_ldxr, + PtrTy); CallInst *Val = Builder.CreateCall(F, LoadAddr, "ldxr"); Val->addParamAttr( 0, Attribute::get(getLLVMContext(), Attribute::ElementType, IntTy)); @@ -9658,12 +9662,13 @@ RealResTy); } - if ((BuiltinID == AArch64::BI__builtin_arm_strex || - BuiltinID == AArch64::BI__builtin_arm_stlex) && + if ((BuiltinID == clang::AArch64::BI__builtin_arm_strex || + BuiltinID == clang::AArch64::BI__builtin_arm_stlex) && getContext().getTypeSize(E->getArg(0)->getType()) == 128) { - Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex - ? Intrinsic::aarch64_stlxp - : Intrinsic::aarch64_stxp); + Function *F = + CGM.getIntrinsic(BuiltinID == clang::AArch64::BI__builtin_arm_stlex + ? Intrinsic::aarch64_stlxp + : Intrinsic::aarch64_stxp); llvm::Type *STy = llvm::StructType::get(Int64Ty, Int64Ty); Address Tmp = CreateMemTemp(E->getArg(0)->getType()); @@ -9679,8 +9684,8 @@ return Builder.CreateCall(F, {Arg0, Arg1, StPtr}, "stxp"); } - if (BuiltinID == AArch64::BI__builtin_arm_strex || - BuiltinID == AArch64::BI__builtin_arm_stlex) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_strex || + BuiltinID == clang::AArch64::BI__builtin_arm_stlex) { Value *StoreVal = EmitScalarExpr(E->getArg(0)); Value *StoreAddr = EmitScalarExpr(E->getArg(1)); @@ -9699,17 +9704,18 @@ StoreVal = Builder.CreateZExtOrBitCast(StoreVal, Int64Ty); } - Function *F = CGM.getIntrinsic(BuiltinID == AArch64::BI__builtin_arm_stlex - ? Intrinsic::aarch64_stlxr - : Intrinsic::aarch64_stxr, - StoreAddr->getType()); + Function *F = + CGM.getIntrinsic(BuiltinID == clang::AArch64::BI__builtin_arm_stlex + ? Intrinsic::aarch64_stlxr + : Intrinsic::aarch64_stxr, + StoreAddr->getType()); CallInst *CI = Builder.CreateCall(F, {StoreVal, StoreAddr}, "stxr"); CI->addParamAttr( 1, Attribute::get(getLLVMContext(), Attribute::ElementType, StoreTy)); return CI; } - if (BuiltinID == AArch64::BI__getReg) { + if (BuiltinID == clang::AArch64::BI__getReg) { Expr::EvalResult Result; if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext())) llvm_unreachable("Sema will ensure that the parameter is constant"); @@ -9727,7 +9733,7 @@ return Builder.CreateCall(F, Metadata); } - if (BuiltinID == AArch64::BI__break) { + if (BuiltinID == clang::AArch64::BI__break) { Expr::EvalResult Result; if (!E->getArg(0)->EvaluateAsInt(Result, CGM.getContext())) llvm_unreachable("Sema will ensure that the parameter is constant"); @@ -9736,33 +9742,33 @@ return Builder.CreateCall(F, {EmitScalarExpr(E->getArg(0))}); } - if (BuiltinID == AArch64::BI__builtin_arm_clrex) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_clrex) { Function *F = CGM.getIntrinsic(Intrinsic::aarch64_clrex); return Builder.CreateCall(F); } - if (BuiltinID == AArch64::BI_ReadWriteBarrier) + if (BuiltinID == clang::AArch64::BI_ReadWriteBarrier) return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, llvm::SyncScope::SingleThread); // CRC32 Intrinsic::ID CRCIntrinsicID = Intrinsic::not_intrinsic; switch (BuiltinID) { - case AArch64::BI__builtin_arm_crc32b: + case clang::AArch64::BI__builtin_arm_crc32b: CRCIntrinsicID = Intrinsic::aarch64_crc32b; break; - case AArch64::BI__builtin_arm_crc32cb: + case clang::AArch64::BI__builtin_arm_crc32cb: CRCIntrinsicID = Intrinsic::aarch64_crc32cb; break; - case AArch64::BI__builtin_arm_crc32h: + case clang::AArch64::BI__builtin_arm_crc32h: CRCIntrinsicID = Intrinsic::aarch64_crc32h; break; - case AArch64::BI__builtin_arm_crc32ch: + case clang::AArch64::BI__builtin_arm_crc32ch: CRCIntrinsicID = Intrinsic::aarch64_crc32ch; break; - case AArch64::BI__builtin_arm_crc32w: + case clang::AArch64::BI__builtin_arm_crc32w: CRCIntrinsicID = Intrinsic::aarch64_crc32w; break; - case AArch64::BI__builtin_arm_crc32cw: + case clang::AArch64::BI__builtin_arm_crc32cw: CRCIntrinsicID = Intrinsic::aarch64_crc32cw; break; - case AArch64::BI__builtin_arm_crc32d: + case clang::AArch64::BI__builtin_arm_crc32d: CRCIntrinsicID = Intrinsic::aarch64_crc32x; break; - case AArch64::BI__builtin_arm_crc32cd: + case clang::AArch64::BI__builtin_arm_crc32cd: CRCIntrinsicID = Intrinsic::aarch64_crc32cx; break; } @@ -9792,17 +9798,17 @@ // Memory Tagging Extensions (MTE) Intrinsics Intrinsic::ID MTEIntrinsicID = Intrinsic::not_intrinsic; switch (BuiltinID) { - case AArch64::BI__builtin_arm_irg: + case clang::AArch64::BI__builtin_arm_irg: MTEIntrinsicID = Intrinsic::aarch64_irg; break; - case AArch64::BI__builtin_arm_addg: + case clang::AArch64::BI__builtin_arm_addg: MTEIntrinsicID = Intrinsic::aarch64_addg; break; - case AArch64::BI__builtin_arm_gmi: + case clang::AArch64::BI__builtin_arm_gmi: MTEIntrinsicID = Intrinsic::aarch64_gmi; break; - case AArch64::BI__builtin_arm_ldg: + case clang::AArch64::BI__builtin_arm_ldg: MTEIntrinsicID = Intrinsic::aarch64_ldg; break; - case AArch64::BI__builtin_arm_stg: + case clang::AArch64::BI__builtin_arm_stg: MTEIntrinsicID = Intrinsic::aarch64_stg; break; - case AArch64::BI__builtin_arm_subp: + case clang::AArch64::BI__builtin_arm_subp: MTEIntrinsicID = Intrinsic::aarch64_subp; break; } @@ -9867,24 +9873,24 @@ } } - if (BuiltinID == AArch64::BI__builtin_arm_rsr || - BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_rsrp || - BuiltinID == AArch64::BI__builtin_arm_wsr || - BuiltinID == AArch64::BI__builtin_arm_wsr64 || - BuiltinID == AArch64::BI__builtin_arm_wsrp) { + if (BuiltinID == clang::AArch64::BI__builtin_arm_rsr || + BuiltinID == clang::AArch64::BI__builtin_arm_rsr64 || + BuiltinID == clang::AArch64::BI__builtin_arm_rsrp || + BuiltinID == clang::AArch64::BI__builtin_arm_wsr || + BuiltinID == clang::AArch64::BI__builtin_arm_wsr64 || + BuiltinID == clang::AArch64::BI__builtin_arm_wsrp) { SpecialRegisterAccessKind AccessKind = Write; - if (BuiltinID == AArch64::BI__builtin_arm_rsr || - BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_rsrp) + if (BuiltinID == clang::AArch64::BI__builtin_arm_rsr || + BuiltinID == clang::AArch64::BI__builtin_arm_rsr64 || + BuiltinID == clang::AArch64::BI__builtin_arm_rsrp) AccessKind = VolatileRead; - bool IsPointerBuiltin = BuiltinID == AArch64::BI__builtin_arm_rsrp || - BuiltinID == AArch64::BI__builtin_arm_wsrp; + bool IsPointerBuiltin = BuiltinID == clang::AArch64::BI__builtin_arm_rsrp || + BuiltinID == clang::AArch64::BI__builtin_arm_wsrp; - bool Is64Bit = BuiltinID != AArch64::BI__builtin_arm_rsr && - BuiltinID != AArch64::BI__builtin_arm_wsr; + bool Is64Bit = BuiltinID != clang::AArch64::BI__builtin_arm_rsr && + BuiltinID != clang::AArch64::BI__builtin_arm_wsr; llvm::Type *ValueType; llvm::Type *RegisterType = Int64Ty; @@ -9900,8 +9906,8 @@ AccessKind); } - if (BuiltinID == AArch64::BI_ReadStatusReg || - BuiltinID == AArch64::BI_WriteStatusReg) { + if (BuiltinID == clang::AArch64::BI_ReadStatusReg || + BuiltinID == clang::AArch64::BI_WriteStatusReg) { LLVMContext &Context = CGM.getLLVMContext(); unsigned SysReg = @@ -9922,7 +9928,7 @@ llvm::Type *RegisterType = Int64Ty; llvm::Type *Types[] = { RegisterType }; - if (BuiltinID == AArch64::BI_ReadStatusReg) { + if (BuiltinID == clang::AArch64::BI_ReadStatusReg) { llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types); return Builder.CreateCall(F, Metadata); @@ -9934,22 +9940,23 @@ return Builder.CreateCall(F, { Metadata, ArgValue }); } - if (BuiltinID == AArch64::BI_AddressOfReturnAddress) { + if (BuiltinID == clang::AArch64::BI_AddressOfReturnAddress) { llvm::Function *F = CGM.getIntrinsic(Intrinsic::addressofreturnaddress, AllocaInt8PtrTy); return Builder.CreateCall(F); } - if (BuiltinID == AArch64::BI__builtin_sponentry) { + if (BuiltinID == clang::AArch64::BI__builtin_sponentry) { llvm::Function *F = CGM.getIntrinsic(Intrinsic::sponentry, AllocaInt8PtrTy); return Builder.CreateCall(F); } - if (BuiltinID == AArch64::BI__mulh || BuiltinID == AArch64::BI__umulh) { + if (BuiltinID == clang::AArch64::BI__mulh || + BuiltinID == clang::AArch64::BI__umulh) { llvm::Type *ResType = ConvertType(E->getType()); llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); - bool IsSigned = BuiltinID == AArch64::BI__mulh; + bool IsSigned = BuiltinID == clang::AArch64::BI__mulh; Value *LHS = Builder.CreateIntCast(EmitScalarExpr(E->getArg(0)), Int128Ty, IsSigned); Value *RHS = @@ -10742,7 +10749,7 @@ "vgetq_lane"); } - case AArch64::BI_InterlockedAdd: { + case clang::AArch64::BI_InterlockedAdd: { Value *Arg0 = EmitScalarExpr(E->getArg(0)); Value *Arg1 = EmitScalarExpr(E->getArg(1)); AtomicRMWInst *RMWI = Builder.CreateAtomicRMW( @@ -12742,6 +12749,16 @@ return Result; } +Value *CodeGenFunction::EmitAArch64CpuInit() { + llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); + llvm::FunctionCallee Func = + CGM.CreateRuntimeFunction(FTy, "init_cpu_features_resolver"); + cast(Func.getCallee())->setDSOLocal(true); + cast(Func.getCallee()) + ->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); + return Builder.CreateCall(Func); +} + Value *CodeGenFunction::EmitX86CpuInit() { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, /*Variadic*/ false); @@ -12753,6 +12770,32 @@ return Builder.CreateCall(Func); } +llvm::Value * +CodeGenFunction::EmitAArch64CpuSupports(ArrayRef FeaturesStrs) { + uint64_t FeaturesMask = llvm::AArch64::getCpuSupportsMask(FeaturesStrs); + Value *Result = Builder.getTrue(); + if (FeaturesMask != 0) { + // Get features from structure in runtime library + // struct { + // unsigned long long features; + // } __aarch64_cpu_features; + llvm::Type *STy = llvm::StructType::get(Int64Ty); + llvm::Constant *AArch64CPUFeatures = + CGM.CreateRuntimeVariable(STy, "__aarch64_cpu_features"); + cast(AArch64CPUFeatures)->setDSOLocal(true); + llvm::Value *CpuFeatures = Builder.CreateGEP( + STy, AArch64CPUFeatures, + {ConstantInt::get(Int32Ty, 0), ConstantInt::get(Int32Ty, 0)}); + Value *Features = Builder.CreateAlignedLoad(Int64Ty, CpuFeatures, + CharUnits::fromQuantity(8)); + Value *Mask = Builder.getInt64(FeaturesMask); + Value *Bitset = Builder.CreateAnd(Features, Mask); + Value *Cmp = Builder.CreateICmpEQ(Bitset, Mask); + Result = Builder.CreateAnd(Result, Cmp); + } + return Result; +} + Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == X86::BI__builtin_cpu_is) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4793,6 +4793,12 @@ // last (if it exists). void EmitMultiVersionResolver(llvm::Function *Resolver, ArrayRef Options); + void + EmitX86MultiVersionResolver(llvm::Function *Resolver, + ArrayRef Options); + void + EmitAArch64MultiVersionResolver(llvm::Function *Resolver, + ArrayRef Options); private: QualType getVarArgType(const Expr *Arg); @@ -4811,7 +4817,11 @@ llvm::Value *EmitX86CpuSupports(ArrayRef FeatureStrs); llvm::Value *EmitX86CpuSupports(uint64_t Mask); llvm::Value *EmitX86CpuInit(); - llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO); + llvm::Value *FormX86ResolverCondition(const MultiVersionResolverOption &RO); + llvm::Value *EmitAArch64CpuInit(); + llvm::Value * + FormAArch64ResolverCondition(const MultiVersionResolverOption &RO); + llvm::Value *EmitAArch64CpuSupports(ArrayRef FeatureStrs); }; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -2558,7 +2558,7 @@ << FeatureList; } } else if (!TargetDecl->isMultiVersion() && - TargetDecl->hasAttr()) { + (TargetDecl->hasAttr())) { // Get the required features for the callee. const TargetAttr *TD = TargetDecl->getAttr(); @@ -2600,8 +2600,16 @@ CGM.getSanStats().create(IRB, SSK); } -llvm::Value * -CodeGenFunction::FormResolverCondition(const MultiVersionResolverOption &RO) { +llvm::Value *CodeGenFunction::FormAArch64ResolverCondition( + const MultiVersionResolverOption &RO) { + if (!RO.Conditions.Features.empty()) { + return EmitAArch64CpuSupports(RO.Conditions.Features); + } + return nullptr; +} + +llvm::Value *CodeGenFunction::FormX86ResolverCondition( + const MultiVersionResolverOption &RO) { llvm::Value *Condition = nullptr; if (!RO.Conditions.Architecture.empty()) @@ -2639,8 +2647,69 @@ void CodeGenFunction::EmitMultiVersionResolver( llvm::Function *Resolver, ArrayRef Options) { - assert(getContext().getTargetInfo().getTriple().isX86() && - "Only implemented for x86 targets"); + + llvm::Triple::ArchType ArchType = + getContext().getTargetInfo().getTriple().getArch(); + + switch (ArchType) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + EmitX86MultiVersionResolver(Resolver, Options); + return; + case llvm::Triple::aarch64: + EmitAArch64MultiVersionResolver(Resolver, Options); + return; + + default: + assert(false && "Only implemented for x86 and AArch64 targets"); + } +} + +void CodeGenFunction::EmitAArch64MultiVersionResolver( + llvm::Function *Resolver, ArrayRef Options) { + assert(!Options.empty() && "No Multiversion Resolver Options Found"); + assert(Options.back().Conditions.Features.size() == 0 && + "Default case must be last"); + bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); + assert(SupportsIFunc && + "Multiversion Resolver requires target IFUNC support"); + + llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver); + Builder.SetInsertPoint(CurBlock); + EmitAArch64CpuInit(); + + for (const MultiVersionResolverOption &RO : Options) { + Builder.SetInsertPoint(CurBlock); + llvm::Value *Condition = FormAArch64ResolverCondition(RO); + + // The 'default' or 'generic' case. + if (!Condition) { + assert(&RO == Options.end() - 1 && + "Default or Generic case must be last"); + CreateMultiVersionResolverReturn(CGM, Resolver, Builder, RO.Function, + SupportsIFunc); + return; + } + + llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver); + CGBuilderTy RetBuilder(*this, RetBlock); + CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder, RO.Function, + SupportsIFunc); + CurBlock = createBasicBlock("resolver_else", Resolver); + Builder.CreateCondBr(Condition, RetBlock, CurBlock); + } + + // If no default, emit an unreachable. + Builder.SetInsertPoint(CurBlock); + llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); +} + +void CodeGenFunction::EmitX86MultiVersionResolver( + llvm::Function *Resolver, ArrayRef Options) { bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); @@ -2651,7 +2720,7 @@ for (const MultiVersionResolverOption &RO : Options) { Builder.SetInsertPoint(CurBlock); - llvm::Value *Condition = FormResolverCondition(RO); + llvm::Value *Condition = FormX86ResolverCondition(RO); // The 'default' or 'generic' case. if (!Condition) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1295,6 +1295,20 @@ Out << ".resolver"; } +static void AppendTargetVersionMangling(const CodeGenModule &CGM, + const TargetVersionAttr *Attr, + raw_ostream &Out) { + if (Attr->isDefaultVersion()) + return; + Out << "._"; + llvm::SmallVector Feats; + Attr->getFeatures(Feats); + for (const auto &Feat : Feats) { + Out << 'M'; + Out << Feat; + } +} + static void AppendTargetMangling(const CodeGenModule &CGM, const TargetAttr *Attr, raw_ostream &Out) { if (Attr->isDefaultVersion()) @@ -1340,14 +1354,27 @@ const TargetClonesAttr *Attr, unsigned VersionIndex, raw_ostream &Out) { - Out << '.'; - StringRef FeatureStr = Attr->getFeatureStr(VersionIndex); - if (FeatureStr.startswith("arch=")) - Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1); - else - Out << FeatureStr; + if (CGM.getTarget().getTriple().isAArch64()) { + StringRef FeatureStr = Attr->getFeatureStr(VersionIndex); + if (FeatureStr == "default") + return; + Out << "._"; + SmallVector Features; + FeatureStr.split(Features, "+"); + for (auto &Feat : Features) { + Out << 'M'; + Out << Feat; + } + } else { + Out << '.'; + StringRef FeatureStr = Attr->getFeatureStr(VersionIndex); + if (FeatureStr.startswith("arch=")) + Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1); + else + Out << FeatureStr; - Out << '.' << Attr->getMangledIndex(VersionIndex); + Out << '.' << Attr->getMangledIndex(VersionIndex); + } } static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, @@ -1403,6 +1430,9 @@ case MultiVersionKind::Target: AppendTargetMangling(CGM, FD->getAttr(), Out); break; + case MultiVersionKind::TargetVersion: + AppendTargetVersionMangling(CGM, FD->getAttr(), Out); + break; case MultiVersionKind::TargetClones: AppendTargetClonesMangling(CGM, FD->getAttr(), GD.getMultiVersionIndex(), Out); @@ -2085,10 +2115,12 @@ const auto *FD = dyn_cast_or_null(GD.getDecl()); FD = FD ? FD->getMostRecentDecl() : FD; const auto *TD = FD ? FD->getAttr() : nullptr; + const auto *TV = FD ? FD->getAttr() : nullptr; + assert((!TD || !TV) && "both target_version and target specified"); const auto *SD = FD ? FD->getAttr() : nullptr; const auto *TC = FD ? FD->getAttr() : nullptr; bool AddedAttr = false; - if (TD || SD || TC) { + if (TD || TV || SD || TC) { llvm::StringMap FeatureMap; getContext().getFunctionFeatureMap(FeatureMap, GD); @@ -3426,12 +3458,18 @@ TargetMVPriority(const TargetInfo &TI, const CodeGenFunction::MultiVersionResolverOption &RO) { unsigned Priority = 0; - for (StringRef Feat : RO.Conditions.Features) + unsigned NumFeatures = 0; + for (StringRef Feat : RO.Conditions.Features) { Priority = std::max(Priority, TI.multiVersionSortPriority(Feat)); + NumFeatures++; + } if (!RO.Conditions.Architecture.empty()) Priority = std::max( Priority, TI.multiVersionSortPriority(RO.Conditions.Architecture)); + + Priority += TI.multiVersionFeatureCost() * NumFeatures; + return Priority; } @@ -3476,13 +3514,19 @@ } assert(Func && "This should have just been created"); } - - const auto *TA = CurFD->getAttr(); - llvm::SmallVector Feats; - TA->getAddedFeatures(Feats); - - Options.emplace_back(cast(Func), - TA->getArchitecture(), Feats); + if (CurFD->getMultiVersionKind() == MultiVersionKind::Target) { + const auto *TA = CurFD->getAttr(); + llvm::SmallVector Feats; + TA->getAddedFeatures(Feats); + Options.emplace_back(cast(Func), + TA->getArchitecture(), Feats); + } else { + const auto *TVA = CurFD->getAttr(); + llvm::SmallVector Feats; + TVA->getFeatures(Feats); + Options.emplace_back(cast(Func), + /*Architecture*/ "", Feats); + } }); } else if (FD->isTargetClonesMultiVersion()) { const auto *TC = FD->getAttr(); @@ -3512,10 +3556,21 @@ StringRef Architecture; llvm::SmallVector Feature; - if (Version.startswith("arch=")) - Architecture = Version.drop_front(sizeof("arch=") - 1); - else if (Version != "default") - Feature.push_back(Version); + if (getTarget().getTriple().isAArch64()) { + if (Version != "default") { + llvm::SmallVector VerFeats; + Version.split(VerFeats, "+"); + for (auto &CurFeat : VerFeats) { + CurFeat = CurFeat.trim(); + Feature.push_back(CurFeat); + } + } + } else { + if (Version.startswith("arch=")) + Architecture = Version.drop_front(sizeof("arch=") - 1); + else if (Version != "default") + Feature.push_back(Version); + } Options.emplace_back(cast(Func), Architecture, Feature); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7167,6 +7167,11 @@ CmdArgs.push_back("+outline-atomics"); } + if (Args.hasArg(options::OPT_mno_fmv)) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-fmv"); + } + if (Args.hasFlag(options::OPT_faddrsig, options::OPT_fno_addrsig, (TC.getTriple().isOSBinFormatELF() || TC.getTriple().isOSBinFormatCOFF()) && diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2523,6 +2523,9 @@ if (FD->isMultiVersion() && FD->hasAttr() && !FD->getAttr()->isDefaultVersion()) continue; + if (FD->isMultiVersion() && FD->hasAttr() && + !FD->getAttr()->isDefaultVersion()) + continue; } S.Diag(Fn->getLocation(), diag::note_possible_target_of_call); ++ShownOverloads; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9823,6 +9823,13 @@ // Handle attributes. ProcessDeclAttributes(S, NewFD, D); + const auto *NewTVA = NewFD->getAttr(); + if (NewTVA && !NewTVA->isDefaultVersion() && + !Context.getTargetInfo().hasFeature("fmv")) { + // Don't add to scope fmv functions declarations if fmv disabled + AddToScope = false; + return NewFD; + } if (getLangOpts().OpenCL) { // OpenCL v1.1 s6.5: Using an address space qualifier in a function return @@ -10003,7 +10010,8 @@ D.setRedeclaration(true); } - assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || + assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() || + !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); @@ -10477,37 +10485,55 @@ PrevVD->getType()); } -/// Check the target attribute of the function for MultiVersion -/// validity. +/// Check the target or target_version attribute of the function for +/// MultiVersion validity. /// /// Returns true if there was an error, false otherwise. static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { const auto *TA = FD->getAttr(); - assert(TA && "MultiVersion Candidate requires a target attribute"); - ParsedTargetAttr ParseInfo = TA->parse(); + const auto *TVA = FD->getAttr(); + assert( + (TA || TVA) && + "MultiVersion Candidate requires a target or target_version attribute"); const TargetInfo &TargetInfo = S.Context.getTargetInfo(); enum ErrType { Feature = 0, Architecture = 1 }; - if (!ParseInfo.Architecture.empty() && - !TargetInfo.validateCpuIs(ParseInfo.Architecture)) { - S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) - << Architecture << ParseInfo.Architecture; - return true; - } - - for (const auto &Feat : ParseInfo.Features) { - auto BareFeat = StringRef{Feat}.substr(1); - if (Feat[0] == '-') { + if (TA) { + ParsedTargetAttr ParseInfo = TA->parse(); + if (!ParseInfo.Architecture.empty() && + !TargetInfo.validateCpuIs(ParseInfo.Architecture)) { S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) - << Feature << ("no-" + BareFeat).str(); + << Architecture << ParseInfo.Architecture; return true; } - if (!TargetInfo.validateCpuSupports(BareFeat) || - !TargetInfo.isValidFeatureName(BareFeat)) { - S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) - << Feature << BareFeat; - return true; + for (const auto &Feat : ParseInfo.Features) { + auto BareFeat = StringRef{Feat}.substr(1); + if (Feat[0] == '-') { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << ("no-" + BareFeat).str(); + return true; + } + + if (!TargetInfo.validateCpuSupports(BareFeat) || + !TargetInfo.isValidFeatureName(BareFeat)) { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << BareFeat; + return true; + } + } + } + + if (TVA) { + llvm::SmallVector Feats; + TVA->getFeatures(Feats); + for (const auto &Feat : Feats) { + if (!TargetInfo.validateCpuSupports(Feat) || + !TargetInfo.isValidFeatureName(Feat)) { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << Feat; + return true; + } } } return false; @@ -10554,6 +10580,10 @@ if (MVKind != MultiVersionKind::Target) return Diagnose(S, A); break; + case attr::TargetVersion: + if (MVKind != MultiVersionKind::TargetVersion) + return Diagnose(S, A); + break; case attr::TargetClones: if (MVKind != MultiVersionKind::TargetClones) return Diagnose(S, A); @@ -10726,18 +10756,18 @@ /// This sets NewFD->isInvalidDecl() to true if there was an error. /// /// Returns true if there was an error, false otherwise. -static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD, - MultiVersionKind MVKind, - const TargetAttr *TA) { +static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) { + MultiVersionKind MVKind = FD->getMultiVersionKind(); assert(MVKind != MultiVersionKind::None && "Function lacks multiversion attribute"); - - // Target only causes MV if it is default, otherwise this is a normal - // function. - if (MVKind == MultiVersionKind::Target && !TA->isDefaultVersion()) + const auto *TA = FD->getAttr(); + const auto *TVA = FD->getAttr(); + // Target and target_version only causes MV if it is default, otherwise this + // is a normal function. + if ((TA && !TA->isDefaultVersion()) || (TVA && !TVA->isDefaultVersion())) return false; - if (MVKind == MultiVersionKind::Target && CheckMultiVersionValue(S, FD)) { + if ((TA || TVA) && CheckMultiVersionValue(S, FD)) { FD->setInvalidDecl(); return true; } @@ -10760,23 +10790,27 @@ return false; } -static bool CheckTargetCausesMultiVersioning( - Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA, - bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { +static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, + FunctionDecl *NewFD, + bool &Redeclaration, + NamedDecl *&OldDecl, + LookupResult &Previous) { + const auto *NewTA = NewFD->getAttr(); + const auto *NewTVA = NewFD->getAttr(); const auto *OldTA = OldFD->getAttr(); - ParsedTargetAttr NewParsed = NewTA->parse(); - // Sort order doesn't matter, it just needs to be consistent. - llvm::sort(NewParsed.Features); - + const auto *OldTVA = OldFD->getAttr(); // If the old decl is NOT MultiVersioned yet, and we don't cause that // to change, this is a simple redeclaration. - if (!NewTA->isDefaultVersion() && - (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) + if ((NewTA && !NewTA->isDefaultVersion() && + (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) || + (NewTVA && !NewTVA->isDefaultVersion() && + (!OldTVA || OldTVA->getTVName() == NewTVA->getTVName()))) return false; // Otherwise, this decl causes MultiVersioning. if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true, - MultiVersionKind::Target)) { + NewTVA ? MultiVersionKind::TargetVersion + : MultiVersionKind::Target)) { NewFD->setInvalidDecl(); return true; } @@ -10787,7 +10821,9 @@ } // If this is 'default', permit the forward declaration. - if (!OldFD->isMultiVersion() && !OldTA && NewTA->isDefaultVersion()) { + if (!OldFD->isMultiVersion() && + ((NewTA && NewTA->isDefaultVersion() && !OldTA) || + (NewTVA && NewTVA->isDefaultVersion() && !OldTVA))) { Redeclaration = true; OldDecl = OldFD; OldFD->setIsMultiVersion(); @@ -10801,23 +10837,46 @@ return true; } - ParsedTargetAttr OldParsed = OldTA->parse(std::less()); + if (NewTA) { + ParsedTargetAttr NewParsed = NewTA->parse(); + // Sort order doesn't matter, it just needs to be consistent. + llvm::sort(NewParsed.Features); + ParsedTargetAttr OldParsed = OldTA->parse(std::less()); + + if (OldParsed == NewParsed) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } - if (OldParsed == NewParsed) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); - S.Diag(OldFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; + if (NewTVA) { + llvm::SmallVector Feats; + OldTVA->getFeatures(Feats); + llvm::sort(Feats); + llvm::SmallVector NewFeats; + NewTVA->getFeatures(NewFeats); + llvm::sort(NewFeats); + + if (Feats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } } for (const auto *FD : OldFD->redecls()) { const auto *CurTA = FD->getAttr(); + const auto *CurTVA = FD->getAttr(); // We allow forward declarations before ANY multiversioning attributes, but // nothing after the fact. if (PreviousDeclsHaveMultiVersionAttribute(FD) && - (!CurTA || CurTA->isInherited())) { + ((NewTA && (!CurTA || CurTA->isInherited())) || + (NewTVA && (!CurTVA || CurTVA->isInherited())))) { S.Diag(FD->getLocation(), diag::err_multiversion_required_in_redecl) - << 0; + << (NewTA ? 0 : 2); S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); NewFD->setInvalidDecl(); return true; @@ -10848,11 +10907,11 @@ /// multiversioned declaration collection. static bool CheckMultiVersionAdditionalDecl( Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, - MultiVersionKind NewMVKind, const TargetAttr *NewTA, - const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, - const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl, - LookupResult &Previous) { - + MultiVersionKind NewMVKind, const CPUDispatchAttr *NewCPUDisp, + const CPUSpecificAttr *NewCPUSpec, const TargetClonesAttr *NewClones, + bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { + const auto *NewTA = NewFD->getAttr(); + const auto *NewTVA = NewFD->getAttr(); MultiVersionKind OldMVKind = OldFD->getMultiVersionKind(); // Disallow mixing of multiversioning types. if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) { @@ -10867,6 +10926,11 @@ NewParsed = NewTA->parse(); llvm::sort(NewParsed.Features); } + llvm::SmallVector NewFeats; + if (NewTVA) { + NewTVA->getFeatures(NewFeats); + llvm::sort(NewFeats); + } bool UseMemberUsingDeclRules = S.CurContext->isRecord() && !NewFD->getFriendObjectKind(); @@ -10884,6 +10948,20 @@ S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; + if (NewMVKind == MultiVersionKind::None && + OldMVKind == MultiVersionKind::TargetVersion) { + NewFD->addAttr(TargetVersionAttr::CreateImplicit( + S.Context, "default", NewFD->getSourceRange(), + AttributeCommonInfo::AS_GNU)); + NewFD->setIsMultiVersion(); + NewMVKind = MultiVersionKind::TargetVersion; + if (!NewTVA) { + NewTVA = NewFD->getAttr(); + NewTVA->getFeatures(NewFeats); + llvm::sort(NewFeats); + } + } + switch (NewMVKind) { case MultiVersionKind::None: assert(OldMVKind == MultiVersionKind::TargetClones && @@ -10907,6 +10985,27 @@ } break; } + case MultiVersionKind::TargetVersion: { + const auto *CurTVA = CurFD->getAttr(); + if (CurTVA->getTVName() == NewTVA->getTVName()) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + llvm::SmallVector CurFeats; + if (CurTVA) { + CurTVA->getFeatures(CurFeats); + llvm::sort(CurFeats); + } + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + break; + } case MultiVersionKind::TargetClones: { const auto *CurClones = CurFD->getAttr(); Redeclaration = true; @@ -10989,7 +11088,8 @@ // Else, this is simply a non-redecl case. Checking the 'value' is only // necessary in the Target case, since The CPUSpecific/Dispatch cases are // handled in the attribute adding step. - if (NewMVKind == MultiVersionKind::Target && + if ((NewMVKind == MultiVersionKind::TargetVersion || + NewMVKind == MultiVersionKind::Target) && CheckMultiVersionValue(S, NewFD)) { NewFD->setInvalidDecl(); return true; @@ -11027,16 +11127,20 @@ bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { const auto *NewTA = NewFD->getAttr(); + const auto *NewTVA = NewFD->getAttr(); const auto *NewCPUDisp = NewFD->getAttr(); const auto *NewCPUSpec = NewFD->getAttr(); const auto *NewClones = NewFD->getAttr(); MultiVersionKind MVKind = NewFD->getMultiVersionKind(); // Main isn't allowed to become a multiversion function, however it IS - // permitted to have 'main' be marked with the 'target' optimization hint. + // permitted to have 'main' be marked with the 'target' optimization hint, + // for 'target_version' only default is allowed. if (NewFD->isMain()) { if (MVKind != MultiVersionKind::None && - !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion())) { + !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion()) && + !(MVKind == MultiVersionKind::TargetVersion && + NewTVA->isDefaultVersion())) { S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); NewFD->setInvalidDecl(); return true; @@ -11051,18 +11155,34 @@ // multiversioning, this isn't an error condition. if (MVKind == MultiVersionKind::None) return false; - return CheckMultiVersionFirstFunction(S, NewFD, MVKind, NewTA); + return CheckMultiVersionFirstFunction(S, NewFD); } FunctionDecl *OldFD = OldDecl->getAsFunction(); - if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) + if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) { + // No target_version attributes mean default + if (!NewTVA) { + const auto *OldTVA = OldFD->getAttr(); + if (OldTVA) { + NewFD->addAttr(TargetVersionAttr::CreateImplicit( + S.Context, "default", NewFD->getSourceRange(), + AttributeCommonInfo::AS_GNU)); + NewFD->setIsMultiVersion(); + OldFD->setIsMultiVersion(); + OldDecl = OldFD; + Redeclaration = true; + return true; + } + } return false; + } // Multiversioned redeclarations aren't allowed to omit the attribute, except - // for target_clones. + // for target_clones and target_version. if (OldFD->isMultiVersion() && MVKind == MultiVersionKind::None && - OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) { + OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones && + OldFD->getMultiVersionKind() != MultiVersionKind::TargetVersion) { S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl) << (OldFD->getMultiVersionKind() != MultiVersionKind::Target); NewFD->setInvalidDecl(); @@ -11072,8 +11192,9 @@ if (!OldFD->isMultiVersion()) { switch (MVKind) { case MultiVersionKind::Target: - return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, - Redeclaration, OldDecl, Previous); + case MultiVersionKind::TargetVersion: + return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration, + OldDecl, Previous); case MultiVersionKind::TargetClones: if (OldFD->isUsed(false)) { NewFD->setInvalidDecl(); @@ -11081,6 +11202,7 @@ } OldFD->setIsMultiVersion(); break; + case MultiVersionKind::CPUDispatch: case MultiVersionKind::CPUSpecific: case MultiVersionKind::None: @@ -11091,9 +11213,9 @@ // At this point, we have a multiversion function decl (in OldFD) AND an // appropriate attribute in the current function decl. Resolve that these are // still compatible with previous declarations. - return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewTA, - NewCPUDisp, NewCPUSpec, NewClones, - Redeclaration, OldDecl, Previous); + return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewCPUDisp, + NewCPUSpec, NewClones, Redeclaration, + OldDecl, Previous); } /// Perform semantic checking of a new function declaration. @@ -14571,6 +14693,16 @@ FD->dropAttr(); FD->setInvalidDecl(); } + if (const auto *Attr = FD->getAttr()) { + if (!Context.getTargetInfo().hasFeature("fmv") && + !Attr->isDefaultVersion()) { + // If function multi versioning disabled skip parsing function body + // defined with non-default target_version attribute + if (SkipBody) + SkipBody->ShouldSkip = true; + return nullptr; + } + } if (auto *Ctor = dyn_cast(FD)) { if (Ctor->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && 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 @@ -3448,6 +3448,42 @@ return false; } +// Check Target Version attrs +bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, + bool &isDefault) { + enum FirstParam { Unsupported }; + enum SecondParam { None }; + enum ThirdParam { Target, TargetClones, TargetVersion }; + if (AttrStr.trim() == "default") + isDefault = true; + llvm::SmallVector Features; + AttrStr.split(Features, "+"); + for (auto &CurFeature : Features) { + CurFeature = CurFeature.trim(); + if (CurFeature == "default") + continue; + if (!Context.getTargetInfo().isValidFeatureName(CurFeature)) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature << TargetVersion; + } + return false; +} + +static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + bool isDefault = false; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || + S.checkTargetVersionAttr(LiteralLoc, Str, isDefault)) + return; + // Do not create default only target_version attribute + if (!isDefault) { + TargetVersionAttr *NewAttr = + ::new (S.Context) TargetVersionAttr(S.Context, AL, Str); + D->addAttr(NewAttr); + } +} + static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; @@ -3459,10 +3495,11 @@ D->addAttr(NewAttr); } -bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, - const StringLiteral *Literal, - bool &HasDefault, bool &HasCommas, - SmallVectorImpl &Strings) { +bool Sema::checkTargetClonesAttrString( + SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, + bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl &Strings, + SmallVectorImpl> &StringsBuffer) { enum FirstParam { Unsupported, Duplicate, Unknown }; enum SecondParam { None, Architecture, Tune }; enum ThirdParam { Target, TargetClones }; @@ -3481,27 +3518,71 @@ getLangOpts(), Context.getTargetInfo()); bool DefaultIsDupe = false; + bool IsCodeImpact = false; if (Cur.empty()) return Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; - if (Cur.startswith("arch=")) { - if (!Context.getTargetInfo().isValidCPUName( - Cur.drop_front(sizeof("arch=") - 1))) + if (Context.getTargetInfo().getTriple().isAArch64()) { + if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + if (llvm::find(Strings, Cur) != Strings.end() || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + else + Strings.push_back(Cur); + } else { + std::pair CurParts = {{}, Cur}; + llvm::SmallVector CurFeatures; + while (!CurParts.second.empty()) { + CurParts = CurParts.second.split('+'); + StringRef CurFeature = CurParts.first.trim(); + if (Context.getTargetInfo().isCodeImpactFeatureName(CurFeature)) + IsCodeImpact = true; + if (!Context.getTargetInfo().isValidFeatureName(CurFeature)) { + Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature << TargetClones; + continue; + } + CurFeatures.push_back(CurFeature); + } + // Canonize TargetClones Attributes + llvm::sort(CurFeatures); + SmallString<64> Res; + for (auto &CurFeat : CurFeatures) { + if (!Res.equals("")) + Res.append("+"); + Res.append(CurFeat); + } + if (llvm::find(Strings, Res.str()) != Strings.end() || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + else if (!IsCodeImpact) + // Ignore no code impact features set in target_clone attribute + Diag(CurLoc, diag::warn_target_clone_no_impact_options); + else { + StringsBuffer.push_back(Res); + Strings.push_back(StringsBuffer.back().str()); + HasNotDefault = true; + } + } + } else { + if (Cur.startswith("arch=")) { + if (!Context.getTargetInfo().isValidCPUName( + Cur.drop_front(sizeof("arch=") - 1))) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << Architecture + << Cur.drop_front(sizeof("arch=") - 1) << TargetClones; + } else if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << Architecture - << Cur.drop_front(sizeof("arch=") - 1) << TargetClones; - } else if (Cur == "default") { - DefaultIsDupe = HasDefault; - HasDefault = true; - } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Cur << TargetClones; - - if (llvm::is_contained(Strings, Cur) || DefaultIsDupe) - Diag(CurLoc, diag::warn_target_clone_duplicate_options); - // Note: Add even if there are duplicates, since it changes name mangling. - Strings.push_back(Cur); + << Unsupported << None << Cur << TargetClones; + if (llvm::find(Strings, Cur) != Strings.end() || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + // Note: Add even if there are duplicates, since it changes name mangling. + Strings.push_back(Cur); + } } if (Str.rtrim().endswith(",")) @@ -3511,6 +3592,11 @@ } static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (S.Context.getTargetInfo().getTriple().isAArch64()) { + if (!S.Context.getTargetInfo().hasFeature("fmv")) + return; + } + // Ensure we don't combine these with themselves, since that causes some // confusing behavior. if (const auto *Other = D->getAttr()) { @@ -3522,7 +3608,8 @@ return; SmallVector Strings; - bool HasCommas = false, HasDefault = false; + SmallVector, 2> StringsBuffer; + bool HasCommas = false, HasDefault = false, HasNotDefault = false; for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef CurStr; @@ -3531,13 +3618,19 @@ S.checkTargetClonesAttrString( LiteralLoc, CurStr, cast(AL.getArgAsExpr(I)->IgnoreParenCasts()), - HasDefault, HasCommas, Strings)) + HasDefault, HasCommas, HasNotDefault, Strings, StringsBuffer)) return; } if (HasCommas && AL.getNumArgs() > 1) S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values); + if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasDefault) { + // Add default attribute if there is no one + HasDefault = true; + Strings.push_back("default"); + } + if (!HasDefault) { S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default); return; @@ -3554,10 +3647,12 @@ } } - cast(D)->setIsMultiVersion(); - TargetClonesAttr *NewAttr = ::new (S.Context) - TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); - D->addAttr(NewAttr); + if (HasNotDefault || !S.Context.getTargetInfo().getTriple().isAArch64()) { + cast(D)->setIsMultiVersion(); + TargetClonesAttr *NewAttr = ::new (S.Context) + TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); + D->addAttr(NewAttr); + } } static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -8714,6 +8809,9 @@ case ParsedAttr::AT_Target: handleTargetAttr(S, D, AL); break; + case ParsedAttr::AT_TargetVersion: + handleTargetVersionAttr(S, D, AL); + break; case ParsedAttr::AT_TargetClones: handleTargetClonesAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -6391,8 +6391,11 @@ return; } - if (Function->isMultiVersion() && Function->hasAttr() && - !Function->getAttr()->isDefaultVersion()) { + if (Function->isMultiVersion() && + ((Function->hasAttr() && + !Function->getAttr()->isDefaultVersion()) || + (Function->hasAttr() && + !Function->getAttr()->isDefaultVersion()))) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; return; @@ -7040,8 +7043,11 @@ return; } - if (Method->isMultiVersion() && Method->hasAttr() && - !Method->getAttr()->isDefaultVersion()) { + if (Method->isMultiVersion() && + ((Method->hasAttr() && + !Method->getAttr()->isDefaultVersion()) || + (Method->hasAttr() && + !Method->getAttr()->isDefaultVersion()))) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; } @@ -7494,8 +7500,11 @@ return; } - if (Conversion->isMultiVersion() && Conversion->hasAttr() && - !Conversion->getAttr()->isDefaultVersion()) { + if (Conversion->isMultiVersion() && + ((Conversion->hasAttr() && + !Conversion->getAttr()->isDefaultVersion()) || + (Conversion->hasAttr() && + !Conversion->getAttr()->isDefaultVersion()))) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; } @@ -10361,6 +10370,9 @@ if (Fn->isMultiVersion() && Fn->hasAttr() && !Fn->getAttr()->isDefaultVersion()) return; + if (Fn->isMultiVersion() && Fn->hasAttr() && + !Fn->getAttr()->isDefaultVersion()) + return; if (shouldSkipNotingLambdaConversionDecl(Fn)) return; @@ -12162,6 +12174,9 @@ const auto *TA = FunDecl->getAttr(); if (TA && !TA->isDefaultVersion()) return false; + const auto *TVA = FunDecl->getAttr(); + if (TVA && !TVA->isDefaultVersion()) + return false; } // If any candidate has a placeholder return type, trigger its deduction diff --git a/clang/test/AST/attr-target-version.c b/clang/test/AST/attr-target-version.c new file mode 100644 --- /dev/null +++ b/clang/test/AST/attr-target-version.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -ast-dump %s | FileCheck %s + +int __attribute__((target_version("sve_bitperm + sha256"))) foov(void) { return 1; } +int __attribute__((target_clones(" lse + fp + sha512 "))) fooc(void) { return 2; } +// CHECK: TargetVersionAttr +// CHECK: sve_bitperm + sha256 +// CHECK: TargetClonesAttr +// CHECK: fp+lse+sha512 default diff --git a/clang/test/CodeGen/attr-target-clones-aarch64.c b/clang/test/CodeGen/attr-target-clones-aarch64.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-target-clones-aarch64.c @@ -0,0 +1,422 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --check-globals --include-generated-funcs +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fmv -S -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV + +int __attribute__((target_clones("lse+aes", "sve2"))) ftc(void) { return 0; } +int __attribute__((target_clones("sha256", "sha256+mte2", " default "))) ftc_def(void) { return 1; } +int __attribute__((target_clones("sha256", "default"))) ftc_dup1(void) { return 2; } +int __attribute__((target_clones("fp", "crc32+dotprod"))) ftc_dup2(void) { return 3; } +int foo() { + return ftc() + ftc_def() + ftc_dup1() + ftc_dup2(); +} + +inline int __attribute__((target_clones("rng+advsimd", "lrcpc", "sve_aes"))) ftc_inline1(void) { return 1; } +inline int __attribute__((target_clones("fp16", "fcma+sve_bitperm", "default"))) ftc_inline2(void); +inline int __attribute__((target_clones("bti", "sve+sb"))) ftc_inline3(void) { return 3; } + +int __attribute__((target_clones("default"))) ftc_direct(void) { return 4; } + +int __attribute__((target_clones("default"))) main() { + return ftc_inline1() + ftc_inline2() + ftc_inline3() + ftc_direct(); +} +inline int __attribute__((target_clones("fp16", "sve_bitperm+fcma", "default"))) ftc_inline2(void) { return 2; }; + +//. +// CHECK: @__aarch64_cpu_features = external dso_local global { i64 } +// CHECK: @ftc.ifunc = weak_odr ifunc i32 (), ptr @ftc.resolver +// CHECK: @ftc_def.ifunc = weak_odr ifunc i32 (), ptr @ftc_def.resolver +// CHECK: @ftc_dup1.ifunc = weak_odr ifunc i32 (), ptr @ftc_dup1.resolver +// CHECK: @ftc_dup2.ifunc = weak_odr ifunc i32 (), ptr @ftc_dup2.resolver +// CHECK: @ftc_inline1.ifunc = weak_odr ifunc i32 (), ptr @ftc_inline1.resolver +// CHECK: @ftc_inline2.ifunc = weak_odr ifunc i32 (), ptr @ftc_inline2.resolver +// CHECK: @ftc_inline3.ifunc = weak_odr ifunc i32 (), ptr @ftc_inline3.resolver +//. +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc._MaesMlse( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc._Msve2( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK-LABEL: @ftc.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 16512 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 16512 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc._MaesMlse +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 2147483648 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 2147483648 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @ftc._Msve2 +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @ftc +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_def._Msha256( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_def._Mmte2Msha256( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_def( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: @ftc_def.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 274877911040 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 274877911040 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc_def._Mmte2Msha256 +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 4096 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 4096 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @ftc_def._Msha256 +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @ftc_def +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_dup1._Msha256( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_dup1( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: @ftc_dup1.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 4096 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 4096 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc_dup1._Msha256 +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @ftc_dup1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_dup2._Mfp( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_dup2._Mcrc32Mdotprod( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_dup2( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK-LABEL: @ftc_dup2.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1040 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1040 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc_dup2._Mcrc32Mdotprod +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 256 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 256 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @ftc_dup2._Mfp +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @ftc_dup2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @foo( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @ftc.ifunc() +// CHECK-NEXT: [[CALL1:%.*]] = call i32 @ftc_def.ifunc() +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: [[CALL2:%.*]] = call i32 @ftc_dup1.ifunc() +// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NEXT: [[CALL4:%.*]] = call i32 @ftc_dup2.ifunc() +// CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] +// CHECK-NEXT: ret i32 [[ADD5]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_direct( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @main( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: [[CALL:%.*]] = call i32 @ftc_inline1.ifunc() +// CHECK-NEXT: [[CALL1:%.*]] = call i32 @ftc_inline2.ifunc() +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: [[CALL2:%.*]] = call i32 @ftc_inline3.ifunc() +// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NEXT: [[CALL4:%.*]] = call i32 @ftc_direct() +// CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] +// CHECK-NEXT: ret i32 [[ADD5]] +// +// +// CHECK-LABEL: @ftc_inline1.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 513 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 513 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc_inline1._MadvsimdMrng +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 4294967296 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 4294967296 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @ftc_inline1._Msve_aes +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 4194304 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 4194304 +// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] +// CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @ftc_inline1._Mlrcpc +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @ftc_inline1 +// +// +// CHECK-LABEL: @ftc_inline2.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 17181966336 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 17181966336 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc_inline2._MfcmaMsve_bitperm +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 65536 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 65536 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @ftc_inline2._Mfp16 +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @ftc_inline2 +// +// +// CHECK-LABEL: @ftc_inline3.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1099545182208 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1099545182208 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @ftc_inline3._MsbMsve +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 8796093022208 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 8796093022208 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @ftc_inline3._Mbti +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @ftc_inline3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1._MadvsimdMrng( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1._Mlrcpc( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1._Msve_aes( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline2._Mfp16( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline2._MfcmaMsve_bitperm( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline2( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline3._Mbti( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline3._MsbMsve( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline3( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @ftc( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 0 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @ftc_def( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 1 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @ftc_dup1( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 2 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @ftc_dup2( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 3 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @foo( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @ftc() +// CHECK-NOFMV-NEXT: [[CALL1:%.*]] = call i32 @ftc_def() +// CHECK-NOFMV-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NOFMV-NEXT: [[CALL2:%.*]] = call i32 @ftc_dup1() +// CHECK-NOFMV-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NOFMV-NEXT: [[CALL4:%.*]] = call i32 @ftc_dup2() +// CHECK-NOFMV-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] +// CHECK-NOFMV-NEXT: ret i32 [[ADD5]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @ftc_direct( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 4 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @main( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @ftc_inline1() +// CHECK-NOFMV-NEXT: [[CALL1:%.*]] = call i32 @ftc_inline2() +// CHECK-NOFMV-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NOFMV-NEXT: [[CALL2:%.*]] = call i32 @ftc_inline3() +// CHECK-NOFMV-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NOFMV-NEXT: [[CALL4:%.*]] = call i32 @ftc_direct() +// CHECK-NOFMV-NEXT: [[ADD5:%.*]] = add nsw i32 [[ADD3]], [[CALL4]] +// CHECK-NOFMV-NEXT: ret i32 [[ADD5]] +// +//. +// CHECK: attributes #0 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+aes,+lse" } +// CHECK: attributes #1 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sve2" } +// CHECK: attributes #2 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #3 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sha2" } +// CHECK: attributes #4 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mte,+sha2" } +// CHECK: attributes #5 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8" } +// CHECK: attributes #6 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+dotprod" } +// CHECK: attributes #7 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+neon,+rand" } +// CHECK: attributes #8 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+rcpc" } +// CHECK: attributes #9 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sve2-aes" } +// CHECK: attributes #10 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fullfp16" } +// CHECK: attributes #11 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+complxnum,+sve2-bitperm" } +// CHECK: attributes #12 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bti" } +// CHECK: attributes #13 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sb,+sve" } +//. +// CHECK-NOFMV: attributes #0 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" } +// CHECK-NOFMV: attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" } diff --git a/clang/test/CodeGen/attr-target-version.c b/clang/test/CodeGen/attr-target-version.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-target-version.c @@ -0,0 +1,637 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --check-globals --include-generated-funcs +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -fmv -S -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK-NOFMV + +int __attribute__((target_version("rng+flagm+fhm"))) fmv(void) { return 8; } +int __attribute__((target_version("flagm2"))) fmv(void) { return 1; } +int __attribute__((target_version("lse+sha256"))) fmv(void) { return 2; } +int __attribute__((target_version("dotprod+ls64_accdata"))) fmv(void) { return 3; } +int __attribute__((target_version("fhm+mte"))) fmv(void) { return 4; } +int __attribute__((target_version("fp+aes"))) fmv(void) { return 5; } +int __attribute__((target_version("crc32+ls64_v"))) fmv(void) { return 6; } +int __attribute__((target_version("bti"))) fmv(void) { return 7; } +int __attribute__((target_version("ls64"))) fmv(void) { return 8; } +int __attribute__((target_version("default"))) fmv(void) { return 0; } +int foo() { + return fmv(); +} + +inline int __attribute__((target_version("sha1+pmull+sve_f64mm"))) fmv_inline(void) { return 1; } +inline int __attribute__((target_version("fp16+fcma+sme+ fp16 "))) fmv_inline(void) { return 2; } +inline int __attribute__((target_version("sha512+sve_i8mm+sve_f32mm"))) fmv_inline(void) { return 12; } +inline int __attribute__((target_version("dit+sve_ebf16"))) fmv_inline(void) { return 8; } +inline int __attribute__((target_version("dpb+lrcpc2 "))) fmv_inline(void) { return 6; } +inline int __attribute__((target_version(" dpb2 + jscvt"))) fmv_inline(void) { return 7; } +inline int __attribute__((target_version("lrcpc+frintts"))) fmv_inline(void) { return 3; } +inline int __attribute__((target_version("sve+sve_bf16"))) fmv_inline(void) { return 4; } +inline int __attribute__((target_version("sve_aes+sve_sha3"))) fmv_inline(void) { return 5; } +inline int __attribute__((target_version("sve2+sve_pmull128+sve_bitperm"))) fmv_inline(void) { return 9; } +inline int __attribute__((target_version("mte2"))) fmv_inline(void) { return 10; } +inline int __attribute__((target_version("mte3"))) fmv_inline(void) { return 11; } +inline int __attribute__((target_version("default"))) fmv_inline(void) { return 3; } + +__attribute__((target_version("ls64"))) int fmv_e(void); +int fmv_e(void) { return 20; } + +static __attribute__((target_version("sb"))) inline int fmv_d(void); +static __attribute__((target_version("default"))) inline int fmv_d(void); + +int __attribute__((target_version("default"))) fmv_default(void) { return 111; } +int fmv_default(void); + +void fmv_c(void); +void __attribute__((target_version("ssbs"))) fmv_c(void){}; +void __attribute__((target_version("default"))) fmv_c(void){}; + +int goo() { + fmv_inline(); + fmv_e(); + fmv_d(); + fmv_c(); + return fmv_default(); +} +static inline int __attribute__((target_version("sb"))) fmv_d(void) { return 0; } +static inline int __attribute__((target_version(" default "))) fmv_d(void) { return 1; } + +static void func(void) {} +inline __attribute__((target_version("default"))) void recb(void) { func(); } +inline __attribute__((target_version("default"))) void reca(void) { recb(); } +void recur(void) { reca(); } + +int __attribute__((target_version("default"))) main(void) { + recur(); + return goo(); +} + +typedef int (*Fptr)(); +void f(Fptr); +int hoo(void) { + f(fmv); + Fptr fp1 = &fmv; + Fptr fp2 = fmv; + return fp1() + fp2(); +} + +//. +// CHECK: @__aarch64_cpu_features = external dso_local global { i64 } +// CHECK: @fmv.ifunc = weak_odr ifunc i32 (), ptr @fmv.resolver +// CHECK: @fmv_inline.ifunc = weak_odr ifunc i32 (), ptr @fmv_inline.resolver +// CHECK: @fmv_e.ifunc = weak_odr ifunc i32 (), ptr @fmv_e.resolver +// CHECK: @fmv_d.ifunc = internal ifunc i32 (), ptr @fmv_d.resolver +// CHECK: @fmv_c.ifunc = weak_odr ifunc void (), ptr @fmv_c.resolver +//. +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._MrngMflagmMfhm( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 8 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._Mflagm2( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._MlseMsha256( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._MdotprodMls64_accdata( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._MfhmMmte( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._MfpMaes( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 5 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._Mcrc32Mls64_v( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 6 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._Mbti( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 7 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv._Mls64( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 8 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @foo( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @fmv.ifunc() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK-LABEL: @fmv.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 11 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 11 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @fmv._MrngMflagmMfhm +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 70368744177680 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 70368744177680 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @fmv._MdotprodMls64_accdata +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 35184372089856 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 35184372089856 +// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] +// CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @fmv._Mcrc32Mls64_v +// CHECK: resolver_else4: +// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 137438953480 +// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 137438953480 +// CHECK-NEXT: [[TMP15:%.*]] = and i1 true, [[TMP14]] +// CHECK-NEXT: br i1 [[TMP15]], label [[RESOLVER_RETURN5:%.*]], label [[RESOLVER_ELSE6:%.*]] +// CHECK: resolver_return5: +// CHECK-NEXT: ret ptr @fmv._MfhmMmte +// CHECK: resolver_else6: +// CHECK-NEXT: [[TMP16:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 16640 +// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 16640 +// CHECK-NEXT: [[TMP19:%.*]] = and i1 true, [[TMP18]] +// CHECK-NEXT: br i1 [[TMP19]], label [[RESOLVER_RETURN7:%.*]], label [[RESOLVER_ELSE8:%.*]] +// CHECK: resolver_return7: +// CHECK-NEXT: ret ptr @fmv._MfpMaes +// CHECK: resolver_else8: +// CHECK-NEXT: [[TMP20:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP20]], 4224 +// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 4224 +// CHECK-NEXT: [[TMP23:%.*]] = and i1 true, [[TMP22]] +// CHECK-NEXT: br i1 [[TMP23]], label [[RESOLVER_RETURN9:%.*]], label [[RESOLVER_ELSE10:%.*]] +// CHECK: resolver_return9: +// CHECK-NEXT: ret ptr @fmv._MlseMsha256 +// CHECK: resolver_else10: +// CHECK-NEXT: [[TMP24:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP24]], 17592186044416 +// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP25]], 17592186044416 +// CHECK-NEXT: [[TMP27:%.*]] = and i1 true, [[TMP26]] +// CHECK-NEXT: br i1 [[TMP27]], label [[RESOLVER_RETURN11:%.*]], label [[RESOLVER_ELSE12:%.*]] +// CHECK: resolver_return11: +// CHECK-NEXT: ret ptr @fmv._Mls64 +// CHECK: resolver_else12: +// CHECK-NEXT: [[TMP28:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP29:%.*]] = and i64 [[TMP28]], 8796093022208 +// CHECK-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP29]], 8796093022208 +// CHECK-NEXT: [[TMP31:%.*]] = and i1 true, [[TMP30]] +// CHECK-NEXT: br i1 [[TMP31]], label [[RESOLVER_RETURN13:%.*]], label [[RESOLVER_ELSE14:%.*]] +// CHECK: resolver_return13: +// CHECK-NEXT: ret ptr @fmv._Mbti +// CHECK: resolver_else14: +// CHECK-NEXT: [[TMP32:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP33:%.*]] = and i64 [[TMP32]], 4 +// CHECK-NEXT: [[TMP34:%.*]] = icmp eq i64 [[TMP33]], 4 +// CHECK-NEXT: [[TMP35:%.*]] = and i1 true, [[TMP34]] +// CHECK-NEXT: br i1 [[TMP35]], label [[RESOLVER_RETURN15:%.*]], label [[RESOLVER_ELSE16:%.*]] +// CHECK: resolver_return15: +// CHECK-NEXT: ret ptr @fmv._Mflagm2 +// CHECK: resolver_else16: +// CHECK-NEXT: ret ptr @fmv +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_e( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 20 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_default( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 111 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_c._Mssbs( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_c( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @goo( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @fmv_inline.ifunc() +// CHECK-NEXT: [[CALL1:%.*]] = call i32 @fmv_e.ifunc() +// CHECK-NEXT: [[CALL2:%.*]] = call i32 @fmv_d.ifunc() +// CHECK-NEXT: call void @fmv_c.ifunc() +// CHECK-NEXT: [[CALL3:%.*]] = call i32 @fmv_default() +// CHECK-NEXT: ret i32 [[CALL3]] +// +// +// CHECK-LABEL: @fmv_inline.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 68721639424 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 68721639424 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @fmv_inline._Mfp16MfcmaMsmeMfp16 +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 27917287424 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 27917287424 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @fmv_inline._Msve2Msve_pmull128Msve_bitperm +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 1073776640 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 1073776640 +// CHECK-NEXT: [[TMP11:%.*]] = and i1 true, [[TMP10]] +// CHECK-NEXT: br i1 [[TMP11]], label [[RESOLVER_RETURN3:%.*]], label [[RESOLVER_ELSE4:%.*]] +// CHECK: resolver_return3: +// CHECK-NEXT: ret ptr @fmv_inline._Msha1MpmullMsve_f64mm +// CHECK: resolver_else4: +// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 805314560 +// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 805314560 +// CHECK-NEXT: [[TMP15:%.*]] = and i1 true, [[TMP14]] +// CHECK-NEXT: br i1 [[TMP15]], label [[RESOLVER_RETURN5:%.*]], label [[RESOLVER_ELSE6:%.*]] +// CHECK: resolver_return5: +// CHECK-NEXT: ret ptr @fmv_inline._Msha512Msve_i8mmMsve_f32mm +// CHECK: resolver_else6: +// CHECK-NEXT: [[TMP16:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP17:%.*]] = and i64 [[TMP16]], 38654705664 +// CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[TMP17]], 38654705664 +// CHECK-NEXT: [[TMP19:%.*]] = and i1 true, [[TMP18]] +// CHECK-NEXT: br i1 [[TMP19]], label [[RESOLVER_RETURN7:%.*]], label [[RESOLVER_ELSE8:%.*]] +// CHECK: resolver_return7: +// CHECK-NEXT: ret ptr @fmv_inline._Msve_aesMsve_sha3 +// CHECK: resolver_else8: +// CHECK-NEXT: [[TMP20:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP21:%.*]] = and i64 [[TMP20]], 134348800 +// CHECK-NEXT: [[TMP22:%.*]] = icmp eq i64 [[TMP21]], 134348800 +// CHECK-NEXT: [[TMP23:%.*]] = and i1 true, [[TMP22]] +// CHECK-NEXT: br i1 [[TMP23]], label [[RESOLVER_RETURN9:%.*]], label [[RESOLVER_ELSE10:%.*]] +// CHECK: resolver_return9: +// CHECK-NEXT: ret ptr @fmv_inline._MditMsve_ebf16 +// CHECK: resolver_else10: +// CHECK-NEXT: [[TMP24:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP25:%.*]] = and i64 [[TMP24]], 100663296 +// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i64 [[TMP25]], 100663296 +// CHECK-NEXT: [[TMP27:%.*]] = and i1 true, [[TMP26]] +// CHECK-NEXT: br i1 [[TMP27]], label [[RESOLVER_RETURN11:%.*]], label [[RESOLVER_ELSE12:%.*]] +// CHECK: resolver_return11: +// CHECK-NEXT: ret ptr @fmv_inline._MsveMsve_bf16 +// CHECK: resolver_else12: +// CHECK-NEXT: [[TMP28:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP29:%.*]] = and i64 [[TMP28]], 20971520 +// CHECK-NEXT: [[TMP30:%.*]] = icmp eq i64 [[TMP29]], 20971520 +// CHECK-NEXT: [[TMP31:%.*]] = and i1 true, [[TMP30]] +// CHECK-NEXT: br i1 [[TMP31]], label [[RESOLVER_RETURN13:%.*]], label [[RESOLVER_ELSE14:%.*]] +// CHECK: resolver_return13: +// CHECK-NEXT: ret ptr @fmv_inline._MlrcpcMfrintts +// CHECK: resolver_else14: +// CHECK-NEXT: [[TMP32:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP33:%.*]] = and i64 [[TMP32]], 8650752 +// CHECK-NEXT: [[TMP34:%.*]] = icmp eq i64 [[TMP33]], 8650752 +// CHECK-NEXT: [[TMP35:%.*]] = and i1 true, [[TMP34]] +// CHECK-NEXT: br i1 [[TMP35]], label [[RESOLVER_RETURN15:%.*]], label [[RESOLVER_ELSE16:%.*]] +// CHECK: resolver_return15: +// CHECK-NEXT: ret ptr @fmv_inline._MdpbMlrcpc2 +// CHECK: resolver_else16: +// CHECK-NEXT: [[TMP36:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP37:%.*]] = and i64 [[TMP36]], 1572864 +// CHECK-NEXT: [[TMP38:%.*]] = icmp eq i64 [[TMP37]], 1572864 +// CHECK-NEXT: [[TMP39:%.*]] = and i1 true, [[TMP38]] +// CHECK-NEXT: br i1 [[TMP39]], label [[RESOLVER_RETURN17:%.*]], label [[RESOLVER_ELSE18:%.*]] +// CHECK: resolver_return17: +// CHECK-NEXT: ret ptr @fmv_inline._Mdpb2Mjscvt +// CHECK: resolver_else18: +// CHECK-NEXT: [[TMP40:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP41:%.*]] = and i64 [[TMP40]], 549755813888 +// CHECK-NEXT: [[TMP42:%.*]] = icmp eq i64 [[TMP41]], 549755813888 +// CHECK-NEXT: [[TMP43:%.*]] = and i1 true, [[TMP42]] +// CHECK-NEXT: br i1 [[TMP43]], label [[RESOLVER_RETURN19:%.*]], label [[RESOLVER_ELSE20:%.*]] +// CHECK: resolver_return19: +// CHECK-NEXT: ret ptr @fmv_inline._Mmte3 +// CHECK: resolver_else20: +// CHECK-NEXT: [[TMP44:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP45:%.*]] = and i64 [[TMP44]], 274877906944 +// CHECK-NEXT: [[TMP46:%.*]] = icmp eq i64 [[TMP45]], 274877906944 +// CHECK-NEXT: [[TMP47:%.*]] = and i1 true, [[TMP46]] +// CHECK-NEXT: br i1 [[TMP47]], label [[RESOLVER_RETURN21:%.*]], label [[RESOLVER_ELSE22:%.*]] +// CHECK: resolver_return21: +// CHECK-NEXT: ret ptr @fmv_inline._Mmte2 +// CHECK: resolver_else22: +// CHECK-NEXT: ret ptr @fmv_inline +// +// +// CHECK-LABEL: @fmv_e.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 17592186044416 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 17592186044416 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @fmv_e._Mls64 +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @fmv_e +// +// +// CHECK-LABEL: @fmv_d.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1099511627776 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1099511627776 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @fmv_d._Msb +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @fmv_d +// +// +// CHECK-LABEL: @fmv_c.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 2199023255552 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2199023255552 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @fmv_c._Mssbs +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @fmv_c +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @recur( +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @reca() +// CHECK-NEXT: ret void +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @main( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NEXT: call void @recur() +// CHECK-NEXT: [[CALL:%.*]] = call i32 @goo() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @hoo( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[FP1:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[FP2:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: call void @f(ptr noundef @fmv.ifunc) +// CHECK-NEXT: store ptr @fmv.ifunc, ptr [[FP1]], align 8 +// CHECK-NEXT: store ptr @fmv.ifunc, ptr [[FP2]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[FP1]], align 8 +// CHECK-NEXT: [[CALL:%.*]] = call i32 [[TMP0]]() +// CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[FP2]], align 8 +// CHECK-NEXT: [[CALL1:%.*]] = call i32 [[TMP1]]() +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: ret i32 [[ADD]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Msha1MpmullMsve_f64mm( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Mfp16MfcmaMsmeMfp16( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Msha512Msve_i8mmMsve_f32mm( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 12 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._MditMsve_ebf16( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 8 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._MdpbMlrcpc2( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 6 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Mdpb2Mjscvt( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 7 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._MlrcpcMfrintts( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._MsveMsve_bf16( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Msve_aesMsve_sha3( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 5 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Msve2Msve_pmull128Msve_bitperm( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 9 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Mmte2( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 10 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline._Mmte3( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 11 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_inline( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_d._Msb( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @fmv_d( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @fmv( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 0 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @foo( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @fmv() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @fmv_e( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 20 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @fmv_default( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 111 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @fmv_c( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret void +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @goo( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @fmv_inline() +// CHECK-NOFMV-NEXT: [[CALL1:%.*]] = call i32 @fmv_e() +// CHECK-NOFMV-NEXT: [[CALL2:%.*]] = call i32 @fmv_d() +// CHECK-NOFMV-NEXT: call void @fmv_c() +// CHECK-NOFMV-NEXT: [[CALL3:%.*]] = call i32 @fmv_default() +// CHECK-NOFMV-NEXT: ret i32 [[CALL3]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define internal i32 @fmv_d( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 1 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @recur( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: call void @reca() +// CHECK-NOFMV-NEXT: ret void +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @main( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 +// CHECK-NOFMV-NEXT: store i32 0, ptr [[RETVAL]], align 4 +// CHECK-NOFMV-NEXT: call void @recur() +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @goo() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: @hoo( +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[FP1:%.*]] = alloca ptr, align 8 +// CHECK-NOFMV-NEXT: [[FP2:%.*]] = alloca ptr, align 8 +// CHECK-NOFMV-NEXT: call void @f(ptr noundef @fmv) +// CHECK-NOFMV-NEXT: store ptr @fmv, ptr [[FP1]], align 8 +// CHECK-NOFMV-NEXT: store ptr @fmv, ptr [[FP2]], align 8 +// CHECK-NOFMV-NEXT: [[TMP0:%.*]] = load ptr, ptr [[FP1]], align 8 +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 [[TMP0]]() +// CHECK-NOFMV-NEXT: [[TMP1:%.*]] = load ptr, ptr [[FP2]], align 8 +// CHECK-NOFMV-NEXT: [[CALL1:%.*]] = call i32 [[TMP1]]() +// CHECK-NOFMV-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NOFMV-NEXT: ret i32 [[ADD]] +// +//. +// CHECK: attributes #0 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+flagm,+rand" } +// CHECK: attributes #1 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+flagm" } +// CHECK: attributes #2 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,+sha2" } +// CHECK: attributes #3 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dotprod,+ls64" } +// CHECK: attributes #4 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+mte" } +// CHECK: attributes #5 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+aes,+fp-armv8" } +// CHECK: attributes #6 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+ls64" } +// CHECK: attributes #7 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bti" } +// CHECK: attributes #8 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ls64" } +// CHECK: attributes #9 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #10 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ssbs" } +// CHECK: attributes #11 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #12 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+f64mm" } +// CHECK: attributes #13 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+complxnum,+fullfp16,+sme" } +// CHECK: attributes #14 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+f32mm,+i8mm,+sha3" } +// CHECK: attributes #15 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dit" } +// CHECK: attributes #16 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+rcpc" } +// CHECK: attributes #17 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+jsconv" } +// CHECK: attributes #18 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fptoint,+rcpc" } +// CHECK: attributes #19 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sve" } +// CHECK: attributes #20 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sve2-aes,+sve2-sha3" } +// CHECK: attributes #21 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sve2,+sve2-bitperm" } +// CHECK: attributes #22 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ls64" } +// CHECK: attributes #23 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sb" } +//. +// CHECK-NOFMV: attributes #0 = { noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" } +// CHECK-NOFMV: attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" } diff --git a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp @@ -0,0 +1,247 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --check-globals --include-generated-funcs +// RUN: %clang_cc1 -std=c++11 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +int __attribute__((target_clones("ls64_v", "default"))) foo_ovl(int) { return 1; } +int __attribute__((target_clones("ls64_accdata"))) foo_ovl(void) { return 2; } + +int bar() { + return foo_ovl(1) + foo_ovl(); +} + +template class MyClass { +public: + int __attribute__((target_clones("frintts", "ssbs"))) foo_tml() { return 1; } +}; + +template class MyClass { +public: + int __attribute__((target_clones("frintts", "ssbs"))) foo_tml() { return 2; } +}; + +template class MyClass { +public: + int foo_tml() { return 3; } +}; + +template <> class MyClass { +public: + int __attribute__((target_clones("default"))) foo_tml() { return 4; } +}; + +void run_foo_tml() { + MyClass Mc1; + Mc1.foo_tml(); + MyClass Mc2; + Mc2.foo_tml(); + MyClass Mc3; + Mc3.foo_tml(); + MyClass Mc4; + Mc4.foo_tml(); +} + +//. +// CHECK: @__aarch64_cpu_features = external dso_local global { i64 } +// CHECK: @_Z7foo_ovli.ifunc = weak_odr ifunc i32 (i32), ptr @_Z7foo_ovli.resolver +// CHECK: @_Z7foo_ovlv.ifunc = weak_odr ifunc i32 (), ptr @_Z7foo_ovlv.resolver +// CHECK: @_ZN7MyClassIssE7foo_tmlEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN7MyClassIssE7foo_tmlEv.resolver +// CHECK: @_ZN7MyClassIisE7foo_tmlEv.ifunc = weak_odr ifunc i32 (ptr), ptr @_ZN7MyClassIisE7foo_tmlEv.resolver +//. +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z7foo_ovli._Mls64_v( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z7foo_ovli( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK-LABEL: @_Z7foo_ovli.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 35184372088832 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 35184372088832 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z7foo_ovli._Mls64_v +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z7foo_ovli +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z7foo_ovlv._Mls64_accdata( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z7foo_ovlv( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: @_Z7foo_ovlv.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 70368744177664 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 70368744177664 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z7foo_ovlv._Mls64_accdata +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z7foo_ovlv +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z3barv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_Z7foo_ovli.ifunc(i32 noundef 1) +// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z7foo_ovlv.ifunc() +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: ret i32 [[ADD]] +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z11run_foo_tmlv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[MC1:%.*]] = alloca [[CLASS_MYCLASS:%.*]], align 1 +// CHECK-NEXT: [[MC2:%.*]] = alloca [[CLASS_MYCLASS_0:%.*]], align 1 +// CHECK-NEXT: [[MC3:%.*]] = alloca [[CLASS_MYCLASS_1:%.*]], align 1 +// CHECK-NEXT: [[MC4:%.*]] = alloca [[CLASS_MYCLASS_2:%.*]], align 1 +// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN7MyClassIssE7foo_tmlEv.ifunc(ptr noundef nonnull align 1 dereferenceable(1) [[MC1]]) +// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_ZN7MyClassIisE7foo_tmlEv.ifunc(ptr noundef nonnull align 1 dereferenceable(1) [[MC2]]) +// CHECK-NEXT: [[CALL2:%.*]] = call noundef i32 @_ZN7MyClassIfsE7foo_tmlEv(ptr noundef nonnull align 1 dereferenceable(1) [[MC3]]) +// CHECK-NEXT: [[CALL3:%.*]] = call noundef i32 @_ZN7MyClassIdfE7foo_tmlEv(ptr noundef nonnull align 1 dereferenceable(1) [[MC4]]) +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: @_ZN7MyClassIssE7foo_tmlEv.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 2199023255552 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2199023255552 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_ZN7MyClassIssE7foo_tmlEv._Mssbs +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16777216 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16777216 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_ZN7MyClassIssE7foo_tmlEv._Mfrintts +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @_ZN7MyClassIssE7foo_tmlEv +// +// +// CHECK-LABEL: @_ZN7MyClassIisE7foo_tmlEv.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 2199023255552 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 2199023255552 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_ZN7MyClassIisE7foo_tmlEv._Mssbs +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16777216 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16777216 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_ZN7MyClassIisE7foo_tmlEv._Mfrintts +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @_ZN7MyClassIisE7foo_tmlEv +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIfsE7foo_tmlEv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIdfE7foo_tmlEv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 4 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIssE7foo_tmlEv._Mfrintts( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIssE7foo_tmlEv._Mssbs( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIssE7foo_tmlEv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIisE7foo_tmlEv._Mfrintts( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIisE7foo_tmlEv._Mssbs( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClassIisE7foo_tmlEv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 2 +// +//. +// CHECK: attributes #0 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ls64" } +// CHECK: attributes #1 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #2 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fptoint" } +// CHECK: attributes #3 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ssbs" } diff --git a/clang/test/CodeGenCXX/attr-target-version.cpp b/clang/test/CodeGenCXX/attr-target-version.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-target-version.cpp @@ -0,0 +1,158 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --check-globals --include-generated-funcs +// RUN: %clang_cc1 -std=c++11 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +int __attribute__((target_version("rng"))) foo(int) { return 1; } +int __attribute__((target_version("default"))) foo(int) { return 2; } +int __attribute__((target_version("sm"))) foo(void) { return 3; } +int __attribute__((target_version("default"))) foo(void) { return 4; } + +class MyClass { +public: + int __attribute__((target_version("dotprod"))) goo(int); + int __attribute__((target_version("crc32"))) goo(int); + int __attribute__((target_version("default"))) goo(int); +}; + +int __attribute__((target_version("default"))) MyClass::goo(int) { return 1; } +int __attribute__((target_version("crc32"))) MyClass::goo(int) { return 2; } +int __attribute__((target_version("dotprod"))) MyClass::goo(int) { return 3; } + +int bar() { + MyClass m; + return m.goo(1) + foo(1) + foo(); +} + +//. +// CHECK: @__aarch64_cpu_features = external dso_local global { i64 } +// CHECK: @_ZN7MyClass3gooEi.ifunc = weak_odr ifunc i32 (ptr, i32), ptr @_ZN7MyClass3gooEi.resolver +// CHECK: @_Z3fooi.ifunc = weak_odr ifunc i32 (i32), ptr @_Z3fooi.resolver +// CHECK: @_Z3foov.ifunc = weak_odr ifunc i32 (), ptr @_Z3foov.resolver +//. +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z3fooi._Mrng( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z3fooi( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z3foov._Msm( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z3foov( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 4 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClass3gooEi( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClass3gooEi._Mcrc32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_ZN7MyClass3gooEi._Mdotprod( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[DOTADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: store i32 [[TMP0:%.*]], ptr [[DOTADDR]], align 4 +// CHECK-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8 +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: mustprogress noinline nounwind optnone +// CHECK-LABEL: @_Z3barv( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[M:%.*]] = alloca [[CLASS_MYCLASS:%.*]], align 1 +// CHECK-NEXT: [[CALL:%.*]] = call noundef i32 @_ZN7MyClass3gooEi.ifunc(ptr noundef nonnull align 1 dereferenceable(1) [[M]], i32 noundef 1) +// CHECK-NEXT: [[CALL1:%.*]] = call noundef i32 @_Z3fooi.ifunc(i32 noundef 1) +// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL]], [[CALL1]] +// CHECK-NEXT: [[CALL2:%.*]] = call noundef i32 @_Z3foov.ifunc() +// CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD]], [[CALL2]] +// CHECK-NEXT: ret i32 [[ADD3]] +// +// +// CHECK-LABEL: @_ZN7MyClass3gooEi.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1024 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1024 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_ZN7MyClass3gooEi._Mcrc32 +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 16 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 16 +// CHECK-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]] +// CHECK-NEXT: br i1 [[TMP7]], label [[RESOLVER_RETURN1:%.*]], label [[RESOLVER_ELSE2:%.*]] +// CHECK: resolver_return1: +// CHECK-NEXT: ret ptr @_ZN7MyClass3gooEi._Mdotprod +// CHECK: resolver_else2: +// CHECK-NEXT: ret ptr @_ZN7MyClass3gooEi +// +// +// CHECK-LABEL: @_Z3fooi.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z3fooi._Mrng +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z3fooi +// +// +// CHECK-LABEL: @_Z3foov.resolver( +// CHECK-NEXT: resolver_entry: +// CHECK-NEXT: call void @init_cpu_features_resolver() +// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 32 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 32 +// CHECK-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]] +// CHECK-NEXT: br i1 [[TMP3]], label [[RESOLVER_RETURN:%.*]], label [[RESOLVER_ELSE:%.*]] +// CHECK: resolver_return: +// CHECK-NEXT: ret ptr @_Z3foov._Msm +// CHECK: resolver_else: +// CHECK-NEXT: ret ptr @_Z3foov +// +//. +// CHECK: attributes #0 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+rand" } +// CHECK: attributes #1 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #2 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+sm4" } +// CHECK: attributes #3 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc" } +// CHECK: attributes #4 = { mustprogress noinline nounwind optnone "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dotprod" } diff --git a/clang/test/Driver/aarch64-features.c b/clang/test/Driver/aarch64-features.c --- a/clang/test/Driver/aarch64-features.c +++ b/clang/test/Driver/aarch64-features.c @@ -6,6 +6,11 @@ // The AArch64 PCS states that chars should be unsigned. // CHECK: fno-signed-char +// Check option to disable Function Multi Versioning option. +// RUN: %clang -target aarch64-linux-gnu -### %s -mno-fmv -fsyntax-only 2>&1 | \ +// RUN: FileCheck -check-prefix=CHECK-NO-FMV %s +// CHECK-NO-FMV: "-target-feature" "-fmv" + // Check for AArch64 out-of-line atomics default settings. // RUN: %clang -target aarch64-linux-android -rtlib=compiler-rt \ // RUN: -### -c %s 2>&1 | FileCheck -check-prefix=CHECK-OUTLINE-ATOMICS-ON %s diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -178,6 +178,7 @@ // CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local) // CHECK-NEXT: Target (SubjectMatchRule_function) // CHECK-NEXT: TargetClones (SubjectMatchRule_function) +// CHECK-NEXT: TargetVersion (SubjectMatchRule_function) // CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member) // CHECK-NEXT: TrivialABI (SubjectMatchRule_record) // CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local) diff --git a/clang/test/Preprocessor/init-aarch64.c b/clang/test/Preprocessor/init-aarch64.c --- a/clang/test/Preprocessor/init-aarch64.c +++ b/clang/test/Preprocessor/init-aarch64.c @@ -22,6 +22,7 @@ // AARCH64-NEXT: #define __ARM_FEATURE_DIRECTED_ROUNDING 1 // AARCH64-NEXT: #define __ARM_FEATURE_DIV 1 // AARCH64-NEXT: #define __ARM_FEATURE_FMA 1 +// AARCH64-NEXT: #define __ARM_FEATURE_FUNCTION_MULTI_VERSIONING 1 // AARCH64-NEXT: #define __ARM_FEATURE_IDIV 1 // AARCH64-NEXT: #define __ARM_FEATURE_LDREX 0xF // AARCH64-NEXT: #define __ARM_FEATURE_NUMERIC_MAXMIN 1 @@ -110,12 +111,12 @@ // AARCH64-NEXT: #define __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 1 // AARCH64_CXX-NEXT: #define __GLIBCXX_BITSIZE_INT_N_0 128 // AARCH64_CXX-NEXT: #define __GLIBCXX_TYPE_INT_N_0 __int128 -// AARCH64-NEXT: #define __INT16_C_SUFFIX__ +// AARCH64-NEXT: #define __INT16_C_SUFFIX__ // AARCH64-NEXT: #define __INT16_FMTd__ "hd" // AARCH64-NEXT: #define __INT16_FMTi__ "hi" // AARCH64-NEXT: #define __INT16_MAX__ 32767 // AARCH64-NEXT: #define __INT16_TYPE__ short -// AARCH64-NEXT: #define __INT32_C_SUFFIX__ +// AARCH64-NEXT: #define __INT32_C_SUFFIX__ // AARCH64-NEXT: #define __INT32_FMTd__ "d" // AARCH64-NEXT: #define __INT32_FMTi__ "i" // AARCH64-NEXT: #define __INT32_MAX__ 2147483647 @@ -125,7 +126,7 @@ // AARCH64-NEXT: #define __INT64_FMTi__ "li" // AARCH64-NEXT: #define __INT64_MAX__ 9223372036854775807L // AARCH64-NEXT: #define __INT64_TYPE__ long int -// AARCH64-NEXT: #define __INT8_C_SUFFIX__ +// AARCH64-NEXT: #define __INT8_C_SUFFIX__ // AARCH64-NEXT: #define __INT8_FMTd__ "hhd" // AARCH64-NEXT: #define __INT8_FMTi__ "hhi" // AARCH64-NEXT: #define __INT8_MAX__ 127 @@ -253,7 +254,7 @@ // AARCH64-NEXT: #define __STDC_UTF_32__ 1 // AARCH64_C: #define __STDC_VERSION__ 201710L // AARCH64-NEXT: #define __STDC__ 1 -// AARCH64-NEXT: #define __UINT16_C_SUFFIX__ +// AARCH64-NEXT: #define __UINT16_C_SUFFIX__ // AARCH64-NEXT: #define __UINT16_FMTX__ "hX" // AARCH64-NEXT: #define __UINT16_FMTo__ "ho" // AARCH64-NEXT: #define __UINT16_FMTu__ "hu" @@ -274,7 +275,7 @@ // AARCH64-NEXT: #define __UINT64_FMTx__ "lx" // AARCH64-NEXT: #define __UINT64_MAX__ 18446744073709551615UL // AARCH64-NEXT: #define __UINT64_TYPE__ long unsigned int -// AARCH64-NEXT: #define __UINT8_C_SUFFIX__ +// AARCH64-NEXT: #define __UINT8_C_SUFFIX__ // AARCH64-NEXT: #define __UINT8_FMTX__ "hhX" // AARCH64-NEXT: #define __UINT8_FMTo__ "hho" // AARCH64-NEXT: #define __UINT8_FMTu__ "hhu" @@ -344,7 +345,7 @@ // AARCH64-NEXT: #define __UINT_LEAST8_FMTx__ "hhx" // AARCH64-NEXT: #define __UINT_LEAST8_MAX__ 255 // AARCH64-NEXT: #define __UINT_LEAST8_TYPE__ unsigned char -// AARCH64-NEXT: #define __USER_LABEL_PREFIX__ +// AARCH64-NEXT: #define __USER_LABEL_PREFIX__ // AARCH64-NEXT: #define __VERSION__ "{{.*}}" // AARCH64-NEXT: #define __WCHAR_MAX__ 4294967295U // AARCH64-NEXT: #define __WCHAR_TYPE__ unsigned int @@ -566,6 +567,7 @@ // AARCH64-MSVC: #define __ARM_FEATURE_DIRECTED_ROUNDING 1 // AARCH64-MSVC: #define __ARM_FEATURE_DIV 1 // AARCH64-MSVC: #define __ARM_FEATURE_FMA 1 +// AARCH64-MSVC: #define __ARM_FEATURE_FUNCTION_MULTI_VERSIONING 1 // AARCH64-MSVC: #define __ARM_FEATURE_IDIV 1 // AARCH64-MSVC: #define __ARM_FEATURE_LDREX 0xF // AARCH64-MSVC: #define __ARM_FEATURE_NUMERIC_MAXMIN 1 diff --git a/clang/test/Sema/attr-target-clones-aarch64.c b/clang/test/Sema/attr-target-clones-aarch64.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-target-clones-aarch64.c @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify %s + +void __attribute__((target_clones("fp16+sve_aes", "sb+sve_sha3"))) no_def(void); + +// expected-warning@+1 {{unsupported 'default' in the 'target_clones' attribute string; 'target_clones' attribute ignored}} +void __attribute__((target_clones("default+sha512"))) warn1(void); +// expected-warning@+1 {{version list contains no code impact entries}} +void __attribute__((target_clones("sha1+pmull"))) warn2(void); + +// expected-error@+2 {{'target_clones' and 'target_version' attributes are not compatible}} +// expected-note@+1 {{conflicting attribute is here}} +void __attribute__((target_version("sve_bf16"), target_clones("sme+mte"))) not_compat(void); + +int redecl(void); +int __attribute__((target_clones("frintts", "advsimd+fp", "default"))) redecl(void) { return 1; } + +int __attribute__((target_clones("jscvt+fcma", "lrcpc", "default"))) redecl2(void); +int __attribute__((target_clones("jscvt+fcma", "lrcpc"))) redecl2(void) { return 1; } + +int __attribute__((target_clones("sve+dotprod"))) redecl3(void); +int redecl3(void); + +int __attribute__((target_clones("rng", "fhm+fp", "default"))) redecl4(void); +// expected-error@+3 {{'target_clones' attribute does not match previous declaration}} +// expected-note@-2 {{previous declaration is here}} +// expected-warning@+1 {{version list contains no code impact entries}} +int __attribute__((target_clones("rng", "fhm+dpb+sha1", "default"))) redecl4(void) { return 1; } + +int __attribute__((target_version("flagm2"))) redef2(void) { return 1; } +// expected-error@+2 {{multiversioning attributes cannot be combined}} +// expected-note@-2 {{previous declaration is here}} +int __attribute__((target_clones("flagm2", "default"))) redef2(void) { return 1; } + +int __attribute__((target_clones("sve_f32mm", "sve_f64mm", "sha1+fp"))) redef3(void) { return 1; } +// expected-error@+2 {{'target_clones' attribute does not match previous declaration}} +// expected-note@-2 {{previous declaration is here}} +int __attribute__((target_clones("sve_f32mm", "sha1+fp", "sve_f64mm"))) redef3(void) { return 1; } + +int __attribute__((target_clones("rdm+lse+rdm", "lse+rdm"))) dup1(void) { return 1; } +// expected-warning@+1 {{version list contains duplicate entries}} +int __attribute__((target_clones("rdm+lse+rdm", "rdm+lse+rdm"))) dup2(void) { return 2; } +// expected-warning@+1 {{version list contains duplicate entries}} +int __attribute__((target_clones("lrcpc2+sve_pmull128", "lrcpc2+sve_pmull128"))) dup3(void) { return 3; } +// expected-warning@+1 {{version list contains duplicate entries}} +void __attribute__((target_clones("sha512", "default", "default"))) dup4(void); +// expected-warning@+2 {{version list contains duplicate entries}} +// expected-warning@+1 {{version list contains duplicate entries}} +int __attribute__((target_clones("fp", "fp", "crc32+dotprod", "dotprod+crc32"))) dup5(void) { return 5; } + +// expected-warning@+1 {{version list contains duplicate entries}} +int __attribute__((target_clones("fp16+mte", "mte+fp16"))) dup6(void) { return 6; } +int __attribute__((target_clones("advsimd+ssbs2", "advsimd+dpb2"))) dup7(void) { return 7; } + +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +void __attribute__((target_clones(""))) empty_target_1(void); +// expected-warning@+2 {{unsupported 'default' in the 'target_clones' attribute string;}} +// expected-warning@+1 {{unsupported 'default' in the 'target_clones' attribute string;}} +void __attribute__((target_clones("default+default"))) empty_target_2(void); +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +void __attribute__((target_clones("+sve2"))) +empty_target_3(void); +// expected-warning@+1 {{unsupported 'bs' in the 'target_clones' attribute string;}} +void __attribute__((target_clones("sb+bs"))) +empty_target_4(void); + +// expected-warning@+1 {{unsupported '' in the 'target_clones' attribute string;}} +void __attribute__((target_clones("default", ""))) +empty_target_5(void); + +// expected-warning@+1 {{version list contains duplicate entries}} +void __attribute__((target_clones("sve_bitperm", "sve_bitperm"))) +dupe_normal(void); + +void __attribute__((target_clones("default"), target_clones("mte3+bti"))) dupe_normal2(void); + +int mv_after_use(void); +int useage(void) { + return mv_after_use(); +} +// expected-error@+1 {{function declaration cannot become a multiversioned function after first usage}} +int __attribute__((target_clones("sve_sha3+ssbs2", "sm"))) mv_after_use(void) { return 1; } +// expected-error@+1 {{'main' cannot be a multiversioned function}} +int __attribute__((target_clones("sve_i8mm"))) main() { return 1; } diff --git a/clang/test/Sema/attr-target-version.c b/clang/test/Sema/attr-target-version.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/attr-target-version.c @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify %s + +int __attribute__((target_version("crc32"))) dup(void) { return 3; } +int __attribute__((target_version("default"))) dup(void) { return 1; } +//expected-error@+2 {{redefinition of 'dup'}} +//expected-note@-2 {{previous definition is here}} +int __attribute__((target_version("default"))) dup(void) { return 2; } + +int __attribute__((target_version("default"))) dup1(void) { return 1; } +//expected-error@+2 {{redefinition of 'dup1'}} +//expected-note@-2 {{previous definition is here}} +int dup1(void) { return 2; } + +int __attribute__((target_version("aes"))) foo(void) { return 1; } +//expected-note@+1 {{previous definition is here}} +int __attribute__((target_version("default"))) foo(void) { return 2; } + +//expected-note@+1 {{previous declaration is here}} +int __attribute__((target_version("sha512 + pmull "))) foo(void) { return 1; } + +//expected-error@+1 {{multiversioning attributes cannot be combined}} +int __attribute__((target("dotprod"))) foo(void) { return -1; } + +//expected-error@+1 {{redefinition of 'foo'}} +int foo(void) { return 2; } + +//expected-note@+1 {{previous declaration is here}} +void __attribute__((target_version("bti+flagm2"))) one(void) {} +//expected-error@+1 {{multiversioned function redeclarations require identical target attributes}} +void __attribute__((target_version("flagm2+bti"))) one(void) {} + +void __attribute__((target_version("ssbs+sha1"))) two(void) {} +void __attribute__((target_version("ssbs+fhm"))) two(void) {} + +//expected-error@+1 {{'main' cannot be a multiversioned function}} +int __attribute__((target_version("lse"))) main(void) { return 1; } + +//expected-note@+1 {{previous definition is here}} +int hoo(void) { return 1; } +//expected-note@-1 {{previous definition is here}} +//expected-warning@+2 {{attribute declaration must precede definition}} +//expected-error@+1 {{redefinition of 'hoo'}} +int __attribute__((target_version("dit"))) hoo(void) { return 2; } + +//expected-warning@+1 {{unsupported '' in the 'target_version' attribute string; 'target_version' attribute ignored}} +int __attribute__((target_version(""))) unsup1(void) { return 1; } +//expected-warning@+1 {{unsupported 'crc' in the 'target_version' attribute string; 'target_version' attribute ignored}} +void __attribute__((target_version("crc"))) unsup2(void) {} + +void __attribute__((target_version("default+fp16"))) koo(void) {} +void __attribute__((target_version("default+default+default"))) loo(void) {} +void __attribute__((target_version("rdm+rng+crc32"))) redef(void) {} +//expected-error@+2 {{redefinition of 'redef'}} +//expected-note@-2 {{previous definition is here}} +void __attribute__((target_version("rdm+rng+crc32"))) redef(void) {} + +int __attribute__((target_version("sm"))) def(void); +void __attribute__((target_version("dit"))) nodef(void); +void __attribute__((target_version("ls64"))) nodef(void); +void __attribute__((target_version("aes"))) ovl(void); +void __attribute__((target_version("default"))) ovl(void); +int bar() { + // expected-error@+2 {{reference to overloaded function could not be resolved; did you mean to call it?}} + // expected-note@-3 {{possible target for call}} + ovl++; + // expected-error@+1 {{no matching function for call to 'nodef'}} + nodef(); + return def(); +} +// expected-error@+1 {{function declaration cannot become a multiversioned function after first usage}} +int __attribute__((target_version("sha1"))) def(void) { return 1; } + +int __attribute__((target_version("sve"))) prot(); +// expected-error@-1 {{multiversioned function must have a prototype}} +// expected-note@+1 {{function multiversioning caused by this declaration}} +int __attribute__((target_version("fcma"))) prot(); + +int __attribute__((target_version("pmull"))) rtype(int); +// expected-error@+1 {{multiversioned function declaration has a different return type}} +float __attribute__((target_version("rdm"))) rtype(int); + +int __attribute__((target_version("sha256"))) combine(void) { return 1; } +// expected-error@+1 {{multiversioned function declaration has a different calling convention}} +int __attribute__((aarch64_vector_pcs, target_version("sha512"))) combine(void) { return 2; } diff --git a/clang/test/SemaCXX/attr-target-clones-aarch64.cpp b/clang/test/SemaCXX/attr-target-clones-aarch64.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-target-clones-aarch64.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++14 + +void lambda() { + // expected-error@+1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}} + auto x = []() __attribute__((target_clones("default"))){}; + x(); + // expected-error@+1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}} + auto y = []() __attribute__((target_clones("fp16+lse", "rdm"))){}; + y(); +} diff --git a/clang/test/SemaCXX/attr-target-version.cpp b/clang/test/SemaCXX/attr-target-version.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/attr-target-version.cpp @@ -0,0 +1,101 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++14 +void __attribute__((target_version("default"))) wrong_tv(void); +//expected-warning@+1 {{unsupported 'vmull' in the 'target_version' attribute string; 'target_version' attribute ignored}} +void __attribute__((target_version("vmull"))) wrong_tv(void); + +void __attribute__((target_version("dotprod"))) no_def(void); +void __attribute__((target_version("rdm+fp"))) no_def(void); + +// expected-error@+1 {{no matching function for call to 'no_def'}} +void foo(void) { no_def(); } + +constexpr int __attribute__((target_version("sve2"))) diff_const(void) { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different constexpr specification}} +int __attribute__((target_version("sve_bitperm"))) diff_const(void); + +int __attribute__((target_version("fp"))) diff_const1(void) { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different constexpr specification}} +constexpr int __attribute__((target_version("sve_aes"))) diff_const1(void); + +static int __attribute__((target_version("sve_sha3"))) diff_link(void) { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different linkage}} +int __attribute__((target_version("dpb"))) diff_link(void); + +int __attribute__((target_version("mte"))) diff_link1(void) { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different linkage}} +static int __attribute__((target_version("bti"))) diff_link1(void); + +int __attribute__((target_version("flagm2"))) diff_link2(void) { return 1; } +extern int __attribute__((target_version("flagm"))) diff_link2(void); + +namespace { +static int __attribute__((target_version("mte3"))) diff_link2(void) { return 2; } +int __attribute__((target_version("sve_bitperm"))) diff_link2(void) { return 1; } +} // namespace + +inline int __attribute__((target_version("sme"))) diff_inline(void) { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different inline specification}} +int __attribute__((target_version("fp16"))) diff_inline(void) { return 2; } + +inline int __attribute__((target_version("sme"))) diff_inline1(void) { return 1; } +int __attribute__((target_version("default"))) diff_inline1(void) { return 2; } + +int __attribute__((target_version("fcma"))) diff_type1(void) { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different return type}} +double __attribute__((target_version("lrcpc"))) diff_type1(void); + +auto __attribute__((target_version("lrcpc2"))) diff_type2(void) -> int { return 1; } +//expected-error@+1 {{multiversioned function declaration has a different return type}} +auto __attribute__((target_version("sve_bf16"))) diff_type2(void) -> long { return (long)1; } + +int __attribute__((target_version("fhm"))) diff_type3(void) noexcept(false) { return 1; } +//expected-error@+2 {{exception specification in declaration does not match previous declaration}} +//expected-note@-2 {{previous declaration is here}} +int __attribute__((target_version("sve_sha3"))) diff_type3(void) noexcept(true) { return 2; } + +template int __attribute__((target_version("default"))) temp(T) { return 1; } + +template int __attribute__((target_version("advsimd"))) temp1(T) { return 1; } +// expected-error@+1 {{attribute 'target_version' multiversioned functions do not yet support function templates}} +template int __attribute__((target_version("sha512"))) temp1(T) { return 2; } + +extern "C" { +int __attribute__((target_version("aes"))) extc(void) { return 1; } +} +//expected-error@+1 {{multiversioned function declaration has a different language linkage}} +int __attribute__((target_version("lse"))) extc(void) { return 1; } + +auto __attribute__((target_version("default"))) ret1(void) { return 1; } +auto __attribute__((target_version("dpb"))) ret2(void) { return 1; } +auto __attribute__((target_version("dpb2"))) ret3(void) -> int { return 1; } + +class Cls { + __attribute__((target_version("rng"))) Cls(); + __attribute__((target_version("sve_i8mm"))) ~Cls(); + + Cls &__attribute__((target_version("sve_f32mm"))) operator=(const Cls &) = default; + Cls &__attribute__((target_version("ssbs"))) operator=(Cls &&) = delete; + + virtual void __attribute__((target_version("default"))) vfunc(); + virtual void __attribute__((target_version("sm"))) vfunc1(); +}; + +__attribute__((target_version("sha512"))) void Decl(); +namespace Nms { +using ::Decl; +// expected-error@+3 {{declaration conflicts with target of using declaration already in scope}} +// expected-note@-4 {{target of using declaration}} +// expected-note@-3 {{using declaration}} +__attribute__((target_version("jscvt"))) void Decl(); +} // namespace Nms + +class Out { + int __attribute__((target_version("bti"))) func(void); + int __attribute__((target_version("ssbs2"))) func(void); +}; +int __attribute__((target_version("bti"))) Out::func(void) { return 1; } +int __attribute__((target_version("ssbs2"))) Out::func(void) { return 2; } +// expected-error@+3 {{out-of-line definition of 'func' does not match any declaration in 'Out'}} +// expected-note@-3 {{member declaration nearly matches}} +// expected-note@-3 {{member declaration nearly matches}} +int __attribute__((target_version("rng"))) Out::func(void) { return 3; } diff --git a/compiler-rt/lib/builtins/cpu_model.c b/compiler-rt/lib/builtins/cpu_model.c --- a/compiler-rt/lib/builtins/cpu_model.c +++ b/compiler-rt/lib/builtins/cpu_model.c @@ -9,7 +9,7 @@ // This file is based on LLVM's lib/Support/Host.cpp. // It implements the operating system Host concept and builtin // __cpu_model for the compiler_rt library for x86 and -// __aarch64_have_lse_atomics for AArch64. +// __aarch64_have_lse_atomics, __aarch64_cpu_features for AArch64. // //===----------------------------------------------------------------------===// @@ -792,6 +792,66 @@ return 0; } #elif defined(__aarch64__) +// CPUFeatures corrsepond to the same +// AArch64 features in llvm +enum CPUFeatures { + FEAT_RNG, + FEAT_FLAGM, + FEAT_FLAGM2, + FEAT_FHM, + FEAT_DOTPROD, + FEAT_SM, + FEAT_RDM, + FEAT_LSE, + FEAT_FP, + FEAT_ADVSIMD, + FEAT_CRC32, + FEAT_SHA1, + FEAT_SHA256, + FEAT_SHA512, + FEAT_AES, + FEAT_PMULL, + FEAT_FP16, + FEAT_DIT, + FEAT_DPB, + FEAT_DPB2, + FEAT_JSCVT, + FEAT_FCMA, + FEAT_LRCPC, + FEAT_LRCPC2, + FEAT_FRINTTS, + FEAT_SVE, + FEAT_BF16, + FEAT_EBF16, + FEAT_I8MM, + FEAT_F32MM, + FEAT_F64MM, + FEAT_SVE2, + FEAT_SVE_AES, + FEAT_SVE_PMULL128, + FEAT_SVE_BITPERM, + FEAT_SVE_SHA3, + FEAT_SME, + FEAT_MTE, + FEAT_MTE2, + FEAT_MTE3, + FEAT_SB, + FEAT_SSBS, + FEAT_SSBS2, + FEAT_BTI, + FEAT_LS64, + FEAT_LS64_V, + FEAT_LS64_ACCDATA, + FEAT_MAX +}; + +// Architecture features used +// in Function Multi Versioning +struct { + unsigned long long features; + // As features grows new fields could be added +} __aarch64_cpu_features __attribute__((visibility("hidden"), nocommon)); + // LSE support detection for out-of-line atomics // using HWCAP and Auxiliary vector _Bool __aarch64_have_lse_atomics @@ -799,12 +859,135 @@ #if defined(__has_include) #if __has_include() #include +#if __has_include() +#include + #ifndef AT_HWCAP #define AT_HWCAP 16 #endif + +#ifndef HWCAP_FP +#define HWCAP_FP (1 << 0) +#endif +#ifndef HWCAP_ASIMD +#define HWCAP_ASIMD (1 << 1) +#endif +#ifndef HWCAP_AES +#define HWCAP_AES (1 << 3) +#endif +#ifndef HWCAP_PMULL +#define HWCAP_PMULL (1 << 4) +#endif +#ifndef HWCAP_SHA1 +#define HWCAP_SHA1 (1 << 5) +#endif +#ifndef HWCAP_SHA2 +#define HWCAP_SHA2 (1 << 6) +#endif #ifndef HWCAP_ATOMICS #define HWCAP_ATOMICS (1 << 8) #endif +#ifndef HWCAP_FPHP +#define HWCAP_FPHP (1 << 9) +#endif +#ifndef HWCAP_ASIMDHP +#define HWCAP_ASIMDHP (1 << 10) +#endif +#ifndef HWCAP_ASIMDRDM +#define HWCAP_ASIMDRDM (1 << 12) +#endif +#ifndef HWCAP_JSCVT +#define HWCAP_JSCVT (1 << 13) +#endif +#ifndef HWCAP_FCMA +#define HWCAP_FCMA (1 << 14) +#endif +#ifndef HWCAP_LRCPC +#define HWCAP_LRCPC (1 << 15) +#endif +#ifndef HWCAP_DCPOP +#define HWCAP_DCPOP (1 << 16) +#endif +#ifndef HWCAP_SM3 +#define HWCAP_SM3 (1 << 18) +#endif +#ifndef HWCAP_SM4 +#define HWCAP_SM4 (1 << 19) +#endif +#ifndef HWCAP_ASIMDDP +#define HWCAP_ASIMDDP (1 << 20) +#endif +#ifndef HWCAP_SHA512 +#define HWCAP_SHA512 (1 << 21) +#endif +#ifndef HWCAP_SVE +#define HWCAP_SVE (1 << 22) +#endif +#ifndef HWCAP_ASIMDFHM +#define HWCAP_ASIMDFHM (1 << 23) +#endif +#ifndef HWCAP_DIT +#define HWCAP_DIT (1 << 24) +#endif +#ifndef HWCAP_ILRCPC +#define HWCAP_ILRCPC (1 << 26) +#endif +#ifndef HWCAP_FLAGM +#define HWCAP_FLAGM (1 << 27) +#endif +#ifndef HWCAP_SSBS +#define HWCAP_SSBS (1 << 28) +#endif +#ifndef HWCAP_SB +#define HWCAP_SB (1 << 29) +#endif + +#ifndef HWCAP2_DCPODP +#define HWCAP2_DCPODP (1 << 0) +#endif +#ifndef HWCAP2_SVE2 +#define HWCAP2_SVE2 (1 << 1) +#endif +#ifndef HWCAP2_SVEAES +#define HWCAP2_SVEAES (1 << 2) +#endif +#ifndef HWCAP2_SVEPMULL +#define HWCAP2_SVEPMULL (1 << 3) +#endif +#ifndef HWCAP2_SVEBITPERM +#define HWCAP2_SVEBITPERM (1 << 4) +#endif +#ifndef HWCAP2_SVESHA3 +#define HWCAP2_SVESHA3 (1 << 5) +#endif +#ifndef HWCAP2_FLAGM2 +#define HWCAP2_FLAGM2 (1 << 7) +#endif +#ifndef HWCAP2_FRINT +#define HWCAP2_FRINT (1 << 8) +#endif +#ifndef HWCAP2_SVEI8MM +#define HWCAP2_SVEI8MM (1 << 9) +#endif +#ifndef HWCAP2_SVEF32MM +#define HWCAP2_SVEF32MM (1 << 10) +#endif +#ifndef HWCAP2_SVEF64MM +#define HWCAP2_SVEF64MM (1 << 11) +#endif +#ifndef HWCAP2_SVEBF16 +#define HWCAP2_SVEBF16 (1 << 12) +#endif +#ifndef HWCAP2_RNG +#define HWCAP2_RNG (1 << 16) +#endif +#ifndef HWCAP2_BTI +#define HWCAP2_BTI (1 << 17) +#endif +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + #if defined(__ANDROID__) #include #include @@ -812,6 +995,13 @@ #include #include #endif + +// Detect Exynos 9810 CPU +#define IF_EXYNOS9810 \ + char arch[PROP_VALUE_MAX]; \ + if (__system_property_get("ro.arch", arch) > 0 && \ + strncmp(arch, "exynos9810", sizeof("exynos9810") - 1) == 0) + static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) { #if defined(__FreeBSD__) unsigned long hwcap; @@ -830,25 +1020,202 @@ _Bool result = (hwcap & HWCAP_ATOMICS) != 0; #if defined(__ANDROID__) if (result) { - char arch[PROP_VALUE_MAX]; - if (__system_property_get("ro.arch", arch) > 0 && - strncmp(arch, "exynos9810", sizeof("exynos9810") - 1) == 0) { - // Some cores in the Exynos 9810 CPU are ARMv8.2 and others are ARMv8.0; - // only the former support LSE atomics. However, the kernel in the - // initial Android 8.0 release of Galaxy S9/S9+ devices incorrectly - // reported the feature as being supported. - // - // The kernel appears to have been corrected to mark it unsupported as of - // the Android 9.0 release on those devices, and this issue has not been - // observed anywhere else. Thus, this workaround may be removed if - // compiler-rt ever drops support for Android 8.0. - result = false; - } + // Some cores in the Exynos 9810 CPU are ARMv8.2 and others are ARMv8.0; + // only the former support LSE atomics. However, the kernel in the + // initial Android 8.0 release of Galaxy S9/S9+ devices incorrectly + // reported the feature as being supported. + // + // The kernel appears to have been corrected to mark it unsupported as of + // the Android 9.0 release on those devices, and this issue has not been + // observed anywhere else. Thus, this workaround may be removed if + // compiler-rt ever drops support for Android 8.0. + IF_EXYNOS9810 result = false; } #endif // defined(__ANDROID__) __aarch64_have_lse_atomics = result; #endif // defined(__FreeBSD__) } + +void init_cpu_features_resolver(unsigned long hwcap, unsigned long hwcap2) { +#define setCPUFeature(F) __aarch64_cpu_features.features |= 1ULL << F +#define getCPUFeature(id, ftr) __asm__("mrs %0, " #id : "=r"(ftr)) +#define extractBits(val, start, number) \ + (val & ((1ULL << number) - 1ULL) << start) >> start + if (hwcap & HWCAP_CRC32) + setCPUFeature(FEAT_CRC32); + if (hwcap & HWCAP_PMULL) + setCPUFeature(FEAT_PMULL); + if (hwcap & HWCAP_FLAGM) + setCPUFeature(FEAT_FLAGM); + if (hwcap2 & HWCAP2_FLAGM2) { + setCPUFeature(FEAT_FLAGM); + setCPUFeature(FEAT_FLAGM2); + } + if (hwcap & HWCAP_SM3 && hwcap & HWCAP_SM4) + setCPUFeature(FEAT_SM); + if (hwcap & HWCAP_SHA512) + setCPUFeature(FEAT_SHA512); + if (hwcap & HWCAP_ASIMDDP) + setCPUFeature(FEAT_DOTPROD); + if (hwcap & HWCAP_ASIMDFHM) + setCPUFeature(FEAT_FHM); + if (hwcap & HWCAP_FPHP) + setCPUFeature(FEAT_FP16); + if (hwcap & HWCAP_DIT) + setCPUFeature(FEAT_DIT); + if (hwcap & HWCAP_ASIMDRDM) + setCPUFeature(FEAT_RDM); + if (hwcap & HWCAP_ILRCPC) + setCPUFeature(FEAT_LRCPC2); + if (hwcap & HWCAP_AES) + setCPUFeature(FEAT_AES); + if (hwcap & HWCAP_SHA1) + setCPUFeature(FEAT_SHA1); + if (hwcap & HWCAP_SHA2) + setCPUFeature(FEAT_SHA256); + if (hwcap & HWCAP_JSCVT) + setCPUFeature(FEAT_JSCVT); + if (hwcap & HWCAP_FCMA) + setCPUFeature(FEAT_FCMA); + if (hwcap & HWCAP_SB) + setCPUFeature(FEAT_SB); + if (hwcap & HWCAP_SSBS) + setCPUFeature(FEAT_SSBS2); + if (hwcap2 & HWCAP2_SVEAES) + setCPUFeature(FEAT_SVE_AES); + if (hwcap2 & HWCAP2_SVEPMULL) { + setCPUFeature(FEAT_SVE_AES); + setCPUFeature(FEAT_SVE_PMULL128); + } + if (hwcap2 & HWCAP2_SVEBITPERM) + setCPUFeature(FEAT_SVE_BITPERM); + if (hwcap2 & HWCAP2_SVESHA3) + setCPUFeature(FEAT_SVE_SHA3); + if (hwcap2 & HWCAP2_DCPODP) + setCPUFeature(FEAT_DPB2); + if (hwcap & HWCAP_ATOMICS) + setCPUFeature(FEAT_LSE); + if (hwcap2 & HWCAP2_RNG) + setCPUFeature(FEAT_RNG); + if (hwcap2 & HWCAP2_FRINT) + setCPUFeature(FEAT_FRINTTS); + if (hwcap2 & HWCAP2_SVEI8MM) + setCPUFeature(FEAT_I8MM); + if (hwcap2 & HWCAP2_SVEF32MM) + setCPUFeature(FEAT_F32MM); + if (hwcap2 & HWCAP2_SVEF64MM) + setCPUFeature(FEAT_F64MM); + if (hwcap2 & HWCAP2_BTI) + setCPUFeature(FEAT_BTI); + if (hwcap & HWCAP_CPUID) { + unsigned long ftr; + getCPUFeature(ID_AA64PFR1_EL1, ftr); + // ID_AA64PFR1_EL1.MTE >= 0b0001 + if (extractBits(ftr, 8, 4) >= 0x1) + setCPUFeature(FEAT_MTE); + // ID_AA64PFR1_EL1.MTE >= 0b0010 + if (extractBits(ftr, 8, 4) >= 0x2) + setCPUFeature(FEAT_MTE2); + // ID_AA64PFR1_EL1.MTE >= 0b0011 + if (extractBits(ftr, 8, 4) >= 0x3) + setCPUFeature(FEAT_MTE3); + // ID_AA64PFR1_EL1.SSBS == 0b0001 + if (extractBits(ftr, 4, 4) == 0x1) + setCPUFeature(FEAT_SSBS); + // ID_AA64PFR1_EL1.SME == 0b0001 + if (extractBits(ftr, 24, 4) == 0x1) + setCPUFeature(FEAT_SME); + getCPUFeature(ID_AA64PFR0_EL1, ftr); + // ID_AA64PFR0_EL1.FP != 0b1111 + if (extractBits(ftr, 16, 4) != 0xF) + setCPUFeature(FEAT_FP); + // ID_AA64PFR0_EL1.AdvSIMD != 0b1111 + if (extractBits(ftr, 20, 4) != 0xF) + setCPUFeature(FEAT_ADVSIMD); + // ID_AA64PFR0_EL1.SVE != 0b0000 + if (extractBits(ftr, 32, 4) != 0x0) { + // get ID_AA64ZFR0_EL1, that name supported + // if sve enabled only + getCPUFeature(S3_0_C0_C4_4, ftr); + // ID_AA64ZFR0_EL1.SVEver == 0b0000 + if (extractBits(ftr, 0, 4) == 0x0) + setCPUFeature(FEAT_SVE); + // ID_AA64ZFR0_EL1.SVEver == 0b0001 + if (extractBits(ftr, 0, 4) == 0x1) + setCPUFeature(FEAT_SVE2); + // ID_AA64ZFR0_EL1.BF16 != 0b0000 + if (extractBits(ftr, 20, 4) != 0x0) + setCPUFeature(FEAT_BF16); + // ID_AA64ZFR0_EL1.BF16 == 0b0010 + if (extractBits(ftr, 20, 4) == 0x2) + setCPUFeature(FEAT_EBF16); + } + getCPUFeature(ID_AA64ISAR1_EL1, ftr); + // ID_AA64ISAR1_EL1.DPB >= 0b0001 + if (extractBits(ftr, 0, 4) >= 0x1) + setCPUFeature(FEAT_DPB); + // ID_AA64ISAR1_EL1.LRCPC != 0b0000 + if (extractBits(ftr, 20, 4) != 0x0) + setCPUFeature(FEAT_LRCPC); + // ID_AA64ISAR1_EL1.LS64 >= 0b0001 + if (extractBits(ftr, 60, 4) >= 0x1) + setCPUFeature(FEAT_LS64); + // ID_AA64ISAR1_EL1.LS64 >= 0b0010 + if (extractBits(ftr, 60, 4) >= 0x2) + setCPUFeature(FEAT_LS64_V); + // ID_AA64ISAR1_EL1.LS64 >= 0b0011 + if (extractBits(ftr, 60, 4) >= 0x3) + setCPUFeature(FEAT_LS64_ACCDATA); + } else { + // Set some features in case of no CPUID support + if (hwcap & (HWCAP_FP | HWCAP_FPHP)) + setCPUFeature(FEAT_FP); + if (hwcap & (HWCAP_ASIMD | HWCAP_ASIMDHP)) + setCPUFeature(FEAT_ADVSIMD); + if (hwcap & HWCAP_DCPOP) + setCPUFeature(FEAT_DPB); + if (hwcap & HWCAP_LRCPC) + setCPUFeature(FEAT_LRCPC); + if (hwcap2 & HWCAP2_MTE) { + setCPUFeature(FEAT_MTE); + setCPUFeature(FEAT_MTE2); + } + if (hwcap2 & HWCAP2_SVEBF16) + setCPUFeature(FEAT_BF16); + if (hwcap2 & HWCAP2_SVE2 && hwcap & HWCAP_SVE) + setCPUFeature(FEAT_SVE2); + } +} + +void CONSTRUCTOR_ATTRIBUTE init_cpu_features(void) { + unsigned long hwcap; + unsigned long hwcap2; + // CPU features already initialized. + if (__aarch64_cpu_features.features) + return; + setCPUFeature(FEAT_MAX); +#if defined(__FreeBSD__) + int res = 0; + res = elf_aux_info(AT_HWCAP, &hwcap, sizeof hwcap); + res |= elf_aux_info(AT_HWCAP2, &hwcap2, sizeof hwcap2); + if (res) + return; +#else +#if defined(__ANDROID__) + // Don't set any CPU features, + // detection could be wrong on Exynos 9810. + IF_EXYNOS9810 return; +#endif // defined(__ANDROID__) +#endif // defined(__FreeBSD__) + hwcap = getauxval(AT_HWCAP); + hwcap2 = getauxval(AT_HWCAP2); + init_cpu_features_resolver(hwcap, hwcap2); +#undef extractBits +#undef getCPUFeature +#undef setCPUFeature +#undef IF_EXYNOS9810 +} #endif // defined(__has_include) #endif // __has_include() +#endif // __has_include() #endif // defined(__aarch64__) diff --git a/llvm/include/llvm/Support/AArch64TargetParser.h b/llvm/include/llvm/Support/AArch64TargetParser.h --- a/llvm/include/llvm/Support/AArch64TargetParser.h +++ b/llvm/include/llvm/Support/AArch64TargetParser.h @@ -25,6 +25,12 @@ namespace AArch64 { +enum CPUFeatures { +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) FEAT_##ID, +#include "llvm/Support/AArch64TargetParser.def" + FEAT_MAX +}; + // Arch extension modifiers for CPUs. enum ArchExtKind : uint64_t { AEK_INVALID = 0, @@ -138,6 +144,7 @@ void fillValidCPUArchList(SmallVectorImpl &Values); bool isX18ReservedByDefault(const Triple &TT); +uint64_t getCpuSupportsMask(ArrayRef FeatureStrs); } // namespace AArch64 } // namespace llvm diff --git a/llvm/include/llvm/Support/AArch64TargetParser.def b/llvm/include/llvm/Support/AArch64TargetParser.def --- a/llvm/include/llvm/Support/AArch64TargetParser.def +++ b/llvm/include/llvm/Support/AArch64TargetParser.def @@ -149,6 +149,58 @@ AARCH64_ARCH_EXT_NAME("pmuv3", AArch64::AEK_PERFMON, "+perfmon", "-perfmon") #undef AARCH64_ARCH_EXT_NAME +#ifndef AARCH64_CPU_FEATURE +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) +#endif +AARCH64_CPU_FEATURE("rng", RNG, "+rand", 10) +AARCH64_CPU_FEATURE("flagm", FLAGM, "+flagm", 20) +AARCH64_CPU_FEATURE("flagm2", FLAGM2, "+flagm", 30) +AARCH64_CPU_FEATURE("fhm", FHM, "", 40) +AARCH64_CPU_FEATURE("dotprod", DORPROD, "+dotprod", 50) +AARCH64_CPU_FEATURE("sm", SM, "+sm4", 60) +AARCH64_CPU_FEATURE("rdm", RDM, "+rdm", 70) +AARCH64_CPU_FEATURE("lse", LSE, "+lse", 80) +AARCH64_CPU_FEATURE("fp", FP, "+fp-armv8", 90) +AARCH64_CPU_FEATURE("advsimd", ADVSIMD, "+neon", 100) +AARCH64_CPU_FEATURE("crc32", CRC32, "+crc", 110) +AARCH64_CPU_FEATURE("sha1", SHA1, "", 120) +AARCH64_CPU_FEATURE("sha256", SHA256, "+sha2", 130) +AARCH64_CPU_FEATURE("sha512", SHA512, "+sha3", 140) +AARCH64_CPU_FEATURE("aes", AES, "+aes", 150) +AARCH64_CPU_FEATURE("pmull", PMULL, "", 160) +AARCH64_CPU_FEATURE("fp16", FP16, "+fullfp16", 170) +AARCH64_CPU_FEATURE("dit", DIT, "+dit", 180) +AARCH64_CPU_FEATURE("dpb", DPB, "", 190) +AARCH64_CPU_FEATURE("dpb2", DPB2, "", 200) +AARCH64_CPU_FEATURE("jscvt", JSCVT, "+jsconv", 210) +AARCH64_CPU_FEATURE("fcma", FCMA, "+complxnum", 220) +AARCH64_CPU_FEATURE("lrcpc", LRCPC, "+rcpc", 230) +AARCH64_CPU_FEATURE("lrcpc2", LRCPC2, "+rcpc", 240) +AARCH64_CPU_FEATURE("frintts", FRINTTS, "+fptoint", 250) +AARCH64_CPU_FEATURE("sve", SVE, "+sve", 260) +AARCH64_CPU_FEATURE("sve_bf16", SVE_BF16, "+bf16", 270) +AARCH64_CPU_FEATURE("sve_ebf16", SVE_EBF16, "", 280) +AARCH64_CPU_FEATURE("sve_i8mm", SVE_I8MM, "+i8mm", 290) +AARCH64_CPU_FEATURE("sve_f32mm", SVE_F32MM, "+f32mm", 300) +AARCH64_CPU_FEATURE("sve_f64mm", SVE_F64MM, "+f64mm", 310) +AARCH64_CPU_FEATURE("sve2", SVE2, "+sve2", 320) +AARCH64_CPU_FEATURE("sve_aes", SVE_AES, "+sve2-aes", 330) +AARCH64_CPU_FEATURE("sve_pmull128", SVE_PMULL128, "", 340) +AARCH64_CPU_FEATURE("sve_bitperm", SVE_BITPERM, "+sve2-bitperm", 350) +AARCH64_CPU_FEATURE("sve_sha3", SVE_SHA3, "+sve2-sha3", 360) +AARCH64_CPU_FEATURE("sme", SME, "+sme", 370) +AARCH64_CPU_FEATURE("mte", MTE, "+mte", 380) +AARCH64_CPU_FEATURE("mte2", MTE2, "+mte", 390) +AARCH64_CPU_FEATURE("mte3", MTE3, "+mte", 400) +AARCH64_CPU_FEATURE("sb", SB, "+sb", 410) +AARCH64_CPU_FEATURE("ssbs", SSBS, "+ssbs", 420) +AARCH64_CPU_FEATURE("ssbs2", SSBS2, "", 430) +AARCH64_CPU_FEATURE("bti", BTI, "+bti", 440) +AARCH64_CPU_FEATURE("ls64", LS64, "+ls64", 450) +AARCH64_CPU_FEATURE("ls64_v", LS64_V, "+ls64", 460) +AARCH64_CPU_FEATURE("ls64_accdata", LS64_ACCDATA, "+ls64", 470) +#undef AARCH64_CPU_FEATURE + #ifndef AARCH64_CPU_NAME #define AARCH64_CPU_NAME(NAME, ID, DEFAULT_FPU, IS_DEFAULT, DEFAULT_EXT) #endif diff --git a/llvm/lib/Support/AArch64TargetParser.cpp b/llvm/lib/Support/AArch64TargetParser.cpp --- a/llvm/lib/Support/AArch64TargetParser.cpp +++ b/llvm/lib/Support/AArch64TargetParser.cpp @@ -59,6 +59,19 @@ .Default(ArchKind::INVALID); } +uint64_t AArch64::getCpuSupportsMask(ArrayRef FeatureStrs) { + uint64_t FeaturesMask = 0; + for (const StringRef &FeatureStr : FeatureStrs) { + unsigned Feature = StringSwitch(FeatureStr) +#define AARCH64_CPU_FEATURE(NAME, ID, OPTION, PRIORITY) \ + .Case(NAME, AArch64::FEAT_##ID) +#include "llvm/Support/AArch64TargetParser.def" + ; + FeaturesMask |= (1ULL << Feature); + } + return FeaturesMask; +} + bool AArch64::getExtensionFeatures(uint64_t Extensions, std::vector &Features) { if (Extensions == AArch64::AEK_INVALID) diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -71,6 +71,9 @@ def FeatureOutlineAtomics : SubtargetFeature<"outline-atomics", "OutlineAtomics", "true", "Enable out of line atomics to support LSE instructions">; +def FeatureFMV : SubtargetFeature<"fmv", "HasFMV", "true", + "Enable Function Multi Versioning support.">; + def FeatureRDM : SubtargetFeature<"rdm", "HasRDM", "true", "Enable ARMv8.1 Rounding Double Multiply Add/Subtract instructions">;