Skip to content

[CUDA][HIP] make trivial ctor/dtor host device #72394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -13450,6 +13450,10 @@ class Sema final {
void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD,
const LookupResult &Previous);

/// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to a
/// trivial cotr/dtor that does not have host and device attributes.
void maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FunctionDecl *FD);

/// May add implicit CUDAConstantAttr attribute to VD, depending on VD
/// and current compilation settings.
void MaybeAddCUDAConstantAttr(VarDecl *VD);
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/Sema/SemaCUDA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,22 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD,
NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
}

// If a trivial ctor/dtor has no host/device
// attributes, make it implicitly host device function.
void Sema::maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FunctionDecl *FD) {
bool IsTrivialCtor = false;
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))
IsTrivialCtor = isEmptyCudaConstructor(SourceLocation(), CD);
bool IsTrivialDtor = false;
if (auto *DD = dyn_cast<CXXDestructorDecl>(FD))
IsTrivialDtor = isEmptyCudaDestructor(SourceLocation(), DD);
if ((IsTrivialCtor || IsTrivialDtor) && !FD->hasAttr<CUDAHostAttr>() &&
!FD->hasAttr<CUDADeviceAttr>()) {
FD->addAttr(CUDAHostAttr::CreateImplicit(Context));
FD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
}
}

// TODO: `__constant__` memory may be a limited resource for certain targets.
// A safeguard may be needed at the end of compilation pipeline if
// `__constant__` memory usage goes beyond limit.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16232,6 +16232,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD && !FD->isDeleted())
checkTypeSupport(FD->getType(), FD->getLocation(), FD);

if (LangOpts.CUDA)
maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FD);

return dcl;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCUDA/call-host-fn-from-device.cu
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ extern "C" void host_fn() {}
struct Dummy {};

struct S {
S() {}
S() { static int nontrivial_ctor = 1; }
// expected-note@-1 2 {{'S' declared here}}
~S() { host_fn(); }
// expected-note@-1 {{'~S' declared here}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCUDA/default-ctor.cu
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ __device__ void fd() {
InD ind;
InH inh; // expected-error{{no matching constructor for initialization of 'InH'}}
InHD inhd;
Out out; // expected-error{{no matching constructor for initialization of 'Out'}}
Out out;
OutD outd;
OutH outh; // expected-error{{no matching constructor for initialization of 'OutH'}}
OutHD outhd;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Test 1: collision between two bases

struct A1_with_host_ctor {
A1_with_host_ctor() {}
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
};

struct B1_with_device_ctor {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCUDA/implicit-member-target-collision.cu
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Test 1: collision between two bases

struct A1_with_host_ctor {
A1_with_host_ctor() {}
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
};

struct B1_with_device_ctor {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCUDA/implicit-member-target-inherited.cu
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Test 1: infer inherited default ctor to be host.

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

struct A4_with_host_ctor {
A4_with_host_ctor() {}
A4_with_host_ctor() { static int nontrivial_ctor = 1; }
};

struct B4_with_inherited_host_ctor : A4_with_host_ctor{
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCUDA/implicit-member-target.cu
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Test 1: infer default ctor to be host.

struct A1_with_host_ctor {
A1_with_host_ctor() {}
A1_with_host_ctor() { static int nontrivial_ctor = 1; }
};

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

struct A4_with_host_ctor {
A4_with_host_ctor() {}
A4_with_host_ctor() { static int nontrivial_ctor = 1; }
};

struct B4_with_implicit_default_ctor {
Expand Down
40 changes: 40 additions & 0 deletions clang/test/SemaCUDA/trivial-ctor-dtor.cu
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -verify %s
// RUN: %clang_cc1 -isystem %S/Inputs -fcuda-is-device -fsyntax-only -verify %s

#include <cuda.h>

// Check trivial ctor/dtor
struct A {
int x;
A() {}
~A() {}
};

__device__ A a;

// Check trivial ctor/dtor of template class
template<typename T>
struct TA {
T x;
TA() {}
~TA() {}
};

__device__ TA<int> ta;

// Check non-trivial ctor/dtor in parent template class
template<typename T>
struct TB {
T x;
TB() { static int nontrivial_ctor = 1; }
~TB() {}
};

template<typename T>
struct TC : TB<T> {
T x;
TC() {}
~TC() {}
};

__device__ TC<int> tc; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}}