Skip to content

Commit cc8390b

Browse files
author
Erich Keane
committed
Permit attribute 'used' with 'target' multiversioning.
This adds infrastructure for a multiversioning whitelist, plus adds 'used' to the allowed list with 'target'. The behavior here mirrors the implementation in GCC, where 'used' only applies to the single declaration and doesn't apply to the ifunc or resolver. This is not being applied to cpu_dispatch and cpu_specific, since the rules are more complicated for cpu_specific, which emits multiple symbols. Additionally, the author isn't currently aware of uses in the wild of this combination, but is aware of a number of target+used combinations.
1 parent 209094e commit cc8390b

File tree

3 files changed

+40
-6
lines changed

3 files changed

+40
-6
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9952,6 +9952,18 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
99529952
return false;
99539953
}
99549954

9955+
// Provide a white-list of attributes that are allowed to be combined with
9956+
// multiversion functions.
9957+
static bool AttrCompatibleWithMultiVersion(attr::Kind Kind,
9958+
MultiVersionKind MVType) {
9959+
switch (Kind) {
9960+
default:
9961+
return false;
9962+
case attr::Used:
9963+
return MVType == MultiVersionKind::Target;
9964+
}
9965+
}
9966+
99559967
static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
99569968
MultiVersionKind MVType) {
99579969
for (const Attr *A : FD->attrs()) {
@@ -9967,7 +9979,9 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
99679979
return true;
99689980
break;
99699981
default:
9970-
return true;
9982+
if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType))
9983+
return true;
9984+
break;
99719985
}
99729986
}
99739987
return false;

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ void bar5() {
5050
int __attribute__((target("avx"))) changed_to_mv(void) { return 0;}
5151
int __attribute__((target("fma4"))) changed_to_mv(void) { return 1;}
5252

53+
__attribute__((target("default"), used)) inline void foo_used(int i, double d) {}
54+
__attribute__((target("avx,sse4.2"))) inline void foo_used(int i, double d) {}
55+
56+
__attribute__((target("default"))) inline void foo_used2(int i, double d) {}
57+
__attribute__((target("avx,sse4.2"), used)) inline void foo_used2(int i, double d) {}
58+
59+
// LINUX: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32, double)* @foo_used to i8*), i8* bitcast (void (i32, double)* @foo_used2.avx_sse4.2 to i8*)], section "llvm.metadata"
60+
// WINDOWS: @llvm.used = appending global [2 x i8*] [i8* bitcast (void (i32, double)* @foo_used to i8*), i8* bitcast (void (i32, double)* @foo_used2.avx_sse4.2 to i8*)], section "llvm.metadata"
61+
5362
// LINUX: @foo.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo.resolver
5463
// LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline.resolver
5564
// LINUX: @foo_decls.ifunc = weak_odr ifunc void (), void ()* ()* @foo_decls.resolver
@@ -203,6 +212,16 @@ int __attribute__((target("fma4"))) changed_to_mv(void) { return 1;}
203212
// WINDOWS: define dso_local i32 @changed_to_mv.avx()
204213
// WINDOWS: define dso_local i32 @changed_to_mv.fma4()
205214

215+
// LINUX: define linkonce void @foo_used(i32 %{{.*}}, double %{{.*}})
216+
// LINUX-NOT: @foo_used.avx_sse4.2(
217+
// LINUX-NOT: @foo_used2(
218+
// LINUX: define linkonce void @foo_used2.avx_sse4.2(i32 %{{.*}}, double %{{.*}})
219+
220+
// WINDOWS: define linkonce_odr dso_local void @foo_used(i32 %{{.*}}, double %{{.*}})
221+
// WINDOWS-NOT: @foo_used.avx_sse4.2(
222+
// WINDOWS-NOT: @foo_used2(
223+
// WINDOWS: define linkonce_odr dso_local void @foo_used2.avx_sse4.2(i32 %{{.*}}, double %{{.*}})
224+
206225
// LINUX: declare i32 @foo.arch_sandybridge()
207226
// WINDOWS: declare dso_local i32 @foo.arch_sandybridge()
208227

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,21 +77,22 @@ int prev_no_target2(void);
7777
int __attribute__((target("arch=ivybridge"))) prev_no_target2(void);
7878

7979
void __attribute__((target("sse4.2"))) addtl_attrs(void);
80-
//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
81-
void __attribute__((used,target("arch=sandybridge"))) addtl_attrs(void);
80+
//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
81+
void __attribute__((no_caller_saved_registers,target("arch=sandybridge")))
82+
addtl_attrs(void);
8283

8384
//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
84-
void __attribute__((target("default"), used)) addtl_attrs2(void);
85+
void __attribute__((target("default"), no_caller_saved_registers)) addtl_attrs2(void);
8586

8687
//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
8788
//expected-note@+2 {{function multiversioning caused by this declaration}}
88-
void __attribute__((used,target("sse4.2"))) addtl_attrs3(void);
89+
void __attribute__((no_caller_saved_registers,target("sse4.2"))) addtl_attrs3(void);
8990
void __attribute__((target("arch=sandybridge"))) addtl_attrs3(void);
9091

9192
void __attribute__((target("sse4.2"))) addtl_attrs4(void);
9293
void __attribute__((target("arch=sandybridge"))) addtl_attrs4(void);
9394
//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
94-
void __attribute__((used,target("arch=ivybridge"))) addtl_attrs4(void);
95+
void __attribute__((no_caller_saved_registers,target("arch=ivybridge"))) addtl_attrs4(void);
9596

9697
int __attribute__((target("sse4.2"))) diff_cc(void);
9798
// expected-error@+1 {{multiversioned function declaration has a different calling convention}}

0 commit comments

Comments
 (0)