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()) {
return true;
break;
default:
- return true;
+ if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType))
+ return true;
+ break;
}
}
return false;
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
// 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()
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}}