Skip to content

Commit 92aba5a

Browse files
author
Erich Keane
committed
CPUDispatch- allow out of line member definitions
ICC permits this, and after some extensive testing it looks like we can support this with very little trouble. We intentionally don't choose to do this with attribute-target (despite it likely working as well!) because GCC does not support that, and introducing said incompatibility doesn't seem worth it.
1 parent 7ef2c68 commit 92aba5a

File tree

3 files changed

+104
-5
lines changed

3 files changed

+104
-5
lines changed

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9693,6 +9693,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
96939693
(D.getCXXScopeSpec().getScopeRep()->isDependent() ||
96949694
(!Previous.empty() && CurContext->isDependentContext()))) {
96959695
// ignore these
9696+
} else if (NewFD->isCPUDispatchMultiVersion() ||
9697+
NewFD->isCPUSpecificMultiVersion()) {
9698+
// ignore this, we allow the redeclaration behavior here to create new
9699+
// versions of the function.
96969700
} else {
96979701
// The user tried to provide an out-of-line definition for a
96989702
// function that is a member of a class or namespace, but there
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=LINUX
2+
// RUN: %clang_cc1 -triple x86_64-windows-pc -fms-compatibility -emit-llvm -o - %s | FileCheck %s --check-prefix=WINDOWS
3+
4+
struct OutOfLineDefs {
5+
int foo(int);
6+
int foo(int, int);
7+
__attribute__((cpu_specific(atom))) int foo(int, int, int) { return 1; }
8+
};
9+
10+
int __attribute__((cpu_specific(atom))) OutOfLineDefs::foo(int) {
11+
return 1;
12+
}
13+
int __attribute__((cpu_specific(ivybridge))) OutOfLineDefs::foo(int) {
14+
return 2;
15+
}
16+
int __attribute__((cpu_dispatch(ivybridge, atom))) OutOfLineDefs::foo(int) {
17+
}
18+
19+
int __attribute__((cpu_specific(atom))) OutOfLineDefs::foo(int, int) {
20+
return 1;
21+
}
22+
int __attribute__((cpu_specific(ivybridge))) OutOfLineDefs::foo(int, int) {
23+
return 2;
24+
}
25+
int __attribute__((cpu_dispatch(ivybridge, atom)))
26+
OutOfLineDefs::foo(int, int) {
27+
}
28+
29+
int __attribute__((cpu_specific(ivybridge))) OutOfLineDefs::foo(int, int, int) {
30+
return 2;
31+
}
32+
int __attribute__((cpu_specific(sandybridge)))
33+
OutOfLineDefs::foo(int, int, int) {
34+
return 3;
35+
}
36+
int __attribute__((cpu_dispatch(sandybridge, ivybridge, atom)))
37+
OutOfLineDefs::foo(int, int, int) {
38+
}
39+
40+
// IFunc definitions, Linux only.
41+
// LINUX: @_ZN13OutOfLineDefs3fooEi = weak_odr alias i32 (%struct.OutOfLineDefs*, i32), i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.ifunc
42+
// LINUX: @_ZN13OutOfLineDefs3fooEii = weak_odr alias i32 (%struct.OutOfLineDefs*, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.ifunc
43+
// LINUX: @_ZN13OutOfLineDefs3fooEiii = weak_odr alias i32 (%struct.OutOfLineDefs*, i32, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.ifunc
44+
45+
// LINUX: @_ZN13OutOfLineDefs3fooEi.ifunc = weak_odr ifunc i32 (%struct.OutOfLineDefs*, i32), i32 (%struct.OutOfLineDefs*, i32)* ()* @_ZN13OutOfLineDefs3fooEi.resolver
46+
// LINUX: @_ZN13OutOfLineDefs3fooEii.ifunc = weak_odr ifunc i32 (%struct.OutOfLineDefs*, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32)* ()* @_ZN13OutOfLineDefs3fooEii.resolver
47+
// LINUX: @_ZN13OutOfLineDefs3fooEiii.ifunc = weak_odr ifunc i32 (%struct.OutOfLineDefs*, i32, i32, i32), i32 (%struct.OutOfLineDefs*, i32, i32, i32)* ()* @_ZN13OutOfLineDefs3fooEiii.resolver
48+
49+
// Arity 1 version:
50+
// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEi.O
51+
// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEi.S
52+
// LINUX: define weak_odr i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.resolver()
53+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.S
54+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32)* @_ZN13OutOfLineDefs3fooEi.O
55+
// LINUX: call void @llvm.trap
56+
57+
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
58+
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
59+
// WINDOWS: define weak_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHH@Z"(%struct.OutOfLineDefs* %0, i32 %1)
60+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1)
61+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1)
62+
// WINDOWS: call void @llvm.trap
63+
64+
// Arity 2 version:
65+
// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEii.O
66+
// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEii.S
67+
// LINUX: define weak_odr i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.resolver()
68+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.S
69+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32)* @_ZN13OutOfLineDefs3fooEii.O
70+
// LINUX: call void @llvm.trap
71+
72+
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
73+
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
74+
// WINDOWS: define weak_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHH@Z"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
75+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
76+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2)
77+
// WINDOWS: call void @llvm.trap
78+
79+
// Arity 3 version:
80+
// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEiii.S
81+
// LINUX: define dso_local i32 @_ZN13OutOfLineDefs3fooEiii.R
82+
// LINUX: define weak_odr i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.resolver()
83+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.R
84+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.S
85+
// LINUX: ret i32 (%struct.OutOfLineDefs*, i32, i32, i32)* @_ZN13OutOfLineDefs3fooEiii.O
86+
// LINUX: call void @llvm.trap
87+
// LINUX: define linkonce_odr i32 @_ZN13OutOfLineDefs3fooEiii.O
88+
89+
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
90+
// WINDOWS: define dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
91+
// WINDOWS: define weak_odr dso_local i32 @"?foo@OutOfLineDefs@@QEAAHHHH@Z"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
92+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
93+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
94+
// WINDOWS: musttail call i32 @"?foo@OutOfLineDefs@@[email protected]"(%struct.OutOfLineDefs* %0, i32 %1, i32 %2, i32 %3)
95+
// WINDOWS: call void @llvm.trap
96+
// WINDOWS: define linkonce_odr dso_local i32 @"?foo@OutOfLineDefs@@[email protected]"
97+

clang/test/SemaCXX/attr-cpuspecific.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,12 @@ struct SpecialFuncs {
9898
SpecialFuncs& __attribute__((cpu_specific(atom))) operator=(SpecialFuncs&&) = delete;
9999
};
100100

101-
struct BadOutOfLine {
101+
struct OutOfLine {
102102
int __attribute__((cpu_specific(atom, ivybridge))) foo(int);
103103
};
104104

105-
int __attribute__((cpu_specific(atom, ivybridge))) BadOutOfLine::foo(int) { return 0; }
106-
// expected-error@+2 {{out-of-line definition of 'foo' does not match any declaration in 'BadOutOfLine'}}
107-
// expected-note@-2 {{member declaration nearly matches}}
108-
int __attribute__((cpu_specific(sandybridge))) BadOutOfLine::foo(int) { return 1; }
105+
int __attribute__((cpu_specific(atom, ivybridge))) OutOfLine::foo(int) { return 0; }
106+
int __attribute__((cpu_specific(sandybridge))) OutOfLine::foo(int) { return 1; }
109107

110108
// Ensure Cpp Spelling works.
111109
[[clang::cpu_specific(ivybridge,atom)]] int CppSpelling(){}

0 commit comments

Comments
 (0)