Skip to content

[SYCL] Add clang support for device_global #5597

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 35 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0251bfb
[SYCL] Add clang support for device_global
schittir Feb 7, 2022
117de59
Remove unused lines i.e., Merge attribute method calls and SYCLUniqueID
schittir Feb 16, 2022
a96d57a
Address some comments, fix format, remove unused lines
schittir Feb 16, 2022
f2230af
Add Sema test; address more comments
schittir Feb 17, 2022
0fb176d
Some fixes in order to pass CodeGen test
Fznamznon Feb 25, 2022
e4c15c4
Refactor isSyclGlobalVariableAllowedType
schittir Feb 25, 2022
af8a294
Fix some test cases; address some comments
schittir Feb 18, 2022
feb841b
Remove explicit attribute handling; change diagnostic message; add test
schittir Mar 1, 2022
df337a7
Add diagnostic to test
schittir Mar 1, 2022
748e8ce
Address Mariya's comments
schittir Mar 1, 2022
d84428c
Fix typo; Refactor methods;
schittir Mar 1, 2022
0343158
Fix quotes, update diag messages, report private members
Fznamznon Mar 2, 2022
6d6d7dd
Change DeviceGlobalType checking call
schittir Mar 3, 2022
679b5f0
Move isSyclGlobalType definition to header
schittir Mar 3, 2022
5ecd545
Address latest comments
schittir Mar 3, 2022
e51530d
Merge remote-tracking branch 'intel_llvm_remote/sycl' into SYCL_devic…
schittir Mar 3, 2022
aef34f9
Add back attribute to CodeGenSYCL/Inputs/sycl.hpp after merge
schittir Mar 3, 2022
4cac80e
Remove additional definition of SYCLDeviceGlobal
schittir Mar 3, 2022
3f79c5e
Add test description; Remove unsupported test cases
schittir Mar 3, 2022
2664869
Fix format
schittir Mar 3, 2022
0469d18
clang-format again!
schittir Mar 4, 2022
d25c816
Fix lit tests; Address comments
schittir Mar 4, 2022
19f62a5
Fix lint
schittir Mar 4, 2022
0354ea5
Lint again :(
schittir Mar 4, 2022
b45159d
Fix build failure; Add comment; Fix indentation
schittir Mar 7, 2022
3baff38
Fix lit test SemaSYCL/explicit-cast-to-generic.cpp
schittir Mar 9, 2022
5bced1a
Emit generic addrspace in llvm.used and llvm.global_ctors
Fznamznon Mar 9, 2022
505a4f2
Fix format
schittir Mar 9, 2022
4905d70
Add comments; rename method; add separate AST test
schittir Mar 10, 2022
3817bf0
Fix lint that git-clang-format didn't catch :(
schittir Mar 10, 2022
1c53934
Add case where device_global attributes are applied to the wrong subject
schittir Mar 11, 2022
e489d50
Attribute doesn't apply to this type
schittir Mar 11, 2022
0709448
Add comments in CodeGenModule.cpp
schittir Mar 11, 2022
d4647f6
Change comments
schittir Mar 14, 2022
ef0f5d0
Change "customer code" to "user code" in documentation
schittir Mar 15, 2022
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
18 changes: 18 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,24 @@ def SYCLIntelMaxGlobalWorkDim : InheritableAttr {
let SupportsNonconformingLambdaSyntax = 1;
}

def SYCLDeviceGlobal: InheritableAttr {
let Spellings = [GNU<"device_global">,
CXX11<"__sycl_detail__", "device_global">];
let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
let Documentation = [SYCLDeviceGlobalAttrDocs];
let SimpleHandler = 1;
}

def SYCLGlobalVariableAllowed : InheritableAttr {
let Spellings = [GNU<"global_variable_allowed">,
CXX11<"__sycl_detail__", "global_variable_allowed">];
let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
let Documentation = [SYCLGlobalVariableAllowedAttrDocs];
let SimpleHandler = 1;
}

def SYCLIntelNoGlobalWorkOffset : InheritableAttr {
let Spellings = [CXX11<"intel", "no_global_work_offset">];
let Args = [ExprArgument<"Value", /*optional*/1>];
Expand Down
38 changes: 38 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3083,6 +3083,44 @@ function. In SYCL 2020 mode, the attribute is not propagated to the kernel.
}];
}

def SYCLDeviceGlobalAttrDocs : Documentation {
let Category = DocCatType;
let Heading = "__sycl_detail__::device_global";
let Content = [{
This attribute is part of support for SYCL device_global feature.
[[__sycl_detail__::device_global]] attribute is used for checking restrictions
on variable declarations using the device_global type instead of the class name.
We do not intend to support this as a general attribute that customer code can
use, so we have this attribute in sycl_detail namespace.

.. code-block:: c++

template<typename T>
struct [[__sycl_detail__::device_global]] device_global {}

device_global<int> Foo;
}];
}

def SYCLGlobalVariableAllowedAttrDocs : Documentation {
let Category = DocCatType;
let Heading = "__sycl_detail__::global_variable_allowed";
let Content = [{
This attribute is part of support for SYCL device_global feature.
[[__sycl_detail__::global_variable_allowed]] attribute is used to avoid
diagnosing an error when variables of type device_global are referenced in
device code. We do not intend to support this as a general attribute that
customer code can use, therefore it is wrapped in sycl_detail namespace.

.. code-block:: c++

template<typename T>
struct [[__sycl_detail__::device_global]] device_global {}

device_global<int> Foo;
}];
}

def SYCLFPGAPipeDocs : Documentation {
let Category = DocCatStmt;
let Heading = "pipe (read_only, write_only)";
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -7099,6 +7099,17 @@ def warn_format_nonliteral : Warning<
"format string is not a string literal">,
InGroup<FormatNonLiteral>, DefaultIgnore;

def err_sycl_device_global_incorrect_scope : Error<
"`device_global` variables must be static or declared at namespace scope">;
def err_not_publicly_accessible: Error<
"member variable %0 not publicly accessible from namespace scope">;
def err_array_of_device_global_not_allowed : Error<
"array of device_global %0 is not allowed">;
def err_shadow_variable_within_same_namespace: Error<
"shadow variable %0 not allowed withing the same enclosing namespace scope">;
def err_namespace_name_shadows_namespace_containing_device_global : Error<
"not allowed: namespace name shadows %0 namespace which contains device_global">;

def err_unexpected_interface : Error<
"unexpected interface name %0: expected expression">;
def err_ref_non_value : Error<"%0 does not refer to a value">;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -13125,6 +13125,9 @@ class Sema final {
SourceLocation BuiltinLoc,
SourceLocation RParenLoc);

bool isSyclGlobalVariableAllowedType(QualType Ty);
bool isSyclDeviceGlobalType(QualType Ty);

private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall);
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2839,6 +2839,12 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
}

void CodeGenModule::addSYCLUniqueID(llvm::GlobalVariable *GV,
const VarDecl *VD) {
auto builtinString = SYCLUniqueStableIdExpr::ComputeName(Context, VD);
GV->addAttribute("sycl-unique-id", builtinString);
}

bool CodeGenModule::isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn,
SourceLocation Loc) const {
const auto &NoSanitizeL = getContext().getNoSanitizeList();
Expand Down Expand Up @@ -4927,6 +4933,12 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (getLangOpts().SYCLIsDevice)
addGlobalIntelFPGAAnnotation(D, GV);

if (getLangOpts().SYCLIsDevice) {
const RecordDecl *RD = D->getType()->getAsRecordDecl();
if (RD && RD->hasAttr<SYCLDeviceGlobalAttr>())
addSYCLUniqueID(GV, D);
}

if (D->getType().isRestrictQualified()) {
llvm::LLVMContext &Context = getLLVMContext();

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,10 @@ class CodeGenModule : public CodeGenTypeCache {
/// annotations are emitted during finalization of the LLVM code.
void AddGlobalAnnotations(const ValueDecl *D, llvm::GlobalValue *GV);

/// Add "sycl-unique-id" llvm attribute for global variables marked with
/// SYCL device_global attribute
void addSYCLUniqueID(llvm::GlobalVariable *GV, const VarDecl *VD);

bool isInNoSanitizeList(SanitizerMask Kind, llvm::Function *Fn,
SourceLocation Loc) const;

Expand Down
15 changes: 14 additions & 1 deletion clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,18 @@ static void emitCallStackNotes(Sema &S, FunctionDecl *FD) {
}
}

bool Sema::isSyclGlobalVariableAllowedType(QualType Ty) {
const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl();
if (!RecTy)
return false;
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RecTy)) {
ClassTemplateDecl *Template = CTSD->getSpecializedTemplate();
if (CXXRecordDecl *RD = Template->getTemplatedDecl())
return RD->hasAttr<SYCLGlobalVariableAllowedAttr>();
}
return RecTy->hasAttr<SYCLGlobalVariableAllowedAttr>();
}

namespace {

/// Helper class that emits deferred diagnostic messages if an entity directly
Expand Down Expand Up @@ -1691,7 +1703,8 @@ class DeferredDiagnosticsEmitter
void visitUsedDecl(SourceLocation Loc, Decl *D) {
if (S.LangOpts.SYCLIsDevice && ShouldEmitRootNode) {
if (auto *VD = dyn_cast<VarDecl>(D)) {
if (!S.checkAllowedSYCLInitializer(VD)) {
if (!S.checkAllowedSYCLInitializer(VD) &&
!S.isSyclGlobalVariableAllowedType(VD->getType())) {
S.Diag(Loc, diag::err_sycl_restrict)
<< Sema::KernelConstStaticVariable;
return;
Expand Down
21 changes: 19 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7057,6 +7057,17 @@ static void copyAttrFromTypedefToDecl(Sema &S, Decl *D, const TypedefType *TT) {
D->addAttr(Clone);
}
}
bool Sema::isSyclDeviceGlobalType(QualType Ty) {
const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl();
if (!RecTy)
return false;
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RecTy)) {
ClassTemplateDecl *Template = CTSD->getSpecializedTemplate();
if (CXXRecordDecl *RD = Template->getTemplatedDecl())
return RD->hasAttr<SYCLDeviceGlobalAttr>();
}
return RecTy->hasAttr<SYCLDeviceGlobalAttr>();
}

NamedDecl *Sema::ActOnVariableDeclarator(
Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo,
Expand Down Expand Up @@ -7394,10 +7405,16 @@ NamedDecl *Sema::ActOnVariableDeclarator(

// Static variables declared inside SYCL device code must be const or
// constexpr
if (getLangOpts().SYCLIsDevice)
if (SCSpec == DeclSpec::SCS_static && !R.isConstant(Context))
if (getLangOpts().SYCLIsDevice) {
if (isSyclDeviceGlobalType(NewVD->getType()) &&
SCSpec != DeclSpec::SCS_static && !NewVD->hasGlobalStorage()) {
Diag(D.getIdentifierLoc(), diag::err_sycl_device_global_incorrect_scope);
}
if (SCSpec == DeclSpec::SCS_static && !R.isConstant(Context) &&
!isSyclGlobalVariableAllowedType(NewVD->getType()))
SYCLDiagIfDeviceCode(D.getIdentifierLoc(), diag::err_sycl_restrict)
<< Sema::KernelNonConstStaticDataVariable;
}

switch (D.getDeclSpec().getConstexprSpecifier()) {
case ConstexprSpecKind::Unspecified:
Expand Down
10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,18 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
(!isUnevaluatedContext() && !isConstantEvaluated());
bool IsEsimdPrivateGlobal = isSYCLEsimdPrivateGlobal(VD);
// Non-const statics are not allowed in SYCL except for ESIMD or with the
// SYCLGlobalVar attribute.
// SYCLGlobalVar or SYCLGlobalVariableAllowed attribute.
if (IsRuntimeEvaluated && !IsEsimdPrivateGlobal && !IsConst &&
VD->getStorageClass() == SC_Static &&
!VD->hasAttr<SYCLGlobalVarAttr>())
!VD->hasAttr<SYCLGlobalVarAttr>() &&
!isSyclGlobalVariableAllowedType(VD->getType()))
SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict)
<< Sema::KernelNonConstStaticDataVariable;
// Non-const globals are not allowed in SYCL except for ESIMD or with the
// SYCLGlobalVar attribute.
// SYCLGlobalVar or SYCLGlobalVariableAllowed attribute.
else if (IsRuntimeEvaluated && !IsEsimdPrivateGlobal && !IsConst &&
VD->hasGlobalStorage() && !VD->hasAttr<SYCLGlobalVarAttr>())
VD->hasGlobalStorage() && !VD->hasAttr<SYCLGlobalVarAttr>() &&
!isSyclGlobalVariableAllowedType(VD->getType()))
SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict)
<< Sema::KernelGlobalVariable;
// ESIMD globals cannot be used in a SYCL context.
Expand Down
23 changes: 23 additions & 0 deletions clang/test/CodeGenSYCL/Inputs/sycl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,29 @@ struct no_alias {
template <bool> class instance {};
};
} // namespace property

// device_global type decorated with attributes
template <typename T>
class [[__sycl_detail__::device_global]]
[[__sycl_detail__::global_variable_allowed]] device_global {
public :
const T & get() const noexcept { return *Data; }
device_global() {}
operator T&() noexcept { return *Data; }
private:
T *Data;
};

// decorated with only global_variable_allowed attribute
template <typename T>
class [[__sycl_detail__::global_variable_allowed]] only_global_var_allowed {
public :
const T & get() const noexcept { return *Data; }
only_global_var_allowed() {}
operator T&() noexcept { return *Data; }
private:
T *Data;
};
} // namespace oneapi
} // namespace ext

Expand Down
64 changes: 64 additions & 0 deletions clang/test/CodeGenSYCL/device_global.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// RUN: %clang_cc1 -fsycl-is-device -internal-isystem %S/Inputs -triple spir64-unknown-unknown-sycldevice -disable-llvm-passes -fsycl-unique-prefix=THE_PREFIX -std=c++17 -emit-llvm %s -o - | FileCheck %s
#include "sycl.hpp"

using namespace sycl::ext::oneapi;
using namespace cl::sycl;
queue q;

device_global<int> A;
static device_global<int> B;

struct Foo {
static device_global<int> C;
};
device_global<int> Foo::C;
// CHECK: @A = addrspace(1) global %"class.cl::sycl::ext::oneapi::device_global" zeroinitializer, align 8 #[[A_ATTRS:[0-9]+]]
// CHECK: @_ZL1B = internal addrspace(1) global %"class.cl::sycl::ext::oneapi::device_global" zeroinitializer, align 8 #[[B_ATTRS:[0-9]+]]
// CHECK: @_ZN3Foo1CE = addrspace(1) global %"class.cl::sycl::ext::oneapi::device_global" zeroinitializer, align 8 #[[C_ATTRS:[0-9]+]]

device_global<int> same_name;
namespace NS {
device_global<int> same_name;
}
// CHECK: @same_name = addrspace(1) global %"class.cl::sycl::ext::oneapi::device_global" zeroinitializer, align 8 #[[SAME_NAME_ATTRS:[0-9]+]]
// CHECK: @_ZN2NS9same_nameE = addrspace(1) global %"class.cl::sycl::ext::oneapi::device_global" zeroinitializer, align 8 #[[SAME_NAME_NS_ATTRS:[0-9]+]]

// check that we don't generate `sycl-unique-id` IR attribute if class does not use
// [[__sycl_detail__::device_global]]
only_global_var_allowed<int> no_device_global;
// CHECK: @no_device_global = addrspace(1) global %"class.cl::sycl::ext::oneapi::only_global_var_allowed" zeroinitializer, align 8{{$}}

void foo() {
q.submit([&](handler &h) {
h.single_task<class kernel_name_1>([=]() {
(void)A;
(void)B;
(void)Foo::C;
(void)same_name;
(void)NS::same_name;
(void)no_device_global;
});
});
}

namespace {
device_global<int> same_name;
}
// CHECK: @_ZN12_GLOBAL__N_19same_nameE = internal addrspace(1) global %"class.cl::sycl::ext::oneapi::device_global" zeroinitializer, align 8 #[[SAME_NAME_ANON_NS_ATTRS:[0-9]+]]

namespace {
void bar() {
q.submit([&](handler &h) {
h.single_task<class kernel_name>([=]() { int A = same_name; });
});
}

}


// CHECK: attributes #[[A_ATTRS]] = { "sycl-unique-id"="_Z1A" }
// CHECK: attributes #[[B_ATTRS]] = { "sycl-unique-id"="THE_PREFIX____ZL1B" }
// CHECK: attributes #[[C_ATTRS]] = { "sycl-unique-id"="_ZN3Foo1CE" }
// CHECK: attributes #[[SAME_NAME_ATTRS]] = { "sycl-unique-id"="_Z9same_name" }
// CHECK: attributes #[[SAME_NAME_NS_ATTRS]] = { "sycl-unique-id"="_ZN2NS9same_nameE" }
// CHECK: attributes #[[SAME_NAME_ANON_NS_ATTRS]] = { "sycl-unique-id"="THE_PREFIX____ZN12_GLOBAL__N_19same_nameE" }
12 changes: 12 additions & 0 deletions clang/test/SemaSYCL/Inputs/sycl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,18 @@ namespace ext {
namespace oneapi {
template <typename... properties>
class accessor_property_list {};

// device_global type decorated with attributes
template <typename T>
struct [[__sycl_detail__::device_global]]
[[__sycl_detail__::global_variable_allowed]] device_global {
public:
const T & get() const noexcept { return *Data; }
device_global() {}
operator T&() noexcept { return *Data; }
private:
T *Data;
};
} // namespace oneapi
} // namespace ext

Expand Down
Loading