forked from OSchip/llvm-project
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.
This commit is contained in:
parent
209094eeb6
commit
cc8390bfe3
|
@ -9952,6 +9952,18 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Provide a white-list of attributes that are allowed to be combined with
|
||||
// multiversion functions.
|
||||
static bool AttrCompatibleWithMultiVersion(attr::Kind Kind,
|
||||
MultiVersionKind MVType) {
|
||||
switch (Kind) {
|
||||
default:
|
||||
return false;
|
||||
case attr::Used:
|
||||
return MVType == MultiVersionKind::Target;
|
||||
}
|
||||
}
|
||||
|
||||
static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
|
||||
MultiVersionKind MVType) {
|
||||
for (const Attr *A : FD->attrs()) {
|
||||
|
@ -9967,7 +9979,9 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD,
|
|||
return true;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -50,6 +50,15 @@ void bar5() {
|
|||
int __attribute__((target("avx"))) changed_to_mv(void) { return 0;}
|
||||
int __attribute__((target("fma4"))) changed_to_mv(void) { return 1;}
|
||||
|
||||
__attribute__((target("default"), used)) inline void foo_used(int i, double d) {}
|
||||
__attribute__((target("avx,sse4.2"))) inline void foo_used(int i, double d) {}
|
||||
|
||||
__attribute__((target("default"))) inline void foo_used2(int i, double d) {}
|
||||
__attribute__((target("avx,sse4.2"), used)) inline void foo_used2(int i, double d) {}
|
||||
|
||||
// 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"
|
||||
// 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"
|
||||
|
||||
// LINUX: @foo.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo.resolver
|
||||
// LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline.resolver
|
||||
// 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;}
|
|||
// WINDOWS: define dso_local i32 @changed_to_mv.avx()
|
||||
// WINDOWS: define dso_local i32 @changed_to_mv.fma4()
|
||||
|
||||
// LINUX: define linkonce void @foo_used(i32 %{{.*}}, double %{{.*}})
|
||||
// LINUX-NOT: @foo_used.avx_sse4.2(
|
||||
// LINUX-NOT: @foo_used2(
|
||||
// LINUX: define linkonce void @foo_used2.avx_sse4.2(i32 %{{.*}}, double %{{.*}})
|
||||
|
||||
// WINDOWS: define linkonce_odr dso_local void @foo_used(i32 %{{.*}}, double %{{.*}})
|
||||
// WINDOWS-NOT: @foo_used.avx_sse4.2(
|
||||
// WINDOWS-NOT: @foo_used2(
|
||||
// WINDOWS: define linkonce_odr dso_local void @foo_used2.avx_sse4.2(i32 %{{.*}}, double %{{.*}})
|
||||
|
||||
// LINUX: declare i32 @foo.arch_sandybridge()
|
||||
// WINDOWS: declare dso_local i32 @foo.arch_sandybridge()
|
||||
|
||||
|
|
|
@ -77,21 +77,22 @@ int prev_no_target2(void);
|
|||
int __attribute__((target("arch=ivybridge"))) prev_no_target2(void);
|
||||
|
||||
void __attribute__((target("sse4.2"))) addtl_attrs(void);
|
||||
//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
|
||||
void __attribute__((used,target("arch=sandybridge"))) addtl_attrs(void);
|
||||
//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
|
||||
void __attribute__((no_caller_saved_registers,target("arch=sandybridge")))
|
||||
addtl_attrs(void);
|
||||
|
||||
//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
|
||||
void __attribute__((target("default"), used)) addtl_attrs2(void);
|
||||
void __attribute__((target("default"), no_caller_saved_registers)) addtl_attrs2(void);
|
||||
|
||||
//expected-error@+2 {{attribute 'target' multiversioning cannot be combined}}
|
||||
//expected-note@+2 {{function multiversioning caused by this declaration}}
|
||||
void __attribute__((used,target("sse4.2"))) addtl_attrs3(void);
|
||||
void __attribute__((no_caller_saved_registers,target("sse4.2"))) addtl_attrs3(void);
|
||||
void __attribute__((target("arch=sandybridge"))) addtl_attrs3(void);
|
||||
|
||||
void __attribute__((target("sse4.2"))) addtl_attrs4(void);
|
||||
void __attribute__((target("arch=sandybridge"))) addtl_attrs4(void);
|
||||
//expected-error@+1 {{attribute 'target' multiversioning cannot be combined}}
|
||||
void __attribute__((used,target("arch=ivybridge"))) addtl_attrs4(void);
|
||||
void __attribute__((no_caller_saved_registers,target("arch=ivybridge"))) addtl_attrs4(void);
|
||||
|
||||
int __attribute__((target("sse4.2"))) diff_cc(void);
|
||||
// expected-error@+1 {{multiversioned function declaration has a different calling convention}}
|
||||
|
|
Loading…
Reference in New Issue