Skip to content

Commit 28d5ec2

Browse files
yxsamliuzahiraam
authored andcommitted
[CUDA][HIP] make trivial ctor/dtor host device (llvm#72394)
Make trivial ctor/dtor implicitly host device functions so that they can be used to initialize file-scope device variables to match nvcc behavior. Fixes: llvm#72261 Fixes: SWDEV-432412
1 parent 061c599 commit 28d5ec2

10 files changed

+71
-8
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13458,6 +13458,10 @@ class Sema final {
1345813458
void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD,
1345913459
const LookupResult &Previous);
1346013460

13461+
/// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to a
13462+
/// trivial cotr/dtor that does not have host and device attributes.
13463+
void maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FunctionDecl *FD);
13464+
1346113465
/// May add implicit CUDAConstantAttr attribute to VD, depending on VD
1346213466
/// and current compilation settings.
1346313467
void MaybeAddCUDAConstantAttr(VarDecl *VD);

clang/lib/Sema/SemaCUDA.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,22 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
772772
NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
773773
}
774774

775+
// If a trivial ctor/dtor has no host/device
776+
// attributes, make it implicitly host device function.
777+
void Sema::maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FunctionDecl *FD) {
778+
bool IsTrivialCtor = false;
779+
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
780+
IsTrivialCtor = isEmptyCudaConstructor(SourceLocation(), CD);
781+
bool IsTrivialDtor = false;
782+
if (auto *DD = dyn_cast<CXXDestructorDecl>(FD))
783+
IsTrivialDtor = isEmptyCudaDestructor(SourceLocation(), DD);
784+
if ((IsTrivialCtor || IsTrivialDtor) && !FD->hasAttr<CUDAHostAttr>() &&
785+
!FD->hasAttr<CUDADeviceAttr>()) {
786+
FD->addAttr(CUDAHostAttr::CreateImplicit(Context));
787+
FD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
788+
}
789+
}
790+
775791
// TODO: `__constant__` memory may be a limited resource for certain targets.
776792
// A safeguard may be needed at the end of compilation pipeline if
777793
// `__constant__` memory usage goes beyond limit.

clang/lib/Sema/SemaDecl.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16232,6 +16232,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1623216232
if (FD && !FD->isDeleted())
1623316233
checkTypeSupport(FD->getType(), FD->getLocation(), FD);
1623416234

16235+
if (LangOpts.CUDA)
16236+
maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FD);
16237+
1623516238
return dcl;
1623616239
}
1623716240

clang/test/SemaCUDA/call-host-fn-from-device.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ extern "C" void host_fn() {}
1212
struct Dummy {};
1313

1414
struct S {
15-
S() {}
15+
S() { static int nontrivial_ctor = 1; }
1616
// expected-note@-1 2 {{'S' declared here}}
1717
~S() { host_fn(); }
1818
// expected-note@-1 {{'~S' declared here}}

clang/test/SemaCUDA/default-ctor.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ __device__ void fd() {
2525
InD ind;
2626
InH inh; // expected-error{{no matching constructor for initialization of 'InH'}}
2727
InHD inhd;
28-
Out out; // expected-error{{no matching constructor for initialization of 'Out'}}
28+
Out out;
2929
OutD outd;
3030
OutH outh; // expected-error{{no matching constructor for initialization of 'OutH'}}
3131
OutHD outhd;

clang/test/SemaCUDA/implicit-member-target-collision-cxx11.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// Test 1: collision between two bases
77

88
struct A1_with_host_ctor {
9-
A1_with_host_ctor() {}
9+
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
1010
};
1111

1212
struct B1_with_device_ctor {

clang/test/SemaCUDA/implicit-member-target-collision.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// Test 1: collision between two bases
77

88
struct A1_with_host_ctor {
9-
A1_with_host_ctor() {}
9+
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
1010
};
1111

1212
struct B1_with_device_ctor {

clang/test/SemaCUDA/implicit-member-target-inherited.cu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// Test 1: infer inherited default ctor to be host.
77

88
struct A1_with_host_ctor {
9-
A1_with_host_ctor() {}
9+
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
1010
};
1111
// expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable}}
1212
// expected-note@-4 {{candidate constructor (the implicit move constructor) not viable}}
@@ -83,7 +83,7 @@ void hostfoo3() {
8383
// Test 4: infer inherited default ctor from a field, not a base
8484

8585
struct A4_with_host_ctor {
86-
A4_with_host_ctor() {}
86+
A4_with_host_ctor() { static int nontrivial_ctor = 1; }
8787
};
8888

8989
struct B4_with_inherited_host_ctor : A4_with_host_ctor{

clang/test/SemaCUDA/implicit-member-target.cu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// Test 1: infer default ctor to be host.
77

88
struct A1_with_host_ctor {
9-
A1_with_host_ctor() {}
9+
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
1010
};
1111

1212
// The implicit default constructor is inferred to be host because it only needs
@@ -75,7 +75,7 @@ void hostfoo3() {
7575
// Test 4: infer default ctor from a field, not a base
7676

7777
struct A4_with_host_ctor {
78-
A4_with_host_ctor() {}
78+
A4_with_host_ctor() { static int nontrivial_ctor = 1; }
7979
};
8080

8181
struct B4_with_implicit_default_ctor {
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
2+
// RUN: %clang_cc1 -isystem %S/Inputs -fcuda-is-device -fsyntax-only -verify %s
3+
4+
#include <cuda.h>
5+
6+
// Check trivial ctor/dtor
7+
struct A {
8+
int x;
9+
A() {}
10+
~A() {}
11+
};
12+
13+
__device__ A a;
14+
15+
// Check trivial ctor/dtor of template class
16+
template<typename T>
17+
struct TA {
18+
T x;
19+
TA() {}
20+
~TA() {}
21+
};
22+
23+
__device__ TA<int> ta;
24+
25+
// Check non-trivial ctor/dtor in parent template class
26+
template<typename T>
27+
struct TB {
28+
T x;
29+
TB() { static int nontrivial_ctor = 1; }
30+
~TB() {}
31+
};
32+
33+
template<typename T>
34+
struct TC : TB<T> {
35+
T x;
36+
TC() {}
37+
~TC() {}
38+
};
39+
40+
__device__ TC<int> tc; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}

0 commit comments

Comments
 (0)