[clang] [AArch64][FMV] Enable PAuth and BTI hardening of resolver functions (PR #141573)
Anatoly Trosinenko via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 17 05:54:12 PDT 2025
https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/141573
>From 83d2b3affe1a438bf260356c3b581fb613da5cd4 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Mon, 26 May 2025 22:28:55 +0300
Subject: [PATCH 1/8] [AArch64][FMV] Enable PAuth and BTI hardening of resolver
functions
---
clang/lib/CodeGen/CodeGenModule.cpp | 9 +++++++
.../CodeGen/ptrauth-resolver-attributes.c | 25 +++++++++++++++++++
2 files changed, 34 insertions(+)
create mode 100644 clang/test/CodeGen/ptrauth-resolver-attributes.c
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 0ebab141b187d..b1d8aa2e7eb8f 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4831,6 +4831,13 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
AddDeferredMultiVersionResolverToEmit(GD);
+ auto SetResolverAttrs = [&](llvm::Function &Resolver) {
+ TargetInfo::BranchProtectionInfo BPI(getLangOpts());
+ TargetCodeGenInfo::setBranchProtectionFnAttributes(BPI, Resolver);
+ TargetCodeGenInfo::setPointerAuthFnAttributes(CodeGenOpts.PointerAuth,
+ Resolver);
+ };
+
// For cpu_specific, don't create an ifunc yet because we don't know if the
// cpu_dispatch will be emitted in this translation unit.
if (ShouldReturnIFunc) {
@@ -4845,6 +4852,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
"", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
+ SetResolverAttrs(cast<llvm::Function>(*Resolver));
if (ResolverGV)
replaceDeclarationWith(ResolverGV, GIF);
return GIF;
@@ -4855,6 +4863,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV &&
"Resolver should be created for the first time");
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
+ SetResolverAttrs(cast<llvm::Function>(*Resolver));
return Resolver;
}
diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/ptrauth-resolver-attributes.c
new file mode 100644
index 0000000000000..8bdedd2c549be
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-resolver-attributes.c
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+
+// Check that resolver functions generated by clang have the correct attributes.
+
+int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; }
+
+int __attribute__((target_version("crc"))) fmv(void) { return 0; }
+int __attribute__((target_version("default"))) fmv(void) { return 0; }
+
+// CHECK: define{{.*}} i32 @ftc._Mcrc() #0
+// CHECK: define{{.*}} ptr @ftc.resolver() #1
+// CHECK: define{{.*}} i32 @fmv._Mcrc() #0
+// CHECK: define{{.*}} i32 @fmv.default() #2
+// CHECK: define{{.*}} i32 @ftc.default() #2
+// CHECK: define{{.*}} ptr @fmv.resolver() #1
+
+// BTI-SIGNRA: attributes #0 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA: attributes #1 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA: attributes #2 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// PAUTHTEST: attributes #0 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST: attributes #1 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST: attributes #2 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
>From 55f830c846f8aea4373bf2c13378365ea85fa342 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 4 Jun 2025 16:34:47 +0300
Subject: [PATCH 2/8] Use setTargetAttributes function
---
clang/lib/CodeGen/CodeGenModule.cpp | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index b1d8aa2e7eb8f..52c557a6f61bb 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4831,11 +4831,11 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
AddDeferredMultiVersionResolverToEmit(GD);
- auto SetResolverAttrs = [&](llvm::Function &Resolver) {
- TargetInfo::BranchProtectionInfo BPI(getLangOpts());
- TargetCodeGenInfo::setBranchProtectionFnAttributes(BPI, Resolver);
- TargetCodeGenInfo::setPointerAuthFnAttributes(CodeGenOpts.PointerAuth,
- Resolver);
+ auto SetResolverAttrs = [&](llvm::Function *Resolver) {
+ // Set the default target-specific attributes, such as PAC and BTI ones on
+ // AArch64. Not passing Decl to prevent setting unrelated attributes,
+ // as Resolver can be shared by multiple declarations.
+ getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this);
};
// For cpu_specific, don't create an ifunc yet because we don't know if the
@@ -4852,7 +4852,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
"", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
- SetResolverAttrs(cast<llvm::Function>(*Resolver));
+ SetResolverAttrs(cast<llvm::Function>(Resolver));
if (ResolverGV)
replaceDeclarationWith(ResolverGV, GIF);
return GIF;
@@ -4863,7 +4863,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV &&
"Resolver should be created for the first time");
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
- SetResolverAttrs(cast<llvm::Function>(*Resolver));
+ SetResolverAttrs(cast<llvm::Function>(Resolver));
return Resolver;
}
>From 7d2b171f1bb7128e39e006cf9d924455fcb0a39a Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 4 Jun 2025 17:36:20 +0300
Subject: [PATCH 3/8] test: accept functions and attribute groups in any order
---
.../CodeGen/ptrauth-resolver-attributes.c | 24 +++++++++----------
1 file changed, 12 insertions(+), 12 deletions(-)
diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/ptrauth-resolver-attributes.c
index 8bdedd2c549be..a1239604226a0 100644
--- a/clang/test/CodeGen/ptrauth-resolver-attributes.c
+++ b/clang/test/CodeGen/ptrauth-resolver-attributes.c
@@ -10,16 +10,16 @@ int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; }
int __attribute__((target_version("crc"))) fmv(void) { return 0; }
int __attribute__((target_version("default"))) fmv(void) { return 0; }
-// CHECK: define{{.*}} i32 @ftc._Mcrc() #0
-// CHECK: define{{.*}} ptr @ftc.resolver() #1
-// CHECK: define{{.*}} i32 @fmv._Mcrc() #0
-// CHECK: define{{.*}} i32 @fmv.default() #2
-// CHECK: define{{.*}} i32 @ftc.default() #2
-// CHECK: define{{.*}} ptr @fmv.resolver() #1
+// CHECK-DAG: define{{.*}} i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]]
+// CHECK-DAG: define{{.*}} i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]]
+// CHECK-DAG: define{{.*}} ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]]
+// CHECK-DAG: define{{.*}} i32 @fmv._Mcrc() #[[ATTR_CRC]]
+// CHECK-DAG: define{{.*}} i32 @fmv.default() #[[ATTR_DEFAULT]]
+// CHECK-DAG: define{{.*}} ptr @fmv.resolver() #[[ATTR_RESOLVER]]
-// BTI-SIGNRA: attributes #0 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
-// BTI-SIGNRA: attributes #1 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
-// BTI-SIGNRA: attributes #2 = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
-// PAUTHTEST: attributes #0 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
-// PAUTHTEST: attributes #1 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
-// PAUTHTEST: attributes #2 = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
>From 4e8a8804453c0e4fa8f2ff7668b7e62f95b75351 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Mon, 14 Jul 2025 21:33:40 +0300
Subject: [PATCH 4/8] Move new test file to AArch64/ subdirectory
---
clang/test/CodeGen/{ => AArch64}/ptrauth-resolver-attributes.c | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename clang/test/CodeGen/{ => AArch64}/ptrauth-resolver-attributes.c (100%)
diff --git a/clang/test/CodeGen/ptrauth-resolver-attributes.c b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
similarity index 100%
rename from clang/test/CodeGen/ptrauth-resolver-attributes.c
rename to clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
>From fcf7cd6f69f51396f746a8b3a120d5f63bd43899 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Fri, 5 Sep 2025 00:11:23 +0300
Subject: [PATCH 5/8] [WIP] Set common attributes on the resolver functions
---
clang/lib/CodeGen/CodeGenModule.cpp | 5 +++
.../AArch64/ptrauth-resolver-attributes.c | 36 +++++++++++++------
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 52c557a6f61bb..9d48b1fd6e462 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4611,6 +4611,8 @@ void CodeGenModule::emitMultiVersionFunctions() {
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
+ setGlobalVisibility(ResolverFunc, /*D=*/nullptr);
+ setDSOLocal(ResolverFunc);
if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
ResolverFunc->setComdat(
@@ -4675,6 +4677,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
+ setGlobalVisibility(ResolverFunc, /*D=*/nullptr);
+ setDSOLocal(ResolverFunc);
+
if (supportsCOMDAT())
ResolverFunc->setComdat(
getModule().getOrInsertComdat(ResolverFunc->getName()));
diff --git a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
index a1239604226a0..edb30cf491fda 100644
--- a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
+++ b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
@@ -1,7 +1,7 @@
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
-// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
-// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,PAUTHTEST %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,PAUTHTEST %s
// Check that resolver functions generated by clang have the correct attributes.
@@ -10,12 +10,28 @@ int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; }
int __attribute__((target_version("crc"))) fmv(void) { return 0; }
int __attribute__((target_version("default"))) fmv(void) { return 0; }
-// CHECK-DAG: define{{.*}} i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]]
-// CHECK-DAG: define{{.*}} i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]]
-// CHECK-DAG: define{{.*}} ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]]
-// CHECK-DAG: define{{.*}} i32 @fmv._Mcrc() #[[ATTR_CRC]]
-// CHECK-DAG: define{{.*}} i32 @fmv.default() #[[ATTR_DEFAULT]]
-// CHECK-DAG: define{{.*}} ptr @fmv.resolver() #[[ATTR_RESOLVER]]
+static int __attribute__((target_clones("crc", "default"))) static_ftc(void) { return 0; }
+
+static int __attribute__((target_version("crc"))) static_fmv(void) { return 0; }
+static int __attribute__((target_version("default"))) static_fmv(void) { return 0; }
+
+// Force emission of static_* functions.
+void *get_ptr1(void) { return static_ftc; }
+void *get_ptr2(void) { return static_fmv; }
+
+// CHECK-DAG: define [[LINKVIS]]i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]]
+// CHECK-DAG: define [[LINKVIS]]i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]]
+// CHECK-DAG: define weak_odr ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]]
+// CHECK-DAG: define [[LINKVIS]]i32 @fmv._Mcrc() #[[ATTR_CRC]]
+// CHECK-DAG: define [[LINKVIS]]i32 @fmv.default() #[[ATTR_DEFAULT]]
+// CHECK-DAG: define weak_odr ptr @fmv.resolver() #[[ATTR_RESOLVER]]
+
+// CHECK-DAG: define internal i32 @static_ftc._Mcrc() #[[ATTR_CRC:[0-9]+]]
+// CHECK-DAG: define internal i32 @static_ftc.default() #[[ATTR_DEFAULT:[0-9]+]]
+// CHECK-DAG: define internal ptr @static_ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]]
+// CHECK-DAG: define internal i32 @static_fmv._Mcrc() #[[ATTR_CRC]]
+// CHECK-DAG: define internal i32 @static_fmv.default() #[[ATTR_DEFAULT]]
+// CHECK-DAG: define internal ptr @static_fmv.resolver() #[[ATTR_RESOLVER]]
// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
>From e1c1e232e2c6aec5a349a5318dc6e68b916a91e7 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Fri, 5 Sep 2025 20:05:30 +0300
Subject: [PATCH 6/8] Introduce setMultiVersionResolverAttributes function
---
clang/lib/CodeGen/CodeGenModule.cpp | 38 +++++++-----
clang/lib/CodeGen/CodeGenModule.h | 9 +++
.../CodeGen/AArch64/fmv-resolver-emission.c | 2 +-
clang/test/CodeGen/AArch64/ptrauth-fmv.c | 42 +++++++++++++
.../AArch64/ptrauth-resolver-attributes.c | 41 ------------
.../CodeGen/AArch64/resolver-attributes.c | 62 +++++++++++++++++++
clang/test/CodeGen/attr-target-clones.c | 4 +-
clang/test/CodeGen/attr-target-mv.c | 6 +-
8 files changed, 141 insertions(+), 63 deletions(-)
create mode 100644 clang/test/CodeGen/AArch64/ptrauth-fmv.c
delete mode 100644 clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
create mode 100644 clang/test/CodeGen/AArch64/resolver-attributes.c
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 9d48b1fd6e462..8c5af9e75e33f 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4610,10 +4610,6 @@ void CodeGenModule::emitMultiVersionFunctions() {
}
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
- ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
- setGlobalVisibility(ResolverFunc, /*D=*/nullptr);
- setDSOLocal(ResolverFunc);
-
if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
ResolverFunc->setComdat(
getModule().getOrInsertComdat(ResolverFunc->getName()));
@@ -4626,6 +4622,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
});
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+ setMultiVersionResolverAttributes(ResolverFunc, GD);
}
// Ensure that any additions to the deferred decls list caused by emitting a
@@ -4676,9 +4673,6 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
- ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
- setGlobalVisibility(ResolverFunc, /*D=*/nullptr);
- setDSOLocal(ResolverFunc);
if (supportsCOMDAT())
ResolverFunc->setComdat(
@@ -4745,6 +4739,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+ setMultiVersionResolverAttributes(ResolverFunc, GD);
if (getTarget().supportsIFunc()) {
llvm::GlobalValue::LinkageTypes Linkage = getMultiversionLinkage(*this, GD);
@@ -4836,13 +4831,6 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
AddDeferredMultiVersionResolverToEmit(GD);
- auto SetResolverAttrs = [&](llvm::Function *Resolver) {
- // Set the default target-specific attributes, such as PAC and BTI ones on
- // AArch64. Not passing Decl to prevent setting unrelated attributes,
- // as Resolver can be shared by multiple declarations.
- getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this);
- };
-
// For cpu_specific, don't create an ifunc yet because we don't know if the
// cpu_dispatch will be emitted in this translation unit.
if (ShouldReturnIFunc) {
@@ -4857,7 +4845,6 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
"", Resolver, &getModule());
GIF->setName(ResolverName);
SetCommonAttributes(FD, GIF);
- SetResolverAttrs(cast<llvm::Function>(Resolver));
if (ResolverGV)
replaceDeclarationWith(ResolverGV, GIF);
return GIF;
@@ -4868,10 +4855,29 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV &&
"Resolver should be created for the first time");
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
- SetResolverAttrs(cast<llvm::Function>(Resolver));
return Resolver;
}
+void CodeGenModule::setMultiVersionResolverAttributes(llvm::Function *Resolver,
+ GlobalDecl GD) {
+ const NamedDecl *D = dyn_cast_or_null<NamedDecl>(GD.getDecl());
+ Resolver->setLinkage(getMultiversionLinkage(*this, GD));
+
+ // Function body has to be emitted before calling setGlobalVisibility
+ // for Resolver to be considered as definition.
+ setGlobalVisibility(Resolver, D);
+
+ setDSOLocal(Resolver);
+
+ // Set the default target-specific attributes, such as PAC and BTI ones on
+ // AArch64. Not passing Decl to prevent setting unrelated attributes,
+ // as Resolver can be shared by multiple declarations.
+ // FIXME Some targets may require a non-null D to set some attributes
+ // (such as "stackrealign" on X86, even when it is requested via
+ // "-mstackrealign" command line option).
+ getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this);
+}
+
bool CodeGenModule::shouldDropDLLAttribute(const Decl *D,
const llvm::GlobalValue *GV) const {
auto SC = GV->getDLLStorageClass();
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 8b1ac2d976c5e..3971b296b3f80 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1851,6 +1851,15 @@ class CodeGenModule : public CodeGenTypeCache {
// that feature and for a regular function (llvm::GlobalValue) otherwise.
llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD);
+ // Set attributes to a resolver function generated by Clang.
+ // GD is either the cpu_dispatch declaration or an arbitrarily chosen
+ // function declaration that triggered the implicit generation of this
+ // resolver function.
+ //
+ /// NOTE: This should only be called for definitions.
+ void setMultiVersionResolverAttributes(llvm::Function *Resolver,
+ GlobalDecl GD);
+
// In scenarios where a function is not known to be a multiversion function
// until a later declaration, it is sometimes necessary to change the
// previously created mangled name to align with requirements of whatever
diff --git a/clang/test/CodeGen/AArch64/fmv-resolver-emission.c b/clang/test/CodeGen/AArch64/fmv-resolver-emission.c
index 591625d4d0da1..193ee9556cab0 100644
--- a/clang/test/CodeGen/AArch64/fmv-resolver-emission.c
+++ b/clang/test/CodeGen/AArch64/fmv-resolver-emission.c
@@ -328,7 +328,7 @@ __attribute__((target_clones("aes"))) void clones_without_default(void) {}
// CHECK-NEXT: ret void
//
//
-// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() {
+// CHECK-LABEL: define {{[^@]+}}@internal_func.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
diff --git a/clang/test/CodeGen/AArch64/ptrauth-fmv.c b/clang/test/CodeGen/AArch64/ptrauth-fmv.c
new file mode 100644
index 0000000000000..3b60ea7412f1b
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/ptrauth-fmv.c
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,BTI-SIGNRA %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
+
+// Check that both multi-versioned functions themselves and corresponding
+// resolvers generated by Clang have the correct PAC/BTI attributes.
+
+int __attribute__((target_clones("crc", "default"))) global_target_clones(void) { return 0; }
+
+int __attribute__((target_version("crc"))) global_target_version(void) { return 0; }
+int __attribute__((target_version("default"))) global_target_version(void) { return 0; }
+
+static int __attribute__((target_clones("crc", "default"))) static_target_clones(void) { return 0; }
+
+static int __attribute__((target_version("crc"))) static_target_version(void) { return 0; }
+static int __attribute__((target_version("default"))) static_target_version(void) { return 0; }
+
+// Force emission of static_* functions.
+void *get_ptr1(void) { return static_target_clones; }
+void *get_ptr2(void) { return static_target_version; }
+
+// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]]
+// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]]
+// CHECK-DAG: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
+// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version._Mcrc() #[[ATTR_CRC]]
+// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version.default() #[[ATTR_DEFAULT]]
+// CHECK-DAG: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]]
+
+// CHECK-DAG: define internal i32 @static_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]]
+// CHECK-DAG: define internal i32 @static_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]]
+// CHECK-DAG: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
+// CHECK-DAG: define internal i32 @static_target_version._Mcrc() #[[ATTR_CRC]]
+// CHECK-DAG: define internal i32 @static_target_version.default() #[[ATTR_DEFAULT]]
+// CHECK-DAG: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
+
+// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
+// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
+// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
diff --git a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c b/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
deleted file mode 100644
index edb30cf491fda..0000000000000
--- a/clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,BTI-SIGNRA %s
-// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -msign-return-address=all -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,BTI-SIGNRA %s
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="dso_local " --check-prefixes=CHECK,PAUTHTEST %s
-// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck -DLINKVIS="" --check-prefixes=CHECK,PAUTHTEST %s
-
-// Check that resolver functions generated by clang have the correct attributes.
-
-int __attribute__((target_clones("crc", "default"))) ftc(void) { return 0; }
-
-int __attribute__((target_version("crc"))) fmv(void) { return 0; }
-int __attribute__((target_version("default"))) fmv(void) { return 0; }
-
-static int __attribute__((target_clones("crc", "default"))) static_ftc(void) { return 0; }
-
-static int __attribute__((target_version("crc"))) static_fmv(void) { return 0; }
-static int __attribute__((target_version("default"))) static_fmv(void) { return 0; }
-
-// Force emission of static_* functions.
-void *get_ptr1(void) { return static_ftc; }
-void *get_ptr2(void) { return static_fmv; }
-
-// CHECK-DAG: define [[LINKVIS]]i32 @ftc._Mcrc() #[[ATTR_CRC:[0-9]+]]
-// CHECK-DAG: define [[LINKVIS]]i32 @ftc.default() #[[ATTR_DEFAULT:[0-9]+]]
-// CHECK-DAG: define weak_odr ptr @ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]]
-// CHECK-DAG: define [[LINKVIS]]i32 @fmv._Mcrc() #[[ATTR_CRC]]
-// CHECK-DAG: define [[LINKVIS]]i32 @fmv.default() #[[ATTR_DEFAULT]]
-// CHECK-DAG: define weak_odr ptr @fmv.resolver() #[[ATTR_RESOLVER]]
-
-// CHECK-DAG: define internal i32 @static_ftc._Mcrc() #[[ATTR_CRC:[0-9]+]]
-// CHECK-DAG: define internal i32 @static_ftc.default() #[[ATTR_DEFAULT:[0-9]+]]
-// CHECK-DAG: define internal ptr @static_ftc.resolver() #[[ATTR_RESOLVER:[0-9]+]]
-// CHECK-DAG: define internal i32 @static_fmv._Mcrc() #[[ATTR_CRC]]
-// CHECK-DAG: define internal i32 @static_fmv.default() #[[ATTR_DEFAULT]]
-// CHECK-DAG: define internal ptr @static_fmv.resolver() #[[ATTR_RESOLVER]]
-
-// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
-// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
-// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
-// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
-// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
-// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
diff --git a/clang/test/CodeGen/AArch64/resolver-attributes.c b/clang/test/CodeGen/AArch64/resolver-attributes.c
new file mode 100644
index 0000000000000..a1263ded46565
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/resolver-attributes.c
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI,ELF %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI,ELF %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN,ELF %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN %s
+
+// Check that the resolver functions generated by Clang have the correct attributes.
+// In these test cases, branch-target-enforcement is used as an example of
+// target-specific attribute that has to be set on every function by default.
+
+// FIXME: `cpu_specific`/`cpu_dispatch` and `target` attributes cannot be
+// tested on AArch64.
+
+__attribute__((target_clones("crc", "default")))
+int global_target_clones(void) { return 0; }
+
+__attribute__((target_version("crc"))) int global_target_version(void) { return 0; }
+__attribute__((target_version("default"))) int global_target_version(void) { return 0; }
+
+__attribute__((target_clones("crc", "default")))
+static int static_target_clones(void) { return 0; }
+
+__attribute__((target_version("crc"))) static int static_target_version(void) { return 0; }
+__attribute__((target_version("default"))) static int static_target_version(void) { return 0; }
+
+// Force emission of static_* functions.
+void *get_ptr1(void) { return static_target_clones; }
+void *get_ptr2(void) { return static_target_version; }
+
+#ifdef __ELF__
+// Make sure target-specific attributes can be overriden as needed for
+// non-autogenerated resolver functions.
+// Note that since there is only a single definition of ifunc_resolver, it
+// is not itself a multi-versioned function, even though it has target(...)
+// attribute.
+int ifunc_func(void) { return 0; }
+__attribute__((target("branch-protection=bti"))) void *ifunc_resolver(void) { return ifunc_func; }
+__attribute__((ifunc("ifunc_resolver"))) int ifunc(void);
+#endif
+
+// ELF: define{{.*}} ptr @ifunc_resolver() #[[ATTR_IFUNC_RESOLVER:[0-9]+]]
+
+// BTI: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
+// BTI: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]]
+// BTI: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER]]
+// BTI: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
+
+// In NOBTI case, no attribute groups are assigned to the resolver functions:
+// NOBTI: define weak_odr ptr @global_target_clones.resolver(){{[^#]*}} {
+// NOBTI: define weak_odr ptr @global_target_version.resolver(){{[^#]*}} {
+// NOBTI: define internal ptr @static_target_clones.resolver(){{[^#]*}} {
+// NOBTI: define internal ptr @static_target_version.resolver(){{[^#]*}} {
+
+// HIDDEN: define weak_odr hidden ptr @global_target_clones.resolver(){{[^#]*}}
+// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{[^#]*}}
+// HIDDEN: define internal ptr @static_target_clones.resolver(){{[^#]*}}
+// HIDDEN: define internal ptr @static_target_version.resolver(){{[^#]*}}
+
+// ELF: attributes #[[ATTR_IFUNC_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }
+
+// BTI: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }
diff --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c
index 3256db061f9a2..e11daa67192dc 100644
--- a/clang/test/CodeGen/attr-target-clones.c
+++ b/clang/test/CodeGen/attr-target-clones.c
@@ -44,9 +44,9 @@
static int __attribute__((target_clones("sse4.2, default"))) internal(void) { return 0; }
int use(void) { return internal(); }
/// Internal linkage resolvers do not use comdat.
-// LINUX: define internal ptr @internal.resolver() {
+// LINUX: define internal ptr @internal.resolver() comdat {
// DARWIN: define internal ptr @internal.resolver() {
-// WINDOWS: define internal i32 @internal() {
+// WINDOWS: define internal i32 @internal() comdat {
int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
// LINUX: define {{.*}}i32 @foo.sse4.2.0()
diff --git a/clang/test/CodeGen/attr-target-mv.c b/clang/test/CodeGen/attr-target-mv.c
index 07f47d93cd29c..6699326ef834f 100644
--- a/clang/test/CodeGen/attr-target-mv.c
+++ b/clang/test/CodeGen/attr-target-mv.c
@@ -283,9 +283,9 @@ void calls_pr50025c(void) { pr50025c(); }
// WINDOWS: call i32 @foo
/// Internal linkage resolvers do not use comdat.
-// ITANIUM: define internal ptr @foo_internal.resolver() {
-
-// WINDOWS: define internal i32 @foo_internal.resolver() {
+// LINUX: define internal ptr @foo_internal.resolver() comdat {
+// DARWIN: define internal ptr @foo_internal.resolver() {
+// WINDOWS: define internal i32 @foo_internal.resolver() comdat {
// ITANIUM: define{{.*}} i32 @bar2()
// ITANIUM: call i32 @foo_inline.ifunc()
>From 4eafbe4fafca25266ad208c0e71ad25749b2f9fa Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 17 Sep 2025 14:44:05 +0300
Subject: [PATCH 7/8] Fix setting comdats on resolver functions
---
clang/lib/CodeGen/CodeGenModule.cpp | 8 ++++----
clang/test/CodeGen/AArch64/fmv-resolver-emission.c | 2 +-
clang/test/CodeGen/attr-target-clones.c | 4 ++--
clang/test/CodeGen/attr-target-mv.c | 6 +++---
4 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 8c5af9e75e33f..0b660e3daaf81 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4610,10 +4610,6 @@ void CodeGenModule::emitMultiVersionFunctions() {
}
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
- if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
- ResolverFunc->setComdat(
- getModule().getOrInsertComdat(ResolverFunc->getName()));
-
const TargetInfo &TI = getTarget();
llvm::stable_sort(
Options, [&TI](const CodeGenFunction::FMVResolverOption &LHS,
@@ -4622,7 +4618,11 @@ void CodeGenModule::emitMultiVersionFunctions() {
});
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
+
setMultiVersionResolverAttributes(ResolverFunc, GD);
+ if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
+ ResolverFunc->setComdat(
+ getModule().getOrInsertComdat(ResolverFunc->getName()));
}
// Ensure that any additions to the deferred decls list caused by emitting a
diff --git a/clang/test/CodeGen/AArch64/fmv-resolver-emission.c b/clang/test/CodeGen/AArch64/fmv-resolver-emission.c
index 193ee9556cab0..591625d4d0da1 100644
--- a/clang/test/CodeGen/AArch64/fmv-resolver-emission.c
+++ b/clang/test/CodeGen/AArch64/fmv-resolver-emission.c
@@ -328,7 +328,7 @@ __attribute__((target_clones("aes"))) void clones_without_default(void) {}
// CHECK-NEXT: ret void
//
//
-// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() comdat {
+// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() {
// CHECK-NEXT: resolver_entry:
// CHECK-NEXT: call void @__init_cpu_features_resolver()
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
diff --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c
index e11daa67192dc..3256db061f9a2 100644
--- a/clang/test/CodeGen/attr-target-clones.c
+++ b/clang/test/CodeGen/attr-target-clones.c
@@ -44,9 +44,9 @@
static int __attribute__((target_clones("sse4.2, default"))) internal(void) { return 0; }
int use(void) { return internal(); }
/// Internal linkage resolvers do not use comdat.
-// LINUX: define internal ptr @internal.resolver() comdat {
+// LINUX: define internal ptr @internal.resolver() {
// DARWIN: define internal ptr @internal.resolver() {
-// WINDOWS: define internal i32 @internal() comdat {
+// WINDOWS: define internal i32 @internal() {
int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
// LINUX: define {{.*}}i32 @foo.sse4.2.0()
diff --git a/clang/test/CodeGen/attr-target-mv.c b/clang/test/CodeGen/attr-target-mv.c
index 6699326ef834f..07f47d93cd29c 100644
--- a/clang/test/CodeGen/attr-target-mv.c
+++ b/clang/test/CodeGen/attr-target-mv.c
@@ -283,9 +283,9 @@ void calls_pr50025c(void) { pr50025c(); }
// WINDOWS: call i32 @foo
/// Internal linkage resolvers do not use comdat.
-// LINUX: define internal ptr @foo_internal.resolver() comdat {
-// DARWIN: define internal ptr @foo_internal.resolver() {
-// WINDOWS: define internal i32 @foo_internal.resolver() comdat {
+// ITANIUM: define internal ptr @foo_internal.resolver() {
+
+// WINDOWS: define internal i32 @foo_internal.resolver() {
// ITANIUM: define{{.*}} i32 @bar2()
// ITANIUM: call i32 @foo_inline.ifunc()
>From f25b5c55965b06ca58df234b551fe3c6eca279c5 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 17 Sep 2025 15:51:47 +0300
Subject: [PATCH 8/8] resolver-attributes.c: the only expected variability for
NOBTI and HIDDEN is optional comdat
---
.../test/CodeGen/AArch64/resolver-attributes.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/clang/test/CodeGen/AArch64/resolver-attributes.c b/clang/test/CodeGen/AArch64/resolver-attributes.c
index a1263ded46565..6e4497cdc8611 100644
--- a/clang/test/CodeGen/AArch64/resolver-attributes.c
+++ b/clang/test/CodeGen/AArch64/resolver-attributes.c
@@ -47,15 +47,15 @@ __attribute__((ifunc("ifunc_resolver"))) int ifunc(void);
// BTI: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
// In NOBTI case, no attribute groups are assigned to the resolver functions:
-// NOBTI: define weak_odr ptr @global_target_clones.resolver(){{[^#]*}} {
-// NOBTI: define weak_odr ptr @global_target_version.resolver(){{[^#]*}} {
-// NOBTI: define internal ptr @static_target_clones.resolver(){{[^#]*}} {
-// NOBTI: define internal ptr @static_target_version.resolver(){{[^#]*}} {
-
-// HIDDEN: define weak_odr hidden ptr @global_target_clones.resolver(){{[^#]*}}
-// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{[^#]*}}
-// HIDDEN: define internal ptr @static_target_clones.resolver(){{[^#]*}}
-// HIDDEN: define internal ptr @static_target_version.resolver(){{[^#]*}}
+// NOBTI: define weak_odr ptr @global_target_clones.resolver(){{( comdat)?}} {
+// NOBTI: define weak_odr ptr @global_target_version.resolver(){{( comdat)?}} {
+// NOBTI: define internal ptr @static_target_clones.resolver() {
+// NOBTI: define internal ptr @static_target_version.resolver() {
+
+// HIDDEN: define weak_odr hidden ptr @global_target_clones.resolver(){{( comdat)?}} {
+// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{( comdat)?}} {
+// HIDDEN: define internal ptr @static_target_clones.resolver() {
+// HIDDEN: define internal ptr @static_target_version.resolver() {
// ELF: attributes #[[ATTR_IFUNC_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }
More information about the cfe-commits
mailing list