Skip to content

Commit e1c1e23

Browse files
committed
Introduce setMultiVersionResolverAttributes function
1 parent fcf7cd6 commit e1c1e23

File tree

8 files changed

+141
-63
lines changed

8 files changed

+141
-63
lines changed

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4610,10 +4610,6 @@ void CodeGenModule::emitMultiVersionFunctions() {
46104610
}
46114611
llvm::Function *ResolverFunc = cast<llvm::Function>(ResolverConstant);
46124612

4613-
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
4614-
setGlobalVisibility(ResolverFunc, /*D=*/nullptr);
4615-
setDSOLocal(ResolverFunc);
4616-
46174613
if (!ResolverFunc->hasLocalLinkage() && supportsCOMDAT())
46184614
ResolverFunc->setComdat(
46194615
getModule().getOrInsertComdat(ResolverFunc->getName()));
@@ -4626,6 +4622,7 @@ void CodeGenModule::emitMultiVersionFunctions() {
46264622
});
46274623
CodeGenFunction CGF(*this);
46284624
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
4625+
setMultiVersionResolverAttributes(ResolverFunc, GD);
46294626
}
46304627

46314628
// Ensure that any additions to the deferred decls list caused by emitting a
@@ -4676,9 +4673,6 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
46764673

46774674
auto *ResolverFunc = cast<llvm::Function>(GetOrCreateLLVMFunction(
46784675
ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false));
4679-
ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD));
4680-
setGlobalVisibility(ResolverFunc, /*D=*/nullptr);
4681-
setDSOLocal(ResolverFunc);
46824676

46834677
if (supportsCOMDAT())
46844678
ResolverFunc->setComdat(
@@ -4745,6 +4739,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
47454739

47464740
CodeGenFunction CGF(*this);
47474741
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
4742+
setMultiVersionResolverAttributes(ResolverFunc, GD);
47484743

47494744
if (getTarget().supportsIFunc()) {
47504745
llvm::GlobalValue::LinkageTypes Linkage = getMultiversionLinkage(*this, GD);
@@ -4836,13 +4831,6 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
48364831
if (FD->isTargetMultiVersion() || FD->isTargetClonesMultiVersion())
48374832
AddDeferredMultiVersionResolverToEmit(GD);
48384833

4839-
auto SetResolverAttrs = [&](llvm::Function *Resolver) {
4840-
// Set the default target-specific attributes, such as PAC and BTI ones on
4841-
// AArch64. Not passing Decl to prevent setting unrelated attributes,
4842-
// as Resolver can be shared by multiple declarations.
4843-
getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this);
4844-
};
4845-
48464834
// For cpu_specific, don't create an ifunc yet because we don't know if the
48474835
// cpu_dispatch will be emitted in this translation unit.
48484836
if (ShouldReturnIFunc) {
@@ -4857,7 +4845,6 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
48574845
"", Resolver, &getModule());
48584846
GIF->setName(ResolverName);
48594847
SetCommonAttributes(FD, GIF);
4860-
SetResolverAttrs(cast<llvm::Function>(Resolver));
48614848
if (ResolverGV)
48624849
replaceDeclarationWith(ResolverGV, GIF);
48634850
return GIF;
@@ -4868,10 +4855,29 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
48684855
assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV &&
48694856
"Resolver should be created for the first time");
48704857
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
4871-
SetResolverAttrs(cast<llvm::Function>(Resolver));
48724858
return Resolver;
48734859
}
48744860

4861+
void CodeGenModule::setMultiVersionResolverAttributes(llvm::Function *Resolver,
4862+
GlobalDecl GD) {
4863+
const NamedDecl *D = dyn_cast_or_null<NamedDecl>(GD.getDecl());
4864+
Resolver->setLinkage(getMultiversionLinkage(*this, GD));
4865+
4866+
// Function body has to be emitted before calling setGlobalVisibility
4867+
// for Resolver to be considered as definition.
4868+
setGlobalVisibility(Resolver, D);
4869+
4870+
setDSOLocal(Resolver);
4871+
4872+
// Set the default target-specific attributes, such as PAC and BTI ones on
4873+
// AArch64. Not passing Decl to prevent setting unrelated attributes,
4874+
// as Resolver can be shared by multiple declarations.
4875+
// FIXME Some targets may require a non-null D to set some attributes
4876+
// (such as "stackrealign" on X86, even when it is requested via
4877+
// "-mstackrealign" command line option).
4878+
getTargetCodeGenInfo().setTargetAttributes(/*D=*/nullptr, Resolver, *this);
4879+
}
4880+
48754881
bool CodeGenModule::shouldDropDLLAttribute(const Decl *D,
48764882
const llvm::GlobalValue *GV) const {
48774883
auto SC = GV->getDLLStorageClass();

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,6 +1851,15 @@ class CodeGenModule : public CodeGenTypeCache {
18511851
// that feature and for a regular function (llvm::GlobalValue) otherwise.
18521852
llvm::Constant *GetOrCreateMultiVersionResolver(GlobalDecl GD);
18531853

1854+
// Set attributes to a resolver function generated by Clang.
1855+
// GD is either the cpu_dispatch declaration or an arbitrarily chosen
1856+
// function declaration that triggered the implicit generation of this
1857+
// resolver function.
1858+
//
1859+
/// NOTE: This should only be called for definitions.
1860+
void setMultiVersionResolverAttributes(llvm::Function *Resolver,
1861+
GlobalDecl GD);
1862+
18541863
// In scenarios where a function is not known to be a multiversion function
18551864
// until a later declaration, it is sometimes necessary to change the
18561865
// previously created mangled name to align with requirements of whatever

clang/test/CodeGen/AArch64/fmv-resolver-emission.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ __attribute__((target_clones("aes"))) void clones_without_default(void) {}
328328
// CHECK-NEXT: ret void
329329
//
330330
//
331-
// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() {
331+
// CHECK-LABEL: define {{[^@]+}}@internal_func.resolver() comdat {
332332
// CHECK-NEXT: resolver_entry:
333333
// CHECK-NEXT: call void @__init_cpu_features_resolver()
334334
// CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr @__aarch64_cpu_features, align 8
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// 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
2+
// 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
3+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
4+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps -emit-llvm %s -o - | FileCheck --check-prefixes=CHECK,PAUTHTEST %s
5+
6+
// Check that both multi-versioned functions themselves and corresponding
7+
// resolvers generated by Clang have the correct PAC/BTI attributes.
8+
9+
int __attribute__((target_clones("crc", "default"))) global_target_clones(void) { return 0; }
10+
11+
int __attribute__((target_version("crc"))) global_target_version(void) { return 0; }
12+
int __attribute__((target_version("default"))) global_target_version(void) { return 0; }
13+
14+
static int __attribute__((target_clones("crc", "default"))) static_target_clones(void) { return 0; }
15+
16+
static int __attribute__((target_version("crc"))) static_target_version(void) { return 0; }
17+
static int __attribute__((target_version("default"))) static_target_version(void) { return 0; }
18+
19+
// Force emission of static_* functions.
20+
void *get_ptr1(void) { return static_target_clones; }
21+
void *get_ptr2(void) { return static_target_version; }
22+
23+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]]
24+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]]
25+
// CHECK-DAG: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
26+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version._Mcrc() #[[ATTR_CRC]]
27+
// CHECK-DAG: define{{( dso_local)?}} i32 @global_target_version.default() #[[ATTR_DEFAULT]]
28+
// CHECK-DAG: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]]
29+
30+
// CHECK-DAG: define internal i32 @static_target_clones._Mcrc() #[[ATTR_CRC:[0-9]+]]
31+
// CHECK-DAG: define internal i32 @static_target_clones.default() #[[ATTR_DEFAULT:[0-9]+]]
32+
// CHECK-DAG: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
33+
// CHECK-DAG: define internal i32 @static_target_version._Mcrc() #[[ATTR_CRC]]
34+
// CHECK-DAG: define internal i32 @static_target_version.default() #[[ATTR_DEFAULT]]
35+
// CHECK-DAG: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
36+
37+
// BTI-SIGNRA-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
38+
// BTI-SIGNRA-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
39+
// BTI-SIGNRA-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"branch-target-enforcement" {{.*}}"sign-return-address"="all" "sign-return-address-key"="a_key"{{.*}} }
40+
// PAUTHTEST-DAG: attributes #[[ATTR_CRC]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
41+
// PAUTHTEST-DAG: attributes #[[ATTR_RESOLVER]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }
42+
// PAUTHTEST-DAG: attributes #[[ATTR_DEFAULT]] = { {{.*}}"ptrauth-auth-traps" "ptrauth-calls" "ptrauth-returns"{{.*}} }

clang/test/CodeGen/AArch64/ptrauth-resolver-attributes.c

Lines changed: 0 additions & 41 deletions
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI,ELF %s
2+
// RUN: %clang_cc1 -triple arm64-apple-ios -mbranch-target-enforce -emit-llvm %s -o - | FileCheck --check-prefixes=BTI %s
3+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI,ELF %s
4+
// RUN: %clang_cc1 -triple arm64-apple-ios -emit-llvm %s -o - | FileCheck --check-prefixes=NOBTI %s
5+
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN,ELF %s
6+
// RUN: %clang_cc1 -triple arm64-apple-ios -fvisibility=hidden -emit-llvm %s -o - | FileCheck --check-prefixes=HIDDEN %s
7+
8+
// Check that the resolver functions generated by Clang have the correct attributes.
9+
// In these test cases, branch-target-enforcement is used as an example of
10+
// target-specific attribute that has to be set on every function by default.
11+
12+
// FIXME: `cpu_specific`/`cpu_dispatch` and `target` attributes cannot be
13+
// tested on AArch64.
14+
15+
__attribute__((target_clones("crc", "default")))
16+
int global_target_clones(void) { return 0; }
17+
18+
__attribute__((target_version("crc"))) int global_target_version(void) { return 0; }
19+
__attribute__((target_version("default"))) int global_target_version(void) { return 0; }
20+
21+
__attribute__((target_clones("crc", "default")))
22+
static int static_target_clones(void) { return 0; }
23+
24+
__attribute__((target_version("crc"))) static int static_target_version(void) { return 0; }
25+
__attribute__((target_version("default"))) static int static_target_version(void) { return 0; }
26+
27+
// Force emission of static_* functions.
28+
void *get_ptr1(void) { return static_target_clones; }
29+
void *get_ptr2(void) { return static_target_version; }
30+
31+
#ifdef __ELF__
32+
// Make sure target-specific attributes can be overriden as needed for
33+
// non-autogenerated resolver functions.
34+
// Note that since there is only a single definition of ifunc_resolver, it
35+
// is not itself a multi-versioned function, even though it has target(...)
36+
// attribute.
37+
int ifunc_func(void) { return 0; }
38+
__attribute__((target("branch-protection=bti"))) void *ifunc_resolver(void) { return ifunc_func; }
39+
__attribute__((ifunc("ifunc_resolver"))) int ifunc(void);
40+
#endif
41+
42+
// ELF: define{{.*}} ptr @ifunc_resolver() #[[ATTR_IFUNC_RESOLVER:[0-9]+]]
43+
44+
// BTI: define weak_odr ptr @global_target_clones.resolver() #[[ATTR_RESOLVER:[0-9]+]]
45+
// BTI: define weak_odr ptr @global_target_version.resolver() #[[ATTR_RESOLVER]]
46+
// BTI: define internal ptr @static_target_clones.resolver() #[[ATTR_RESOLVER]]
47+
// BTI: define internal ptr @static_target_version.resolver() #[[ATTR_RESOLVER]]
48+
49+
// In NOBTI case, no attribute groups are assigned to the resolver functions:
50+
// NOBTI: define weak_odr ptr @global_target_clones.resolver(){{[^#]*}} {
51+
// NOBTI: define weak_odr ptr @global_target_version.resolver(){{[^#]*}} {
52+
// NOBTI: define internal ptr @static_target_clones.resolver(){{[^#]*}} {
53+
// NOBTI: define internal ptr @static_target_version.resolver(){{[^#]*}} {
54+
55+
// HIDDEN: define weak_odr hidden ptr @global_target_clones.resolver(){{[^#]*}}
56+
// HIDDEN: define weak_odr hidden ptr @global_target_version.resolver(){{[^#]*}}
57+
// HIDDEN: define internal ptr @static_target_clones.resolver(){{[^#]*}}
58+
// HIDDEN: define internal ptr @static_target_version.resolver(){{[^#]*}}
59+
60+
// ELF: attributes #[[ATTR_IFUNC_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }
61+
62+
// BTI: attributes #[[ATTR_RESOLVER]] = { {{.*}}"branch-target-enforcement"{{.*}} }

clang/test/CodeGen/attr-target-clones.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
static int __attribute__((target_clones("sse4.2, default"))) internal(void) { return 0; }
4545
int use(void) { return internal(); }
4646
/// Internal linkage resolvers do not use comdat.
47-
// LINUX: define internal ptr @internal.resolver() {
47+
// LINUX: define internal ptr @internal.resolver() comdat {
4848
// DARWIN: define internal ptr @internal.resolver() {
49-
// WINDOWS: define internal i32 @internal() {
49+
// WINDOWS: define internal i32 @internal() comdat {
5050

5151
int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
5252
// LINUX: define {{.*}}i32 @foo.sse4.2.0()

clang/test/CodeGen/attr-target-mv.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -283,9 +283,9 @@ void calls_pr50025c(void) { pr50025c(); }
283283
// WINDOWS: call i32 @foo
284284

285285
/// Internal linkage resolvers do not use comdat.
286-
// ITANIUM: define internal ptr @foo_internal.resolver() {
287-
288-
// WINDOWS: define internal i32 @foo_internal.resolver() {
286+
// LINUX: define internal ptr @foo_internal.resolver() comdat {
287+
// DARWIN: define internal ptr @foo_internal.resolver() {
288+
// WINDOWS: define internal i32 @foo_internal.resolver() comdat {
289289

290290
// ITANIUM: define{{.*}} i32 @bar2()
291291
// ITANIUM: call i32 @foo_inline.ifunc()

0 commit comments

Comments
 (0)