https://github.com/yxsamliu created https://github.com/llvm/llvm-project/pull/73140
Treat ctor/dtor in device var init as host device function so that they can be used to initialize file-scope device variables to match nvcc behavior. If they are non-trivial they will be diagnosed. We cannot add implicit host device attrs to non-trivial ctor/dtor since determining whether they are non-trivial needs to know whether they have a trivial body and all their member and base classes' ctor/dtor have trivial body, which is affected by where their bodies are defined or instantiated. Fixes: #72261 Fixes: SWDEV-432412 >From 511cecff7f76958ebfe713189bc106615763b64a Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <yaxun....@amd.com> Date: Wed, 22 Nov 2023 09:53:17 -0500 Subject: [PATCH 1/3] Revert "[CUDA][HIP] ignore implicit host/device attr for override (#72815)" This reverts commit a1e2c6566305061c115954b048f2957c8d55cb5b. --- clang/lib/Sema/SemaOverload.cpp | 6 ++---- .../SemaCUDA/implicit-member-target-inherited.cu | 1 - clang/test/SemaCUDA/trivial-ctor-dtor.cu | 16 ---------------- 3 files changed, 2 insertions(+), 21 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 64607e28b8b35e6..9800d7f1c9cfee9 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1491,10 +1491,8 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, // Don't allow overloading of destructors. (In theory we could, but it // would be a giant change to clang.) if (!isa<CXXDestructorDecl>(New)) { - Sema::CUDAFunctionTarget NewTarget = SemaRef.IdentifyCUDATarget( - New, isa<CXXConstructorDecl>(New)), - OldTarget = SemaRef.IdentifyCUDATarget( - Old, isa<CXXConstructorDecl>(New)); + Sema::CUDAFunctionTarget NewTarget = SemaRef.IdentifyCUDATarget(New), + OldTarget = SemaRef.IdentifyCUDATarget(Old); if (NewTarget != Sema::CFT_InvalidTarget) { assert((OldTarget != Sema::CFT_InvalidTarget) && "Unexpected invalid target."); diff --git a/clang/test/SemaCUDA/implicit-member-target-inherited.cu b/clang/test/SemaCUDA/implicit-member-target-inherited.cu index ceca0891fc9b03c..781199bba6b5a11 100644 --- a/clang/test/SemaCUDA/implicit-member-target-inherited.cu +++ b/clang/test/SemaCUDA/implicit-member-target-inherited.cu @@ -39,7 +39,6 @@ struct A2_with_device_ctor { }; // expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable}} // expected-note@-4 {{candidate constructor (the implicit move constructor) not viable}} -// expected-note@-4 {{candidate inherited constructor not viable: call to __device__ function from __host__ function}} struct B2_with_implicit_default_ctor : A2_with_device_ctor { using A2_with_device_ctor::A2_with_device_ctor; diff --git a/clang/test/SemaCUDA/trivial-ctor-dtor.cu b/clang/test/SemaCUDA/trivial-ctor-dtor.cu index 21d698d28492ac3..1df8adc62bab590 100644 --- a/clang/test/SemaCUDA/trivial-ctor-dtor.cu +++ b/clang/test/SemaCUDA/trivial-ctor-dtor.cu @@ -38,19 +38,3 @@ struct TC : TB<T> { }; __device__ TC<int> tc; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}} - -// Check trivial ctor specialization -template <typename T> -struct C { //expected-note {{candidate constructor (the implicit copy constructor) not viable}} - //expected-note@-1 {{candidate constructor (the implicit move constructor) not viable}} - explicit C() {}; -}; - -template <> C<int>::C() {}; -__device__ C<int> ci_d; -C<int> ci_h; - -// Check non-trivial ctor specialization -template <> C<float>::C() { static int nontrivial_ctor = 1; } //expected-note {{candidate constructor not viable: call to __host__ function from __device__ function}} -__device__ C<float> cf_d; //expected-error {{no matching constructor for initialization of 'C<float>'}} -C<float> cf_h; >From e9a8e906d4c14eb4b317a7420b9bba3dc7321ba2 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <yaxun....@amd.com> Date: Wed, 22 Nov 2023 09:53:20 -0500 Subject: [PATCH 2/3] Revert "[CUDA][HIP] make trivial ctor/dtor host device (#72394)" This reverts commit 27e6e4a4d0e3296cebad8db577ec0469a286795e. --- clang/include/clang/Sema/Sema.h | 4 -- clang/lib/Sema/SemaCUDA.cpp | 16 -------- clang/lib/Sema/SemaDecl.cpp | 3 -- .../test/SemaCUDA/call-host-fn-from-device.cu | 2 +- clang/test/SemaCUDA/default-ctor.cu | 2 +- .../implicit-member-target-collision-cxx11.cu | 2 +- .../implicit-member-target-collision.cu | 2 +- .../implicit-member-target-inherited.cu | 4 +- clang/test/SemaCUDA/implicit-member-target.cu | 4 +- clang/test/SemaCUDA/trivial-ctor-dtor.cu | 40 ------------------- 10 files changed, 8 insertions(+), 71 deletions(-) delete mode 100644 clang/test/SemaCUDA/trivial-ctor-dtor.cu diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 59806bcbcbb2dbc..e8914f5fcddf19e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13466,10 +13466,6 @@ 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); diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index b94f448dabe7517..318174f7be8fa95 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -772,22 +772,6 @@ 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. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 4e1857b931cc868..23dd8ae15c16583 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -16255,9 +16255,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD && !FD->isDeleted()) checkTypeSupport(FD->getType(), FD->getLocation(), FD); - if (LangOpts.CUDA) - maybeAddCUDAHostDeviceAttrsToTrivialCtorDtor(FD); - return dcl; } diff --git a/clang/test/SemaCUDA/call-host-fn-from-device.cu b/clang/test/SemaCUDA/call-host-fn-from-device.cu index b62de92db02d6de..acdd291b664579b 100644 --- a/clang/test/SemaCUDA/call-host-fn-from-device.cu +++ b/clang/test/SemaCUDA/call-host-fn-from-device.cu @@ -12,7 +12,7 @@ extern "C" void host_fn() {} struct Dummy {}; struct S { - S() { static int nontrivial_ctor = 1; } + S() {} // expected-note@-1 2 {{'S' declared here}} ~S() { host_fn(); } // expected-note@-1 {{'~S' declared here}} diff --git a/clang/test/SemaCUDA/default-ctor.cu b/clang/test/SemaCUDA/default-ctor.cu index 31971fe6b3863c7..cbad7a1774c1501 100644 --- a/clang/test/SemaCUDA/default-ctor.cu +++ b/clang/test/SemaCUDA/default-ctor.cu @@ -25,7 +25,7 @@ __device__ void fd() { InD ind; InH inh; // expected-error{{no matching constructor for initialization of 'InH'}} InHD inhd; - Out out; + Out out; // expected-error{{no matching constructor for initialization of 'Out'}} OutD outd; OutH outh; // expected-error{{no matching constructor for initialization of 'OutH'}} OutHD outhd; diff --git a/clang/test/SemaCUDA/implicit-member-target-collision-cxx11.cu b/clang/test/SemaCUDA/implicit-member-target-collision-cxx11.cu index edb543f637ccc18..06015ed0d6d8edc 100644 --- a/clang/test/SemaCUDA/implicit-member-target-collision-cxx11.cu +++ b/clang/test/SemaCUDA/implicit-member-target-collision-cxx11.cu @@ -6,7 +6,7 @@ // Test 1: collision between two bases struct A1_with_host_ctor { - A1_with_host_ctor() { static int nontrivial_ctor = 1; } + A1_with_host_ctor() {} }; struct B1_with_device_ctor { diff --git a/clang/test/SemaCUDA/implicit-member-target-collision.cu b/clang/test/SemaCUDA/implicit-member-target-collision.cu index 16b5978af40872b..a50fddaa4615b22 100644 --- a/clang/test/SemaCUDA/implicit-member-target-collision.cu +++ b/clang/test/SemaCUDA/implicit-member-target-collision.cu @@ -6,7 +6,7 @@ // Test 1: collision between two bases struct A1_with_host_ctor { - A1_with_host_ctor() { static int nontrivial_ctor = 1; } + A1_with_host_ctor() {} }; struct B1_with_device_ctor { diff --git a/clang/test/SemaCUDA/implicit-member-target-inherited.cu b/clang/test/SemaCUDA/implicit-member-target-inherited.cu index 781199bba6b5a11..2178172ed01930d 100644 --- a/clang/test/SemaCUDA/implicit-member-target-inherited.cu +++ b/clang/test/SemaCUDA/implicit-member-target-inherited.cu @@ -6,7 +6,7 @@ // Test 1: infer inherited default ctor to be host. struct A1_with_host_ctor { - A1_with_host_ctor() { static int nontrivial_ctor = 1; } + A1_with_host_ctor() {} }; // expected-note@-3 {{candidate constructor (the implicit copy constructor) not viable}} // expected-note@-4 {{candidate constructor (the implicit move constructor) not viable}} @@ -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() { static int nontrivial_ctor = 1; } + A4_with_host_ctor() {} }; struct B4_with_inherited_host_ctor : A4_with_host_ctor{ diff --git a/clang/test/SemaCUDA/implicit-member-target.cu b/clang/test/SemaCUDA/implicit-member-target.cu index 552f8f2ebd94fd5..d87e69624043419 100644 --- a/clang/test/SemaCUDA/implicit-member-target.cu +++ b/clang/test/SemaCUDA/implicit-member-target.cu @@ -6,7 +6,7 @@ // Test 1: infer default ctor to be host. struct A1_with_host_ctor { - A1_with_host_ctor() { static int nontrivial_ctor = 1; } + A1_with_host_ctor() {} }; // The implicit default constructor is inferred to be host because it only needs @@ -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() { static int nontrivial_ctor = 1; } + A4_with_host_ctor() {} }; struct B4_with_implicit_default_ctor { diff --git a/clang/test/SemaCUDA/trivial-ctor-dtor.cu b/clang/test/SemaCUDA/trivial-ctor-dtor.cu deleted file mode 100644 index 1df8adc62bab590..000000000000000 --- a/clang/test/SemaCUDA/trivial-ctor-dtor.cu +++ /dev/null @@ -1,40 +0,0 @@ -// 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}} >From df2b64e19df24b2c2a3256af501b7190b32ebf36 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" <yaxun....@amd.com> Date: Wed, 22 Nov 2023 10:02:59 -0500 Subject: [PATCH 3/3] [CUDA][HIP] allow trivial ctor/dtor in device var init Treat ctor/dtor in device var init as host device function so that they can be used to initialize file-scope device variables to match nvcc behavior. If they are non-trivial they will be diagnosed. We cannot add implicit host device attrs to non-trivial ctor/dtor since determining whether they are non-trivial needs to know whether they have a trivial body and all their member and base classes' ctor/dtor have trivial body, which is affected by where their bodies are defined or instantiated. Fixes: #72261 Fixes: SWDEV-432412 --- clang/lib/Sema/SemaCUDA.cpp | 9 ++++ clang/test/SemaCUDA/trivial-ctor-dtor.cu | 57 ++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 clang/test/SemaCUDA/trivial-ctor-dtor.cu diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 318174f7be8fa95..6a66ecf6f94c178 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -225,6 +225,15 @@ Sema::CUDAFunctionPreference Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee) { assert(Callee && "Callee must be valid."); + + // Treat ctor/dtor as host device function in device var initializer to allow + // trivial ctor/dtor without device attr to be used. Non-trivial ctor/dtor + // will be diagnosed by checkAllowedCUDAInitializer. + if (Caller == nullptr && CurCUDATargetCtx.Kind == CTCK_InitGlobalVar && + CurCUDATargetCtx.Target == CFT_Device && + (isa<CXXConstructorDecl>(Callee) || isa<CXXDestructorDecl>(Callee))) + return CFP_HostDevice; + CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller); CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee); diff --git a/clang/test/SemaCUDA/trivial-ctor-dtor.cu b/clang/test/SemaCUDA/trivial-ctor-dtor.cu new file mode 100644 index 000000000000000..34142bcc621200f --- /dev/null +++ b/clang/test/SemaCUDA/trivial-ctor-dtor.cu @@ -0,0 +1,57 @@ +// 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() {} +}; + +template class TC<int>; + +__device__ TC<int> tc; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}} + +// Check trivial ctor specialization +template <typename T> +struct C { + explicit C() {}; +}; + +template <> C<int>::C() {}; +__device__ C<int> ci_d; +C<int> ci_h; + +// Check non-trivial ctor specialization +template <> C<float>::C() { static int nontrivial_ctor = 1; } +__device__ C<float> cf_d; //expected-error {{dynamic initialization is not supported for __device__, __constant__, __shared__, and __managed__ variables}} +C<float> cf_h; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits