Skip to content

Commit 876f99a

Browse files
yxsamliuMakarand Maydeo
authored andcommitted
[CUDA][HIP] make trivial ctor/dtor host device
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 cherry-pick of: llvm#72394 [CUDA][HIP] ignore implicit host/device attr for override When deciding whether a previous function declaration is an overload or override, implicit host/device attrs should not be considered. This fixes the failure for the following code: `template <typename T> class C { explicit C() {}; }; template <> C<int>::C() {}; ` The issue was introduced by llvm#72394 sine the template specialization is treated as overload due to implicit host/device attrs are considered for overload/override differentiation. cherry-pick of llvm#72815 Change-Id: Ie896cc0e4d5d82d5af48e08a996a3b392285d9ee
1 parent 357ce67 commit 876f99a

11 files changed

+92
-10
lines changed

clang/include/clang/Sema/Sema.h

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

13196+
/// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to a
13197+
/// trivial cotr/dtor that does not have host and device attributes.
13198+
void maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FunctionDecl *FD);
13199+
1319613200
/// May add implicit CUDAConstantAttr attribute to VD, depending on VD
1319713201
/// and current compilation settings.
1319813202
void MaybeAddCUDAConstantAttr(VarDecl *VD);

clang/lib/Sema/SemaCUDA.cpp

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

733+
// If a trivial ctor/dtor has no host/device
734+
// attributes, make it implicitly host device function.
735+
void Sema::maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FunctionDecl *FD) {
736+
bool IsTrivialCtor = false;
737+
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
738+
IsTrivialCtor = isEmptyCudaConstructor(SourceLocation(), CD);
739+
bool IsTrivialDtor = false;
740+
if (auto *DD = dyn_cast<CXXDestructorDecl>(FD))
741+
IsTrivialDtor = isEmptyCudaDestructor(SourceLocation(), DD);
742+
if ((IsTrivialCtor || IsTrivialDtor) && !FD->hasAttr<CUDAHostAttr>() &&
743+
!FD->hasAttr<CUDADeviceAttr>()) {
744+
FD->addAttr(CUDAHostAttr::CreateImplicit(Context));
745+
FD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
746+
}
747+
}
748+
733749
// TODO: `__constant__` memory may be a limited resource for certain targets.
734750
// A safeguard may be needed at the end of compilation pipeline if
735751
// `__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
@@ -15884,6 +15884,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
1588415884
if (FD && !FD->isDeleted())
1588515885
checkTypeSupport(FD->getType(), FD->getLocation(), FD);
1588615886

15887+
if (LangOpts.CUDA)
15888+
maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FD);
15889+
1588715890
return dcl;
1588815891
}
1588915892

clang/lib/Sema/SemaOverload.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,8 +1404,10 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
14041404
// Don't allow overloading of destructors. (In theory we could, but it
14051405
// would be a giant change to clang.)
14061406
if (!isa<CXXDestructorDecl>(New)) {
1407-
CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New),
1408-
OldTarget = IdentifyCUDATarget(Old);
1407+
CUDAFunctionTarget NewTarget = IdentifyCUDATarget(
1408+
New, isa<CXXConstructorDecl>(New)),
1409+
OldTarget = IdentifyCUDATarget(
1410+
Old, isa<CXXConstructorDecl>(New));
14091411
if (NewTarget != CFT_InvalidTarget) {
14101412
assert((OldTarget != CFT_InvalidTarget) &&
14111413
"Unexpected invalid target.");

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: 3 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}}
@@ -39,6 +39,7 @@ struct A2_with_device_ctor {
3939
};
4040
// expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable}}
4141
// expected-note@-4 {{candidate constructor (the implicit move constructor) not viable}}
42+
// expected-note@-4 {{candidate inherited constructor not viable: call to __device__ function from __host__ function}}
4243

4344
struct B2_with_implicit_default_ctor : A2_with_device_ctor {
4445
using A2_with_device_ctor::A2_with_device_ctor;
@@ -83,7 +84,7 @@ void hostfoo3() {
8384
// Test 4: infer inherited default ctor from a field, not a base
8485

8586
struct A4_with_host_ctor {
86-
A4_with_host_ctor() {}
87+
A4_with_host_ctor() { static int nontrivial_ctor = 1; }
8788
};
8889

8990
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: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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}}
41+
42+
// Check trivial ctor specialization
43+
template <typename T>
44+
struct C { //expected-note {{candidate constructor (the implicit copy constructor) not viable}}
45+
//expected-note@-1 {{candidate constructor (the implicit move constructor) not viable}}
46+
explicit C() {};
47+
};
48+
49+
template <> C<int>::C() {};
50+
__device__ C<int> ci_d;
51+
C<int> ci_h;
52+
53+
// Check non-trivial ctor specialization
54+
template <> C<float>::C() { static int nontrivial_ctor = 1; } //expected-note {{candidate constructor not viable: call to __host__ function from __device__ function}}
55+
__device__ C<float> cf_d; //expected-error {{no matching constructor for initialization of 'C<float>'}}
56+
C<float> cf_h;

0 commit comments

Comments
 (0)