From dfef9d04c0a65423a051ac00044b39f8911aa731 Mon Sep 17 00:00:00 2001 From: Alexandros Lamprineas Date: Fri, 22 Mar 2024 17:21:13 +0000 Subject: [PATCH] [FMV] Allow mixing target_version with target_clones. The latest ACLE allows it and further clarifies the following in regards to the combination of the two attributes: "If the `default` matches with another explicitly provided version in the same translation unit, then the compiler can emit only one function instead of the two. The explicitly provided version shall be preferred." ("default" refers to the default clone here) https://github.com/ARM-software/acle/pull/310 --- clang/include/clang/Basic/Attr.td | 14 + clang/lib/AST/ASTContext.cpp | 15 +- clang/lib/CodeGen/CodeGenModule.cpp | 105 ++++--- clang/lib/Sema/SemaDecl.cpp | 190 ++++++++---- .../CodeGen/aarch64-mixed-target-attributes.c | 278 ++++++++++++++++++ .../test/CodeGen/attr-target-clones-aarch64.c | 94 +++--- .../CodeGenCXX/attr-target-clones-aarch64.cpp | 28 +- clang/test/Sema/attr-target-clones-aarch64.c | 2 +- 8 files changed, 537 insertions(+), 189 deletions(-) create mode 100644 clang/test/CodeGen/aarch64-mixed-target-attributes.c diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3e03e55612645b..318d4e5ac5ba44 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3088,6 +3088,20 @@ def TargetClones : InheritableAttr { StringRef getFeatureStr(unsigned Index) const { return *(featuresStrs_begin() + Index); } + bool isDefaultVersion(unsigned Index) const { + return getFeatureStr(Index) == "default"; + } + void getFeatures(llvm::SmallVectorImpl &Out, + unsigned Index) const { + if (isDefaultVersion(Index)) return; + StringRef Features = getFeatureStr(Index); + SmallVector AttrFeatures; + Features.split(AttrFeatures, "+"); + for (auto &Feature : AttrFeatures) { + Feature = Feature.trim(); + Out.push_back(Feature); + } + } // Given an index into the 'featuresStrs' sequence, compute a unique // ID to be used with function name mangling for the associated variant. // This mapping is necessary due to a requirement that the mangling ID diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fcf801adeaf5ef..0b5f20a572a742 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -13676,22 +13676,19 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else if (const auto *TC = FD->getAttr()) { std::vector Features; - StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (Target->getTriple().isAArch64()) { // TargetClones for AArch64 - if (VersionStr != "default") { - SmallVector VersionFeatures; - VersionStr.split(VersionFeatures, "+"); - for (auto &VFeature : VersionFeatures) { - VFeature = VFeature.trim(); + llvm::SmallVector Feats; + TC->getFeatures(Feats, GD.getMultiVersionIndex()); + for (StringRef Feat : Feats) + if (Target->validateCpuSupports(Feat.str())) // Use '?' to mark features that came from AArch64 TargetClones. - Features.push_back((StringRef{"?"} + VFeature).str()); - } - } + Features.push_back("?" + Feat.str()); Features.insert(Features.begin(), Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); } else { + StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (VersionStr.starts_with("arch=")) TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); else if (VersionStr != "default") diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index ac81df8cf7adfe..bc7d7ac561113b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3712,7 +3712,8 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Forward declarations are emitted lazily on first use. if (!FD->doesThisDeclarationHaveABody()) { if (!FD->doesDeclarationForceExternallyVisibleDefinition() && - !FD->isTargetVersionMultiVersion()) + (!FD->isMultiVersion() || + !FD->getASTContext().getTargetInfo().getTriple().isAArch64())) return; StringRef MangledName = getMangledName(GD); @@ -3994,10 +3995,11 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD, auto *Spec = FD->getAttr(); for (unsigned I = 0; I < Spec->cpus_size(); ++I) EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); - } else if (FD->isTargetClonesMultiVersion()) { - auto *Clone = FD->getAttr(); - for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I) - if (Clone->isFirstOfVersion(I)) + } else if (auto *TC = FD->getAttr()) { + for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) + // AArch64 favors the default target version over the clone if any. + if ((!TC->isDefaultVersion(I) || !getTarget().getTriple().isAArch64()) && + TC->isFirstOfVersion(I)) EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); // Ensure that the resolver function is also emitted. GetOrCreateMultiVersionResolver(GD); @@ -4137,57 +4139,49 @@ void CodeGenModule::emitMultiVersionFunctions() { }; bool HasDefaultDecl = !FD->isTargetVersionMultiVersion(); - bool ShouldEmitResolver = !FD->isTargetVersionMultiVersion(); + bool ShouldEmitResolver = + !getContext().getTargetInfo().getTriple().isAArch64(); SmallVector Options; - if (FD->isTargetMultiVersion()) { - getContext().forEachMultiversionedFunctionVersion( - FD, [&](const FunctionDecl *CurFD) { - llvm::SmallVector Feats; - llvm::Function *Func = createFunction(CurFD); - if (const auto *TA = CurFD->getAttr()) { - TA->getAddedFeatures(Feats); - Options.emplace_back(Func, TA->getArchitecture(), Feats); - } else if (const auto *TVA = CurFD->getAttr()) { - bool HasDefaultDef = TVA->isDefaultVersion() && - CurFD->doesThisDeclarationHaveABody(); - HasDefaultDecl |= TVA->isDefaultVersion(); - ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef); - TVA->getFeatures(Feats); - Options.emplace_back(Func, /*Architecture*/ "", Feats); - } else - llvm_unreachable("unexpected MultiVersionKind"); - }); - } else if (const auto *TC = FD->getAttr()) { - for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) { - if (!TC->isFirstOfVersion(I)) - continue; + getContext().forEachMultiversionedFunctionVersion( + FD, [&](const FunctionDecl *CurFD) { + llvm::SmallVector Feats; - llvm::Function *Func = createFunction(FD, I); - StringRef Version = TC->getFeatureStr(I); - StringRef Architecture; - llvm::SmallVector Feature; - - if (getTarget().getTriple().isAArch64()) { - if (Version != "default") { - llvm::SmallVector VerFeats; - Version.split(VerFeats, "+"); - for (auto &CurFeat : VerFeats) - Feature.push_back(CurFeat.trim()); - } - } else { - if (Version.starts_with("arch=")) - Architecture = Version.drop_front(sizeof("arch=") - 1); - else if (Version != "default") - Feature.push_back(Version); - } - - Options.emplace_back(Func, Architecture, Feature); - } - } else { - assert(0 && "Expected a target or target_clones multiversion function"); - continue; - } + if (const auto *TA = CurFD->getAttr()) { + TA->getAddedFeatures(Feats); + llvm::Function *Func = createFunction(CurFD); + Options.emplace_back(Func, TA->getArchitecture(), Feats); + } else if (const auto *TVA = CurFD->getAttr()) { + bool HasDefaultDef = TVA->isDefaultVersion() && + CurFD->doesThisDeclarationHaveABody(); + HasDefaultDecl |= TVA->isDefaultVersion(); + ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef); + TVA->getFeatures(Feats); + llvm::Function *Func = createFunction(CurFD); + Options.emplace_back(Func, /*Architecture*/ "", Feats); + } else if (const auto *TC = CurFD->getAttr()) { + ShouldEmitResolver |= CurFD->doesThisDeclarationHaveABody(); + for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) { + if (!TC->isFirstOfVersion(I)) + continue; + + llvm::Function *Func = createFunction(CurFD, I); + StringRef Architecture; + Feats.clear(); + if (getTarget().getTriple().isAArch64()) + TC->getFeatures(Feats, I); + else { + StringRef Version = TC->getFeatureStr(I); + if (Version.starts_with("arch=")) + Architecture = Version.drop_front(sizeof("arch=") - 1); + else if (Version != "default") + Feats.push_back(Version); + } + Options.emplace_back(Func, Architecture, Feats); + } + } else + llvm_unreachable("unexpected MultiVersionKind"); + }); if (!ShouldEmitResolver) continue; @@ -4378,7 +4372,7 @@ void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) { const auto *FD = cast(GD.getDecl()); assert(FD && "Not a FunctionDecl?"); - if (FD->isTargetVersionMultiVersion()) { + if (FD->isTargetVersionMultiVersion() || FD->isTargetClonesMultiVersion()) { std::string MangledName = getMangledNameImpl(*this, GD, FD, /*OmitMultiVersionMangling=*/true); if (!DeferredResolversToEmit.insert(MangledName).second) @@ -4489,7 +4483,8 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( if (FD->isMultiVersion()) { UpdateMultiVersionNames(GD, FD, MangledName); - if (FD->isTargetVersionMultiVersion() && !FD->isUsed()) + if (FD->getASTContext().getTargetInfo().getTriple().isAArch64() && + !FD->isUsed()) AddDeferredMultiVersionResolverToEmit(GD); else if (!IsForDefinition) return GetOrCreateMultiVersionResolver(GD); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 73ea155053d737..9a286e0b26a4c6 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11260,11 +11260,13 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, return Diagnose(S, A); break; case attr::TargetVersion: - if (MVKind != MultiVersionKind::TargetVersion) + if (MVKind != MultiVersionKind::TargetVersion && + MVKind != MultiVersionKind::TargetClones) return Diagnose(S, A); break; case attr::TargetClones: - if (MVKind != MultiVersionKind::TargetClones) + if (MVKind != MultiVersionKind::TargetClones && + MVKind != MultiVersionKind::TargetVersion) return Diagnose(S, A); break; default: @@ -11469,6 +11471,22 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) { return false; } +static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) { + if (!From->getASTContext().getTargetInfo().getTriple().isAArch64()) + return; + + MultiVersionKind MVKindFrom = From->getMultiVersionKind(); + MultiVersionKind MVKindTo = To->getMultiVersionKind(); + + if (MVKindTo == MultiVersionKind::None && + (MVKindFrom == MultiVersionKind::TargetVersion || + MVKindFrom == MultiVersionKind::TargetClones)) { + To->setIsMultiVersion(); + To->addAttr(TargetVersionAttr::CreateImplicit( + To->getASTContext(), "default", To->getSourceRange())); + } +} + static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, bool &Redeclaration, @@ -11479,10 +11497,7 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, // The definitions should be allowed in any order. If we have discovered // a new target version and the preceeding was the default, then add the // corresponding attribute to it. - if (OldFD->getMultiVersionKind() == MultiVersionKind::None && - NewFD->getMultiVersionKind() == MultiVersionKind::TargetVersion) - OldFD->addAttr(TargetVersionAttr::CreateImplicit(S.Context, "default", - OldFD->getSourceRange())); + patchDefaultTargetVersion(NewFD, OldFD); const auto *NewTA = NewFD->getAttr(); const auto *NewTVA = NewFD->getAttr(); @@ -11583,36 +11598,60 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, return false; } -static bool MultiVersionTypesCompatible(MultiVersionKind Old, - MultiVersionKind New) { - if (Old == New || Old == MultiVersionKind::None || - New == MultiVersionKind::None) +static bool MultiVersionTypesCompatible(FunctionDecl *Old, FunctionDecl *New) { + MultiVersionKind OldKind = Old->getMultiVersionKind(); + MultiVersionKind NewKind = New->getMultiVersionKind(); + + if (OldKind == NewKind || OldKind == MultiVersionKind::None || + NewKind == MultiVersionKind::None) return true; - return (Old == MultiVersionKind::CPUDispatch && - New == MultiVersionKind::CPUSpecific) || - (Old == MultiVersionKind::CPUSpecific && - New == MultiVersionKind::CPUDispatch); + if (Old->getASTContext().getTargetInfo().getTriple().isAArch64()) { + switch (OldKind) { + case MultiVersionKind::TargetVersion: + return NewKind == MultiVersionKind::TargetClones; + case MultiVersionKind::TargetClones: + return NewKind == MultiVersionKind::TargetVersion; + default: + return false; + } + } else { + switch (OldKind) { + case MultiVersionKind::CPUDispatch: + return NewKind == MultiVersionKind::CPUSpecific; + case MultiVersionKind::CPUSpecific: + return NewKind == MultiVersionKind::CPUDispatch; + default: + return false; + } + } } /// Check the validity of a new function declaration being added to an existing /// multiversioned declaration collection. static bool CheckMultiVersionAdditionalDecl( Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, - 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(); + const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, + const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl, + LookupResult &Previous) { + // Disallow mixing of multiversioning types. - if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) { + if (!MultiVersionTypesCompatible(OldFD, NewFD)) { S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); S.Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); return true; } + // Add the default target_version attribute if it's missing. + patchDefaultTargetVersion(OldFD, NewFD); + patchDefaultTargetVersion(NewFD, OldFD); + + const auto *NewTA = NewFD->getAttr(); + const auto *NewTVA = NewFD->getAttr(); + MultiVersionKind NewMVKind = NewFD->getMultiVersionKind(); + MultiVersionKind OldMVKind = OldFD->getMultiVersionKind(); + ParsedTargetAttr NewParsed; if (NewTA) { NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr( @@ -11641,19 +11680,6 @@ static bool CheckMultiVersionAdditionalDecl( S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; - if (NewMVKind == MultiVersionKind::None && - OldMVKind == MultiVersionKind::TargetVersion) { - NewFD->addAttr(TargetVersionAttr::CreateImplicit( - S.Context, "default", NewFD->getSourceRange())); - 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 && @@ -11681,43 +11707,81 @@ static bool CheckMultiVersionAdditionalDecl( break; } case MultiVersionKind::TargetVersion: { - const auto *CurTVA = CurFD->getAttr(); - if (CurTVA->getName() == NewTVA->getName()) { - NewFD->setIsMultiVersion(); - Redeclaration = true; - OldDecl = ND; - return false; - } - llvm::SmallVector CurFeats; - if (CurTVA) { + if (const auto *CurTVA = CurFD->getAttr()) { + if (CurTVA->getName() == NewTVA->getName()) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + llvm::SmallVector CurFeats; 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; + + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } else if (const auto *CurClones = CurFD->getAttr()) { + // Default + if (NewFeats.empty()) + break; + + for (unsigned I = 0; I < CurClones->featuresStrs_size(); ++I) { + llvm::SmallVector CurFeats; + CurClones->getFeatures(CurFeats, I); + 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(); + assert(NewClones && "MultiVersionKind does not match attribute type"); + if (const auto *CurClones = CurFD->getAttr()) { + if (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() || + !std::equal(CurClones->featuresStrs_begin(), + CurClones->featuresStrs_end(), + NewClones->featuresStrs_begin())) { + S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } else if (const auto *CurTVA = CurFD->getAttr()) { + llvm::SmallVector CurFeats; + CurTVA->getFeatures(CurFeats); + llvm::sort(CurFeats); + + // Default + if (CurFeats.empty()) + break; + + for (unsigned I = 0; I < NewClones->featuresStrs_size(); ++I) { + NewFeats.clear(); + NewClones->getFeatures(NewFeats, I); + llvm::sort(NewFeats); + + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } + break; + } Redeclaration = true; OldDecl = CurFD; NewFD->setIsMultiVersion(); - - if (CurClones && NewClones && - (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() || - !std::equal(CurClones->featuresStrs_begin(), - CurClones->featuresStrs_end(), - NewClones->featuresStrs_begin()))) { - S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match); - S.Diag(CurFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; - } - return false; } case MultiVersionKind::CPUSpecific: @@ -11913,7 +11977,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // 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, NewCPUDisp, + return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, NewCPUDisp, NewCPUSpec, NewClones, Redeclaration, OldDecl, Previous); } diff --git a/clang/test/CodeGen/aarch64-mixed-target-attributes.c b/clang/test/CodeGen/aarch64-mixed-target-attributes.c new file mode 100644 index 00000000000000..aef6ce36ab1c05 --- /dev/null +++ b/clang/test/CodeGen/aarch64-mixed-target-attributes.c @@ -0,0 +1,278 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals --include-generated-funcs +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature -v9.5a -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 + +// The following is guarded because in NOFMV we get an error for redefining the default. +#ifdef __HAVE_FUNCTION_MULTI_VERSIONING +int explicit_default(void) { return 0; } +__attribute__((target_version("jscvt"))) int explicit_default(void) { return 1; } +__attribute__((target_clones("dotprod", "lse"))) int explicit_default(void) { return 2; } +__attribute__((target_version("rdma"))) int explicit_default(void) { return 3; } + +int foo(void) { return explicit_default(); } +#endif + +__attribute__((target_version("jscvt"))) int implicit_default(void) { return 1; } +__attribute__((target_clones("dotprod", "lse"))) int implicit_default(void) { return 2; } +__attribute__((target_version("rdma"))) int implicit_default(void) { return 3; } + +int bar(void) { return implicit_default(); } + +// These shouldn't generate anything. +int unused_version_declarations(void); +__attribute__((target_clones("dotprod", "lse"))) int unused_version_declarations(void); +__attribute__((target_version("jscvt"))) int unused_version_declarations(void); + +// These should generate the default (mangled) version and the resolver. +int default_def_with_version_decls(void) { return 0; } +__attribute__((target_clones("dotprod", "lse"))) int default_def_with_version_decls(void); +__attribute__((target_version("jscvt"))) int default_def_with_version_decls(void); + +//. +// CHECK: @__aarch64_cpu_features = external dso_local global { i64 } +// CHECK: @explicit_default.ifunc = weak_odr alias i32 (), ptr @explicit_default +// CHECK: @implicit_default.ifunc = weak_odr alias i32 (), ptr @implicit_default +// CHECK: @default_def_with_version_decls.ifunc = weak_odr alias i32 (), ptr @default_def_with_version_decls +// CHECK: @explicit_default = weak_odr ifunc i32 (), ptr @explicit_default.resolver +// CHECK: @implicit_default = weak_odr ifunc i32 (), ptr @implicit_default.resolver +// CHECK: @default_def_with_version_decls = weak_odr ifunc i32 (), ptr @default_def_with_version_decls.resolver +//. +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default.default +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default._Mjscvt +// CHECK-SAME: () #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default._Mdotprod +// CHECK-SAME: () #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default._Mlse +// CHECK-SAME: () #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define {{[^@]+}}@explicit_default.resolver() comdat { +// 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]], 1048576 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// 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 @explicit_default._Mjscvt +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 64 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 64 +// 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 @explicit_default._Mrdm +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 16 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 16 +// 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 @explicit_default._Mdotprod +// CHECK: resolver_else4: +// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 128 +// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 128 +// 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 @explicit_default._Mlse +// CHECK: resolver_else6: +// CHECK-NEXT: ret ptr @explicit_default.default +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@explicit_default._Mrdm +// CHECK-SAME: () #[[ATTR4:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@foo +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @explicit_default() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default._Mjscvt +// CHECK-SAME: () #[[ATTR1]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default._Mdotprod +// CHECK-SAME: () #[[ATTR2]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default._Mlse +// CHECK-SAME: () #[[ATTR3]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define {{[^@]+}}@implicit_default.resolver() comdat { +// 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]], 1048576 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// 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 @implicit_default._Mjscvt +// CHECK: resolver_else: +// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP5:%.*]] = and i64 [[TMP4]], 64 +// CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[TMP5]], 64 +// 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 @implicit_default._Mrdm +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 16 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 16 +// 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 @implicit_default._Mdotprod +// CHECK: resolver_else4: +// CHECK-NEXT: [[TMP12:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP13:%.*]] = and i64 [[TMP12]], 128 +// CHECK-NEXT: [[TMP14:%.*]] = icmp eq i64 [[TMP13]], 128 +// 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 @implicit_default._Mlse +// CHECK: resolver_else6: +// CHECK-NEXT: ret ptr @implicit_default.default +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default._Mrdm +// CHECK-SAME: () #[[ATTR4]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 3 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@bar +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[CALL:%.*]] = call i32 @implicit_default() +// CHECK-NEXT: ret i32 [[CALL]] +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@default_def_with_version_decls.default +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 0 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: define {{[^@]+}}@implicit_default.default +// CHECK-SAME: () #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// +// CHECK-LABEL: define {{[^@]+}}@default_def_with_version_decls.resolver() comdat { +// 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]], 1048576 +// CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1048576 +// 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 @default_def_with_version_decls._Mjscvt +// 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 @default_def_with_version_decls._Mdotprod +// CHECK: resolver_else2: +// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8 +// CHECK-NEXT: [[TMP9:%.*]] = and i64 [[TMP8]], 128 +// CHECK-NEXT: [[TMP10:%.*]] = icmp eq i64 [[TMP9]], 128 +// 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 @default_def_with_version_decls._Mlse +// CHECK: resolver_else4: +// CHECK-NEXT: ret ptr @default_def_with_version_decls.default +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@implicit_default +// CHECK-NOFMV-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 2 +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@bar +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: [[CALL:%.*]] = call i32 @implicit_default() +// CHECK-NOFMV-NEXT: ret i32 [[CALL]] +// +// +// CHECK-NOFMV: Function Attrs: noinline nounwind optnone +// CHECK-NOFMV-LABEL: define {{[^@]+}}@default_def_with_version_decls +// CHECK-NOFMV-SAME: () #[[ATTR0]] { +// CHECK-NOFMV-NEXT: entry: +// CHECK-NOFMV-NEXT: ret i32 0 +// +//. +// CHECK: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.5a" } +// CHECK: attributes #[[ATTR1]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+jsconv,+neon,-v9.5a" } +// CHECK: attributes #[[ATTR2]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dotprod,+fp-armv8,+neon,-v9.5a" } +// CHECK: attributes #[[ATTR3]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" } +// CHECK: attributes #[[ATTR4]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+rdm,-v9.5a" } +// CHECK: attributes #[[ATTR5:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+dotprod,+fp-armv8,+neon,-v9.5a" } +// CHECK: attributes #[[ATTR6:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+jsconv,+neon,-v9.5a" } +// CHECK: attributes #[[ATTR7:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.5a" } +// CHECK: attributes #[[ATTR8:[0-9]+]] = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+lse,-v9.5a" } +//. +// CHECK-NOFMV: attributes #[[ATTR0]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-fmv" } +//. +// CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} +// CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} +//. +// CHECK-NOFMV: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} +// CHECK-NOFMV: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} +//. diff --git a/clang/test/CodeGen/attr-target-clones-aarch64.c b/clang/test/CodeGen/attr-target-clones-aarch64.c index 94095f9aa3e1f4..8c8b951e9118d7 100644 --- a/clang/test/CodeGen/attr-target-clones-aarch64.c +++ b/clang/test/CodeGen/attr-target-clones-aarch64.c @@ -29,8 +29,8 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK: @ftc_def.ifunc = weak_odr alias i32 (), ptr @ftc_def // CHECK: @ftc_dup1.ifunc = weak_odr alias i32 (), ptr @ftc_dup1 // CHECK: @ftc_dup2.ifunc = weak_odr alias i32 (), ptr @ftc_dup2 -// CHECK: @ftc_inline1.ifunc = weak_odr alias i32 (), ptr @ftc_inline1 // CHECK: @ftc_inline2.ifunc = weak_odr alias i32 (), ptr @ftc_inline2 +// CHECK: @ftc_inline1.ifunc = weak_odr alias i32 (), ptr @ftc_inline1 // CHECK: @ftc_inline3.ifunc = weak_odr alias i32 (), ptr @ftc_inline3 // CHECK: @ftc = weak_odr ifunc i32 (), ptr @ftc.resolver // CHECK: @ftc_def = weak_odr ifunc i32 (), ptr @ftc_def.resolver @@ -52,12 +52,6 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: ret i32 0 // // -// CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc.default( -// CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 0 -// -// // CHECK-LABEL: @ftc.resolver( // CHECK-NEXT: resolver_entry: // CHECK-NEXT: call void @__init_cpu_features_resolver() @@ -92,12 +86,6 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: ret i32 1 // // -// CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_def.default( -// 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() @@ -126,12 +114,6 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: ret i32 2 // // -// CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_dup1.default( -// 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() @@ -158,12 +140,6 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // CHECK-NEXT: ret i32 3 // // -// CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_dup2.default( -// 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() @@ -192,6 +168,12 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // // // 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_direct( // CHECK-NEXT: entry: // CHECK-NEXT: ret i32 4 @@ -287,45 +269,63 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline1._MrngMsimd( +// CHECK-LABEL: @ftc_inline2._MfcmaMsve2-bitperm( // CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 1 +// CHECK-NEXT: ret i32 2 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline1._MpredresMrcpc( +// CHECK-LABEL: @ftc.default( // CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 1 +// CHECK-NEXT: ret i32 0 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline1._Msve2-aesMwfxt( +// CHECK-LABEL: @ftc_def.default( // CHECK-NEXT: entry: // CHECK-NEXT: ret i32 1 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline1.default( +// CHECK-LABEL: @ftc_dup1.default( // CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 1 +// CHECK-NEXT: ret i32 2 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline2._Mfp16( +// CHECK-LABEL: @ftc_dup2.default( // CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 2 +// CHECK-NEXT: ret i32 3 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline2._MfcmaMsve2-bitperm( +// CHECK-LABEL: @ftc_inline2.default( // CHECK-NEXT: entry: // CHECK-NEXT: ret i32 2 // // // CHECK: Function Attrs: noinline nounwind optnone -// CHECK-LABEL: @ftc_inline2.default( +// CHECK-LABEL: @ftc_inline1._MrngMsimd( // CHECK-NEXT: entry: -// CHECK-NEXT: ret i32 2 +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1._MpredresMrcpc( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1._Msve2-aesMwfxt( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 +// +// +// CHECK: Function Attrs: noinline nounwind optnone +// CHECK-LABEL: @ftc_inline1.default( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 1 // // // CHECK: Function Attrs: noinline nounwind optnone @@ -406,16 +406,16 @@ inline int __attribute__((target_clones("fp16", "sve2-bitperm+fcma", "default")) //. // CHECK: attributes #[[ATTR0:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+lse,+neon" } // CHECK: attributes #[[ATTR1:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve,+sve2" } -// CHECK: attributes #[[ATTR2:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } -// CHECK: attributes #[[ATTR3:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+sha2" } -// CHECK: attributes #[[ATTR4:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+mte,+neon,+sha2" } -// CHECK: attributes #[[ATTR5:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon" } -// CHECK: attributes #[[ATTR6:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+dotprod,+fp-armv8,+neon" } -// CHECK: attributes #[[ATTR7:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+rand" } -// CHECK: attributes #[[ATTR8:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+predres,+rcpc" } -// CHECK: attributes #[[ATTR9:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve,+sve2,+sve2-aes,+wfxt" } -// CHECK: attributes #[[ATTR10:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon" } -// CHECK: attributes #[[ATTR11:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+complxnum,+fp-armv8,+fullfp16,+neon,+sve,+sve2,+sve2-bitperm" } +// CHECK: attributes #[[ATTR2:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+sha2" } +// CHECK: attributes #[[ATTR3:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+mte,+neon,+sha2" } +// CHECK: attributes #[[ATTR4:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon" } +// CHECK: attributes #[[ATTR5:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+crc,+dotprod,+fp-armv8,+neon" } +// CHECK: attributes #[[ATTR6:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +// CHECK: attributes #[[ATTR7:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon" } +// CHECK: attributes #[[ATTR8:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+complxnum,+fp-armv8,+fullfp16,+neon,+sve,+sve2,+sve2-bitperm" } +// CHECK: attributes #[[ATTR9:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+neon,+rand" } +// CHECK: attributes #[[ATTR10:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+predres,+rcpc" } +// CHECK: attributes #[[ATTR11:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sve,+sve2,+sve2-aes,+wfxt" } // CHECK: attributes #[[ATTR12:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bti" } // CHECK: attributes #[[ATTR13:[0-9]+]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon,+sb,+sve" } //. diff --git a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp index 14963867798d34..7953f902bf09b2 100644 --- a/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp +++ b/clang/test/CodeGenCXX/attr-target-clones-aarch64.cpp @@ -56,13 +56,6 @@ void run_foo_tml() { // CHECK-NEXT: ret i32 1 // // -// CHECK-LABEL: @_Z7foo_ovli.default( -// 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() @@ -82,11 +75,6 @@ void run_foo_tml() { // CHECK-NEXT: ret i32 2 // // -// CHECK-LABEL: @_Z7foo_ovlv.default( -// 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() @@ -182,6 +170,18 @@ void run_foo_tml() { // CHECK-NEXT: ret i32 4 // // +// CHECK-LABEL: @_Z7foo_ovli.default( +// 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_ovlv.default( +// CHECK-NEXT: entry: +// CHECK-NEXT: ret i32 2 +// +// // CHECK-LABEL: @_ZN7MyClassIssE7foo_tmlEv._Mfrintts( // CHECK-NEXT: entry: // CHECK-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8 @@ -231,8 +231,8 @@ void run_foo_tml() { // //. // CHECK: attributes #[[ATTR0:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fp-armv8,+fullfp16,+neon" } -// CHECK: attributes #[[ATTR1:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } -// CHECK: attributes #[[ATTR2:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ls64" } +// CHECK: attributes #[[ATTR1:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+ls64" } +// CHECK: attributes #[[ATTR2:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } // CHECK: attributes #[[ATTR3:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+fptoint" } // CHECK: attributes #[[ATTR4:[0-9]+]] = { mustprogress noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="+bf16,+sme,+sme-f64f64" } //. diff --git a/clang/test/Sema/attr-target-clones-aarch64.c b/clang/test/Sema/attr-target-clones-aarch64.c index 0ce277f41884c6..bc3fceab82825b 100644 --- a/clang/test/Sema/attr-target-clones-aarch64.c +++ b/clang/test/Sema/attr-target-clones-aarch64.c @@ -27,7 +27,7 @@ int __attribute__((target_clones("rng", "fp16fml+fp", "default"))) redecl4(void) int __attribute__((target_clones("dgh+memtag+rpres+ls64_v", "ebf16+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-error@+2 {{multiversioned function redeclarations require identical target attributes}} // expected-note@-2 {{previous declaration is here}} int __attribute__((target_clones("flagm2", "default"))) redef2(void) { return 1; }