Skip to content

Commit 2225ffd

Browse files
committed
[SYCL] Move device code outlining to CodeGen, add tests
Moved device code outlining to CodeGen because the old scheme in combination with SYCL_EXTERNAL implementation for methods triggered assertions Signed-off-by: Mariya Podchishchaeva <[email protected]>
1 parent 2aef157 commit 2225ffd

File tree

8 files changed

+117
-69
lines changed

8 files changed

+117
-69
lines changed

clang/lib/AST/ASTContext.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10156,6 +10156,10 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
1015610156
if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
1015710157
return true;
1015810158

10159+
if (LangOpts.SYCLIsDevice && !D->hasAttr<OpenCLKernelAttr>() &&
10160+
!D->hasAttr<SYCLDeviceAttr>())
10161+
return false;
10162+
1015910163
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
1016010164
// Forward declarations aren't required.
1016110165
if (!FD->doesThisDeclarationHaveABody())
@@ -10179,10 +10183,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
1017910183
}
1018010184

1018110185
// Methods explcitly marked with 'sycl_device' attribute (via SYCL_EXTERNAL)
10182-
// must be emitted regardless of number of actual uses
10183-
if (LangOpts.SYCLIsDevice && isa<CXXMethodDecl>(D))
10186+
// or `indirectly_callable' attribute must be emitted regardless of number
10187+
// of actual uses
10188+
if (LangOpts.SYCLIsDevice && isa<CXXMethodDecl>(D)) {
10189+
if (auto *A = D->getAttr<SYCLDeviceIndirectlyCallableAttr>())
10190+
return !A->isImplicit();
1018410191
if (auto *A = D->getAttr<SYCLDeviceAttr>())
1018510192
return !A->isImplicit();
10193+
}
1018610194

1018710195
GVALinkage Linkage = GetGVALinkageForFunction(FD);
1018810196

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2516,11 +2516,6 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
25162516
if (Global->hasAttr<IFuncAttr>())
25172517
return emitIFuncDefinition(GD);
25182518

2519-
if (LangOpts.SYCLIsDevice) {
2520-
if (!Global->hasAttr<SYCLDeviceAttr>())
2521-
return;
2522-
}
2523-
25242519
// If this is a cpu_dispatch multiversion function, emit the resolver.
25252520
if (Global->hasAttr<CPUDispatchAttr>())
25262521
return emitCPUDispatchDefinition(GD);
@@ -2565,6 +2560,11 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
25652560
}
25662561
}
25672562

2563+
if (LangOpts.SYCLIsDevice && MustBeEmitted(Global)) {
2564+
addDeferredDeclToEmit(GD);
2565+
return;
2566+
}
2567+
25682568
// Ignore declarations, they will be emitted on their first use.
25692569
if (const auto *FD = dyn_cast<FunctionDecl>(Global)) {
25702570
// Forward declarations are emitted lazily on first use.

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4441,7 +4441,6 @@ static void handleSYCLDeviceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
44414441
<< AL << 1 /* function with a raw pointer parameter type */;
44424442
}
44434443

4444-
S.addSyclDeviceDecl(D);
44454444
handleSimpleAttribute<SYCLDeviceAttr>(S, D, AL);
44464445
}
44474446

@@ -4453,7 +4452,6 @@ static void handleSYCLDeviceIndirectlyCallableAttr(Sema &S, Decl *D,
44534452
return;
44544453
}
44554454

4456-
S.addSyclDeviceDecl(D);
44574455
D->addAttr(SYCLDeviceAttr::CreateImplicit(S.Context));
44584456
handleSimpleAttribute<SYCLDeviceIndirectlyCallableAttr>(S, D, AL);
44594457
}

clang/lib/Sema/SemaSYCL.cpp

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,6 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
228228

229229
CheckSYCLType(Callee->getReturnType(), Callee->getSourceRange());
230230

231-
if (FunctionDecl *Def = Callee->getDefinition()) {
232-
if (!Def->hasAttr<SYCLDeviceAttr>()) {
233-
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
234-
SemaRef.addSyclDeviceDecl(Def);
235-
}
236-
}
237231
if (auto const *FD = dyn_cast<FunctionDecl>(Callee)) {
238232
// FIXME: We need check all target specified attributes for error if
239233
// that function with attribute can not be called from sycl kernel. The
@@ -265,23 +259,6 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
265259
bool VisitCXXConstructExpr(CXXConstructExpr *E) {
266260
for (const auto &Arg : E->arguments())
267261
CheckSYCLType(Arg->getType(), Arg->getSourceRange());
268-
269-
CXXConstructorDecl *Ctor = E->getConstructor();
270-
271-
if (FunctionDecl *Def = Ctor->getDefinition()) {
272-
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
273-
SemaRef.addSyclDeviceDecl(Def);
274-
}
275-
276-
const auto *ConstructedType = Ctor->getParent();
277-
if (ConstructedType->hasUserDeclaredDestructor()) {
278-
CXXDestructorDecl *Dtor = ConstructedType->getDestructor();
279-
280-
if (FunctionDecl *Def = Dtor->getDefinition()) {
281-
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
282-
SemaRef.addSyclDeviceDecl(Def);
283-
}
284-
}
285262
return true;
286263
}
287264

@@ -330,25 +307,6 @@ class MarkDeviceFunction : public RecursiveASTVisitor<MarkDeviceFunction> {
330307
return true;
331308
}
332309

333-
bool VisitCXXNewExpr(CXXNewExpr *E) {
334-
// Memory storage allocation is not allowed in kernels.
335-
// All memory allocation for the device is done on
336-
// the host using accessor classes. Consequently, the default
337-
// allocation operator new overloads that allocate
338-
// storage are disallowed in a SYCL kernel. The placement
339-
// new operator and any user-defined overloads that
340-
// do not allocate storage are permitted.
341-
if (FunctionDecl *FD = E->getOperatorNew()) {
342-
if (FunctionDecl *Def = FD->getDefinition()) {
343-
if (!Def->hasAttr<SYCLDeviceAttr>()) {
344-
Def->addAttr(SYCLDeviceAttr::CreateImplicit(SemaRef.Context));
345-
SemaRef.addSyclDeviceDecl(Def);
346-
}
347-
}
348-
}
349-
return true;
350-
}
351-
352310
// The call graph for this translation unit.
353311
CallGraph SYCLCG;
354312
// The set of functions called by a kernel function.
@@ -1389,13 +1347,8 @@ void Sema::MarkDevice(void) {
13891347
}
13901348
}
13911349
for (const auto &elt : Marker.KernelSet) {
1392-
if (FunctionDecl *Def = elt->getDefinition()) {
1393-
if (!Def->hasAttr<SYCLDeviceAttr>()) {
1394-
Def->addAttr(SYCLDeviceAttr::CreateImplicit(Context));
1395-
addSyclDeviceDecl(Def);
1396-
}
1350+
if (FunctionDecl *Def = elt->getDefinition())
13971351
Marker.TraverseStmt(Def->getBody());
1398-
}
13991352
}
14001353
}
14011354

@@ -1467,10 +1420,6 @@ static void emitCallToUndefinedFnDiag(Sema &SemaRef, const FunctionDecl *Callee,
14671420
if (Callee->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
14681421
return;
14691422

1470-
// Don't emit diagnostic for functions not called from device code
1471-
if (!Caller->hasAttr<SYCLDeviceAttr>() && !Caller->hasAttr<SYCLKernelAttr>())
1472-
return;
1473-
14741423
bool RedeclHasAttr = false;
14751424

14761425
for (const Decl *Redecl : Callee->redecls()) {

clang/test/CodeGenSYCL/device-indirectly-callable-attr.cpp

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,65 @@ void foo() {
77
helper();
88
}
99

10-
// CHECK: define spir_func void @{{.*foo.*}}() #[[ATTRS_FOO:[0-9]+]]
10+
// CHECK: define spir_func void @{{.*foo.*}}() #[[ATTRS_INDIR_CALL:[0-9]+]]
1111
// CHECK: call spir_func void @{{.*helper.*}}()
1212
//
13-
// CHECK: define spir_func void @{{.*helper.*}}() #[[ATTRS_HELPER:[0-9]+]]
13+
// CHECK: define spir_func void @{{.*helper.*}}() #[[ATTRS_NOT_INDIR_CALL:[0-9]+]]
1414
//
15-
// CHECK: attributes #[[ATTRS_FOO]] = { {{.*}} "referenced-indirectly"
16-
// CHECK-NOT: attributes #[[ATTRS_HELPER]] = { {{.*}} "referenced-indirectly"
15+
16+
int bar20(int a) { return a + 20; }
17+
18+
class A {
19+
public:
20+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1A3fooEv{{.*}}#[[ATTRS_INDIR_CALL]]
21+
// CHECK-DAG: define spir_func i32 @_Z5bar20{{.*}}#[[ATTRS_NOT_INDIR_CALL]]
22+
[[intel::device_indirectly_callable]] void foo() { bar20(10); }
23+
24+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1AC1Ev{{.*}}#[[ATTRS_INDIR_CALL]]
25+
[[intel::device_indirectly_callable]] A() {}
26+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1AD1Ev{{.*}}#[[ATTRS_INDIR_CALL]]
27+
[[intel::device_indirectly_callable]] ~A() {}
28+
29+
template <typename T>
30+
[[intel::device_indirectly_callable]] void AFoo(T t) {}
31+
32+
// Templates are emitted when they are instantiated
33+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1A4AFooIiEEvT_{{.*}}#[[ATTRS_INDIR_CALL]]
34+
template <>
35+
[[intel::device_indirectly_callable]] void AFoo<int>(int t) {}
36+
};
37+
38+
39+
struct Base {
40+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN4Base12BaseWithAttrEv{{.*}}#[[ATTRS_INDIR_CALL]]
41+
[[intel::device_indirectly_callable]] virtual void BaseWithAttr() { int a = 10; }
42+
virtual void BaseWithoutAttr() {int b = 20; }
43+
};
44+
45+
struct Overrider : Base {
46+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Overrider12BaseWithAttrEv{{.*}}#[[ATTRS_INDIR_CALL]]
47+
[[intel::device_indirectly_callable]] void BaseWithAttr() override { int a = 20; }
48+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Overrider15BaseWithoutAttrEv{{.*}}#[[ATTRS_INDIR_CALL]]
49+
[[intel::device_indirectly_callable]] void BaseWithoutAttr() override { int b = 30; }
50+
};
51+
52+
struct Overrider1 : Base {
53+
// CHECK-NOT: define linkonce_odr spir_func void @_ZN10Overrider112BaseWithAttrEv
54+
void BaseWithAttr() override { int a = 20; }
55+
};
56+
57+
58+
struct Finalizer : Base {
59+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Finalizer12BaseWithAttrEv{{.*}}#[[ATTRS_INDIR_CALL]]
60+
[[intel::device_indirectly_callable]] void BaseWithAttr() final { int a = 20; }
61+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Finalizer15BaseWithoutAttrEv{{.*}}#[[ATTRS_INDIR_CALL]]
62+
[[intel::device_indirectly_callable]] void BaseWithoutAttr() final { int b = 30; }
63+
};
64+
65+
struct Finalizer1 : Base {
66+
// CHECK-NOT: define linkonce_odr spir_func void @_ZN10Finalizer112BaseWithAttrEv
67+
void BaseWithAttr() final { int a = 20; }
68+
};
69+
70+
// CHECK: attributes #[[ATTRS_INDIR_CALL]] = { {{.*}} "referenced-indirectly"
71+
// CHECK-NOT: attributes #[[ATTRS_NOT_INDIR_CALL]] = { {{.*}} "referenced-indirectly"

clang/test/CodeGenSYCL/sycl-device.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,19 @@
33

44
int bar(int b);
55

6+
int bar10(int a) { return a + 10; }
7+
int bar20(int a) { return a + 20; }
8+
69
class A {
710
public:
811
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1A3fooEv
9-
__attribute__((sycl_device)) void foo() {}
12+
// CHECK-DAG: define spir_func i32 @_Z5bar20i
13+
__attribute__((sycl_device)) void foo() { bar20(10); }
1014

1115
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1AC1Ev
1216
__attribute__((sycl_device))
13-
A() {}
17+
A() { bar10(10); }
18+
// CHECK-DAG: define spir_func i32 @_Z5bar10i
1419
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1AD1Ev
1520
__attribute__((sycl_device)) ~A() {}
1621

@@ -36,10 +41,41 @@ struct B<int> {
3641
int data;
3742
B(int _data) : data(_data) {}
3843

39-
// CHECK-DAG: _ZN1BIiE4BFooEi
44+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN1BIiE4BFooEi
4045
__attribute__((sycl_device)) void BFoo(int t) {}
4146
};
4247

48+
struct Base {
49+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN4Base12BaseWithAttrEv
50+
__attribute__((sycl_device)) virtual void BaseWithAttr() { int a = 10; }
51+
virtual void BaseWithoutAttr() {int b = 20; }
52+
};
53+
54+
struct Overrider : Base {
55+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Overrider12BaseWithAttrEv
56+
__attribute__((sycl_device)) void BaseWithAttr() override { int a = 20; }
57+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Overrider15BaseWithoutAttrEv
58+
__attribute__((sycl_device)) void BaseWithoutAttr() override { int b = 30; }
59+
};
60+
61+
struct Overrider1 : Base {
62+
// CHECK-NOT: define linkonce_odr spir_func void @_ZN10Overrider112BaseWithAttrEv
63+
void BaseWithAttr() override { int a = 20; }
64+
};
65+
66+
67+
struct Finalizer : Base {
68+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Finalizer12BaseWithAttrEv
69+
__attribute__((sycl_device)) void BaseWithAttr() final { int a = 20; }
70+
// CHECK-DAG: define linkonce_odr spir_func void @_ZN9Finalizer15BaseWithoutAttrEv
71+
__attribute__((sycl_device)) void BaseWithoutAttr() final { int b = 30; }
72+
};
73+
74+
struct Finalizer1 : Base {
75+
// CHECK-NOT: define linkonce_odr spir_func void @_ZN10Finalizer112BaseWithAttrEv
76+
void BaseWithAttr() final { int a = 20; }
77+
};
78+
4379
// CHECK-DAG: define spir_func i32 @_Z3fooii
4480
__attribute__((sycl_device))
4581
int foo(int a, int b) { return a + bar(b); }

clang/test/SemaSYCL/call-to-undefined-function.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ void forwardDeclFn() {
9292
}
9393

9494
int main() {
95+
// No problems in host code
96+
undefined();
97+
9598
kernel_single_task<class CallToUndefinedFnTester>([]() {
9699
// expected-note@-1 {{called by 'operator()'}}
97100
// expected-note@-2 {{called by 'operator()'}}

clang/test/SemaSYCL/device-indirectly-callable-attr.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ void baz() {}
4545
#endif // NO_SYCL
4646

4747
// CHECK: FunctionDecl {{.*}} helper
48-
// CHECK: SYCLDeviceAttr
4948
//
5049
// CHECK: FunctionDecl {{.*}} foo
5150
// CHECK: SYCLDeviceAttr

0 commit comments

Comments
 (0)