Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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 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">;
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -12659,7 +12661,8 @@ class Sema final {
KernelUseAssembly,
KernelCallDllimportFunction,
KernelCallVariadicFunction,
KernelCallUndefinedFunction
KernelCallUndefinedFunction,
KernelConstStaticVariable
};

bool isKnownGoodSYCLDecl(const Decl *D);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
VD->hasGlobalStorage() && !isa<ParmVarDecl>(VD))
SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict)
<< Sema::KernelGlobalVariable;
// Disallow const statics 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;
}
}

Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
// -----------------------------------------------------------------------------
Expand Down
9 changes: 8 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 4 additions & 9 deletions clang/test/CodeGenSYCL/sycl-device-static-init.cpp
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -33,11 +29,10 @@ const int BaseInit<T>::var = 9;
template struct BaseInit<TestBaseType>;
template <typename name, typename Func>
__attribute__((sycl_kernel)) void kernel_single_task(Func kernelFunc) {
kernelFunc(BaseInit<TestBaseType>::s_regbase);
kernelFunc();
}
int main() {
kernel_single_task<class fake_kernel>([=](RegisterBaseInit s) {
s.foo();
kernel_single_task<class fake_kernel>([=]() {
});
return 0;
}
37 changes: 34 additions & 3 deletions clang/test/SemaSYCL/sycl-device-const-static.cpp
Original file line number Diff line number Diff line change
@@ -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 <typename T>
struct U {
static const S s2;
};
template <class T>
const S U<T>::s2;

template struct U<Base>;

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 variable that is neither zero-initialized nor constant-initialized}}
(void)T::s1;
// expected-error@+1{{SYCL kernel cannot use a const static variable that is neither zero-initialized nor constant-initialized}}
(void)s5;
// expected-error@+1{{SYCL kernel cannot use a const static variable that is neither zero-initialized nor constant-initialized}}
(void)s6;
}

template <typename Name, typename Func>
__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<fake_kernel, (lambda at {{.*}})>}}
// expected-note-re@+2{{called by 'kernel_single_task<fake_kernel, (lambda at {{.*}})>}}
// expected-note-re@+1{{called by 'kernel_single_task<fake_kernel, (lambda at {{.*}})>}}
kernelFunc();
// expected-error@+1{{SYCL kernel cannot use a const static variable that is neither zero-initialized nor constant-initialized}}
kernelFunc(U<Base>::s2);
}

int main() {
static int s2;
kernel_single_task<class fake_kernel>([]() {
kernel_single_task<class fake_kernel>([](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;
});
Expand Down