diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 42456865f2567..80795aa4ee738 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10850,6 +10850,8 @@ def err_sycl_restrict : Error< "|call a dllimport function" "|call a variadic function" "|call an undefined function without SYCL_EXTERNAL attribute" + "|use a const static or global variable that is neither zero-initialized " + "nor constant-initialized" "}0">; def err_sycl_virtual_types : Error< "No class with a vtable can be used in a SYCL kernel or any code included in the kernel">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fe00bbcf63d66..2862eceade7ef 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9943,6 +9943,8 @@ class Sema final { void addSYCLIntelPipeIOAttr(Decl *D, const AttributeCommonInfo &CI, Expr *ID); bool checkNSReturnsRetainedReturnType(SourceLocation loc, QualType type); + bool checkAllowedSYCLInitializer(VarDecl *VD, + bool CheckValueDependent = false); // Adds an intel_reqd_sub_group_size attribute to a particular declaration. void addIntelReqdSubGroupSizeAttr(Decl *D, const AttributeCommonInfo &CI, @@ -12659,7 +12661,8 @@ class Sema final { KernelUseAssembly, KernelCallDllimportFunction, KernelCallVariadicFunction, - KernelCallUndefinedFunction + KernelCallUndefinedFunction, + KernelConstStaticVariable }; bool isKnownGoodSYCLDecl(const Decl *D); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index a6e440c3a8daa..2bdfb4dfd784e 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1288,8 +1288,7 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) { ctor.addInt(Int32Ty, I.Priority); ctor.add(llvm::ConstantExpr::getBitCast(I.Initializer, CtorPFTy)); if (I.AssociatedData) - ctor.add(llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( - I.AssociatedData, VoidPtrTy)); + ctor.add(llvm::ConstantExpr::getBitCast(I.AssociatedData, VoidPtrTy)); else ctor.addNullPointer(VoidPtrTy); ctor.finishAndAddTo(ctors); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d613db8a6b100..b5dd7a5cfef8d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -223,6 +223,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, VD->hasGlobalStorage() && !isa(VD)) SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict) << Sema::KernelGlobalVariable; + // Disallow const statics and globals that are not zero-initialized + // or constant-initialized. + else if (IsConst && VD->hasGlobalStorage() && !VD->isConstexpr() && + !checkAllowedSYCLInitializer(VD, /*CheckValueDependent =*/true)) + SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict) + << Sema::KernelConstStaticVariable; } } diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 09d5a45b306d0..758ea5f311f9f 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -1845,6 +1845,23 @@ void Sema::finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller, } } +bool Sema::checkAllowedSYCLInitializer(VarDecl *VD, bool CheckValueDependent) { + assert(getLangOpts().SYCLIsDevice && + "Should only be called during SYCL compilation"); + + if (VD->isInvalidDecl() || !VD->hasInit() || !VD->hasGlobalStorage()) + return true; + + const Expr *Init = VD->getInit(); + bool ValueDependent = CheckValueDependent && Init->isValueDependent(); + bool isConstantInit = + Init && !ValueDependent && Init->isConstantInitializer(Context, false); + if (!VD->isConstexpr() && Init && !ValueDependent && !isConstantInit) + return false; + + return true; +} + // ----------------------------------------------------------------------------- // Integration header functionality implementation // ----------------------------------------------------------------------------- diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 49e82c02939b1..5a2967cd091f3 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5101,6 +5101,10 @@ void Sema::InstantiateVariableInitializer( if (getLangOpts().CUDA) checkAllowedCUDAInitializer(Var); + + if (getLangOpts().SYCLIsDevice && !checkAllowedSYCLInitializer(Var)) + SYCLDiagIfDeviceCode(Var->getLocation(), diag::err_sycl_restrict) + << Sema::KernelConstStaticVariable; } /// Instantiate the definition of the given variable from its @@ -5255,7 +5259,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // Do not explicitly emit non-const static data member definitions // on SYCL device. if (!SemaRef.getLangOpts().SYCLIsDevice || !Var->isStaticDataMember() || - Var->isConstexpr() || Var->getType().isConstQualified()) + Var->isConstexpr() || + (Var->getType().isConstQualified() && Var->getInit() && + Var->getInit()->isConstantInitializer(SemaRef.getASTContext(), + false))) Consumer.HandleCXXStaticMemberVarInstantiation(Var); } } PassToConsumerRAII(*this, Consumer, Var); diff --git a/clang/test/CodeGenSYCL/sycl-device-static-init.cpp b/clang/test/CodeGenSYCL/sycl-device-static-init.cpp index 8ff1869ed7d74..b811b1061bfd6 100644 --- a/clang/test/CodeGenSYCL/sycl-device-static-init.cpp +++ b/clang/test/CodeGenSYCL/sycl-device-static-init.cpp @@ -1,17 +1,13 @@ // RUN: %clang_cc1 -fsycl -fsycl-is-device -triple spir64-unknown-unknown-sycldevice -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s // Test that static initializers do not force the emission of globals on sycl device -// CHECK: %struct._ZTS16RegisterBaseInit.RegisterBaseInit = type { i8 } // CHECK-NOT: $_ZN8BaseInitI12TestBaseTypeE15s_regbase_ncsdmE = comdat any // CHECK: $_ZN8BaseInitI12TestBaseTypeE3varE = comdat any -// CHECK: @_ZN8BaseInitI12TestBaseTypeE9s_regbaseE = {{.*}} global %struct._ZTS16RegisterBaseInit.RegisterBaseInit -// CHECK-NOT: @_ZN8BaseInitI12TestBaseTypeE15s_regbase_ncsdmE = weak_odr addrspace(1) global %struct._ZTS16RegisterBaseInit.RegisterBaseInit zeroinitializer, comdat, align 1 // CHECK: @_ZN8BaseInitI12TestBaseTypeE3varE = weak_odr addrspace(1) constant i32 9, comdat, align 4 -// CHECK: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init, i8* addrspacecast (i8 addrspace(1)* getelementptr inbounds (%struct._ZTS16RegisterBaseInit.RegisterBaseInit, %struct._ZTS16RegisterBaseInit.RegisterBaseInit addrspace(1)* @_ZN8BaseInitI12TestBaseTypeE9s_regbaseE, i32 0, i32 0) to i8*) }] +// CHECK-NOT: @_ZN8BaseInitI12TestBaseTypeE15s_regbase_ncsdmE = weak_odr addrspace(1) global %struct._ZTS16RegisterBaseInit.RegisterBaseInit zeroinitializer, comdat, align 1 // CHECK-NOT: @_ZGVN8BaseInitI12TestBaseTypeE15s_regbase_ncsdmE = weak_odr global i64 0, comdat($_ZN8BaseInitI12TestBaseTypeE9s_regbaseE), align 8 // CHECK: define spir_kernel void @_ZTSZ4mainE11fake_kernel() -// CHECK: call spir_func void @"_ZZ4mainENK3$_0clE16RegisterBaseInit -// CHECK: declare spir_func void @_ZN16RegisterBaseInit3fooEv +// CHECK: call spir_func void @"_ZZ4mainENK3$_0clEv struct TestBaseType {}; struct RegisterBaseInit { @@ -33,11 +29,10 @@ const int BaseInit::var = 9; template struct BaseInit; template __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { - kernelFunc(BaseInit::s_regbase); + kernelFunc(); } int main() { - kernel_single_task([=](RegisterBaseInit s) { - s.foo(); + kernel_single_task([=]() { }); return 0; } diff --git a/clang/test/SemaSYCL/sycl-device-const-static.cpp b/clang/test/SemaSYCL/sycl-device-const-static.cpp index 359a533e4181b..0e90057c73d60 100644 --- a/clang/test/SemaSYCL/sycl-device-const-static.cpp +++ b/clang/test/SemaSYCL/sycl-device-const-static.cpp @@ -1,26 +1,57 @@ // RUN: %clang_cc1 -fsycl -fsycl-is-device -verify -fsyntax-only %s +struct Base {}; +struct S { + void foo() {} + S() {} +}; + +struct T { + const static S s1; +}; +const S T::s1; + +template +struct U { + static const S s2; +}; +template +const S U::s2; + +template struct U; + +const S s5; + void usage() { // expected-error@+1{{SYCL kernel cannot use a non-const static data variable}} static int s1; const static int cs = 0; constexpr static int ces = 0; + static const S s6; + // expected-error@+1{{SYCL kernel cannot use a const static or global variable that is neither zero-initialized nor constant-initialized}} + (void)T::s1; + // expected-error@+1{{SYCL kernel cannot use a const static or global variable that is neither zero-initialized nor constant-initialized}} + (void)s5; + // expected-error@+1{{SYCL kernel cannot use a const static or global variable that is neither zero-initialized nor constant-initialized}} + (void)s6; } template __attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) { // expected-error@+1{{SYCL kernel cannot use a non-const static data variable}} static int z; + // expected-note-re@+3{{called by 'kernel_single_task}} // expected-note-re@+2{{called by 'kernel_single_task}} - // expected-note-re@+1{{called by 'kernel_single_task}} - kernelFunc(); + // expected-error@+1{{SYCL kernel cannot use a const static or global variable that is neither zero-initialized nor constant-initialized}} + kernelFunc(U::s2); } int main() { static int s2; - kernel_single_task([]() { + kernel_single_task([](S s4) { // expected-note@+1{{called by 'operator()'}} usage(); + s4.foo(); // expected-error@+1{{SYCL kernel cannot use a non-const static data variable}} static int s3; });