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 all 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
29 changes: 19 additions & 10 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -1257,17 +1257,8 @@ def SYCLUsesAspects : InheritableAttr {
let Subjects = SubjectList<[CXXRecord, Function], ErrorDiag>;
let Args = [VariadicExprArgument<"Aspects">];
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
// Only used internally by the SYCL implementation
let Documentation = [Undocumented];
}

def SYCLDeviceGlobal : InheritableAttr {
let Spellings = [CXX11<"__sycl_detail__", "device_global">];
let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
// Only used internally by the SYCL implementation
// Only used internally by SYCL implementation
let Documentation = [Undocumented];
let SimpleHandler = 1;
}

// Marks functions which must not be vectorized via horizontal SIMT widening,
Expand Down Expand Up @@ -1448,6 +1439,24 @@ def SYCLIntelMaxGlobalWorkDim : InheritableAttr {
let SupportsNonconformingLambdaSyntax = 1;
}

def SYCLDeviceGlobal: InheritableAttr {
let Spellings = [CXX11<"__sycl_detail__", "device_global">];
let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
// Only used internally by SYCL implementation
let Documentation = [SYCLDeviceGlobalAttrDocs];
let SimpleHandler = 1;
}

def SYCLGlobalVariableAllowed : InheritableAttr {
let Spellings = [CXX11<"__sycl_detail__", "global_variable_allowed">];
let Subjects = SubjectList<[CXXRecord], ErrorDiag>;
let LangOpts = [SYCLIsDevice, SilentlyIgnoreSYCLIsHost];
// Only used internally by SYCL implementation
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
43 changes: 43 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3033,6 +3033,49 @@ 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.
Global or static variables of type decorated with this attribute have
`sycl-unique-id`, an LLVM IR attribute, added to the definition of each such
variable, which provides a unique string identifier using
__builtin_sycl_unique_stable_id.
We do not intend to support this as a general attribute that user 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 global or static variables of type decorated with this
attribute are referenced in device code. We do not intend to support this as a
general attribute that user code can use, therefore it is wrapped in
sycl_detail namespace.

.. code-block:: c++

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

device_global<int> Foo;
}];
}

def SYCLFPGAPipeDocs : Documentation {
let Category = DocCatStmt;
let Heading = "pipe (read_only, write_only)";
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -7094,6 +7094,11 @@ 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_sycl_device_global_not_publicly_accessible: Error<
"'device_global' member variable %0 is not publicly accessible from namespace scope">;

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
13 changes: 13 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -13163,6 +13163,19 @@ class Sema final {
SourceLocation BuiltinLoc,
SourceLocation RParenLoc);

template <typename AttrTy>
bool isTypeDecoratedWithDeclAttribute(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<AttrTy>();
}
return RecTy->hasAttr<AttrTy>();
}

private:
bool SemaBuiltinPrefetch(CallExpr *TheCall);
bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall);
Expand Down
49 changes: 41 additions & 8 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1594,10 +1594,17 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
llvm::Type *CtorPFTy = llvm::PointerType::get(CtorFTy,
TheModule.getDataLayout().getProgramAddressSpace());
llvm::PointerType *TargetType = VoidPtrTy;
// Get target type when templated global variables are used,
// to emit them correctly in the target (default) address space and avoid
// emitting them in a private address space.
if (getLangOpts().SYCLIsDevice)
TargetType = llvm::IntegerType::getInt8PtrTy(
getLLVMContext(), getContext().getTargetAddressSpace(LangAS::Default));

// Get the type of a ctor entry, { i32, void ()*, i8* }.
llvm::StructType *CtorStructTy = llvm::StructType::get(
Int32Ty, CtorPFTy, VoidPtrTy);
llvm::StructType *CtorStructTy =
llvm::StructType::get(Int32Ty, CtorPFTy, TargetType);

// Construct the constructor and destructor arrays.
ConstantInitBuilder builder(*this);
Expand All @@ -1606,10 +1613,12 @@ void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
auto ctor = ctors.beginStruct(CtorStructTy);
ctor.addInt(Int32Ty, I.Priority);
ctor.add(llvm::ConstantExpr::getBitCast(I.Initializer, CtorPFTy));
// Emit appropriate bitcasts for pointers of different address spaces.
if (I.AssociatedData)
ctor.add(llvm::ConstantExpr::getBitCast(I.AssociatedData, VoidPtrTy));
ctor.add(llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
I.AssociatedData, TargetType));
else
ctor.addNullPointer(VoidPtrTy);
ctor.addNullPointer(TargetType);
ctor.finishAndAddTo(ctors);
}

Expand Down Expand Up @@ -2428,19 +2437,26 @@ static void emitUsed(CodeGenModule &CGM, StringRef Name,
// Don't create llvm.used if there is no need.
if (List.empty())
return;
// For SYCL emit pointers in the default address space which is a superset of
// other address spaces, so that casts from any other address spaces will be
// valid.
llvm::PointerType *TargetType = CGM.Int8PtrTy;
if (CGM.getLangOpts().SYCLIsDevice)
TargetType = llvm::IntegerType::getInt8PtrTy(
CGM.getLLVMContext(),
CGM.getContext().getTargetAddressSpace(LangAS::Default));

// Convert List to what ConstantArray needs.
SmallVector<llvm::Constant*, 8> UsedArray;
UsedArray.resize(List.size());
for (unsigned i = 0, e = List.size(); i != e; ++i) {
UsedArray[i] =
llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
cast<llvm::Constant>(&*List[i]), CGM.Int8PtrTy);
UsedArray[i] = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
cast<llvm::Constant>(&*List[i]), TargetType);
}

if (UsedArray.empty())
return;
llvm::ArrayType *ATy = llvm::ArrayType::get(CGM.Int8PtrTy, UsedArray.size());
llvm::ArrayType *ATy = llvm::ArrayType::get(TargetType, UsedArray.size());

auto *GV = new llvm::GlobalVariable(
CGM.getModule(), ATy, false, llvm::GlobalValue::AppendingLinkage,
Expand Down Expand Up @@ -2846,6 +2862,15 @@ void CodeGenModule::AddGlobalAnnotations(const ValueDecl *D,
Annotations.push_back(EmitAnnotateAttr(GV, I, D->getLocation()));
}

// Add "sycl-unique-id" llvm IR attribute that has a unique string generated
// by __builtin_sycl_unique_stable_id for global variables marked with
// SYCL device_global attribute.
static void addSYCLUniqueID(llvm::GlobalVariable *GV, const VarDecl *VD,
ASTContext &Context) {
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 @@ -4942,6 +4967,14 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
if (getLangOpts().SYCLIsDevice)
addGlobalIntelFPGAAnnotation(D, GV);

// If VarDecl has a type decorated with SYCL device_global attribute, emit IR
// attribute 'sycl-unique-id'.
if (getLangOpts().SYCLIsDevice) {
const RecordDecl *RD = D->getType()->getAsRecordDecl();
if (RD && RD->hasAttr<SYCLDeviceGlobalAttr>())
addSYCLUniqueID(GV, D, Context);
}

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

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1703,7 +1703,9 @@ 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.isTypeDecoratedWithDeclAttribute<SYCLGlobalVariableAllowedAttr>(
VD->getType())) {
S.Diag(Loc, diag::err_sycl_restrict)
<< Sema::KernelConstStaticVariable;
return;
Expand Down
19 changes: 15 additions & 4 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7400,12 +7400,23 @@ NamedDecl *Sema::ActOnVariableDeclarator(
NewVD->setTSCSpec(TSCS);
}

// Static variables declared inside SYCL device code must be const or
// constexpr
if (getLangOpts().SYCLIsDevice)
if (SCSpec == DeclSpec::SCS_static && !R.isConstant(Context))
// Global variables with types decorated with device_global attribute must be
// static if they are declared in SYCL device code.
if (getLangOpts().SYCLIsDevice) {
if (SCSpec != DeclSpec::SCS_static && !NewVD->hasGlobalStorage() &&
isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
NewVD->getType()))
Diag(D.getIdentifierLoc(), diag::err_sycl_device_global_incorrect_scope);

// Static variables declared inside SYCL device code must be const or
// constexpr unless their types are decorated with global_variable_allowed
// attribute.
if (SCSpec == DeclSpec::SCS_static && !R.isConstant(Context) &&
!isTypeDecoratedWithDeclAttribute<SYCLGlobalVariableAllowedAttr>(
NewVD->getType()))
SYCLDiagIfDeviceCode(D.getIdentifierLoc(), diag::err_sycl_restrict)
<< Sema::KernelNonConstStaticDataVariable;
}

switch (D.getDeclSpec().getConstexprSpecifier()) {
case ConstexprSpecKind::Unspecified:
Expand Down
13 changes: 13 additions & 0 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3529,6 +3529,19 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
}
}

// Emit diagnostic if a private member of type decorated with device_global
// attribute is accessed.
if (getLangOpts().SYCLIsDevice) {
if (auto Value = dyn_cast<ValueDecl>(Member)) {
if (isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
Value->getType()) &&
Value->getAccess() != AS_public) {
Diag(Loc, diag::err_sycl_device_global_not_publicly_accessible)
<< Value;
}
}
}

return Member;
}

Expand Down
12 changes: 8 additions & 4 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,16 +227,20 @@ 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>() &&
!isTypeDecoratedWithDeclAttribute<SYCLGlobalVariableAllowedAttr>(
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>() &&
!isTypeDecoratedWithDeclAttribute<SYCLGlobalVariableAllowedAttr>(
VD->getType()))
SYCLDiagIfDeviceCode(*Locs.begin(), diag::err_sycl_restrict)
<< Sema::KernelGlobalVariable;
// ESIMD globals cannot be used in a SYCL context.
Expand Down
25 changes: 6 additions & 19 deletions clang/lib/Sema/SemaSYCL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,6 @@ class Util {
/// specialization id class.
static bool isSyclSpecIdType(QualType Ty);

/// Checks whether given clang type is a full specialization of the SYCL
/// device_global class.
static bool isSyclDeviceGlobalType(QualType Ty);

/// Checks whether given clang type is a full specialization of the SYCL
/// kernel_handler class.
static bool isSyclKernelHandlerType(QualType Ty);
Expand Down Expand Up @@ -4896,7 +4892,8 @@ void SYCLIntegrationFooter::addVarDecl(const VarDecl *VD) {
return;
// Step 1: ensure that this is of the correct type template specialization.
if (!Util::isSyclSpecIdType(VD->getType()) &&
!Util::isSyclDeviceGlobalType(VD->getType())) {
!S.isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
VD->getType())) {
// Handle the case where this could be a deduced type, such as a deduction
// guide. We have to do this here since this function, unlike most of the
// rest of this file, is called during Sema instead of after it. We will
Expand Down Expand Up @@ -5076,7 +5073,8 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {
// Skip if this isn't a SpecIdType or DeviceGlobal. This can happen if it
// was a deduced type.
if (!Util::isSyclSpecIdType(VD->getType()) &&
!Util::isSyclDeviceGlobalType(VD->getType()))
!S.isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
VD->getType()))
continue;

// Skip if we've already visited this.
Expand All @@ -5090,7 +5088,8 @@ bool SYCLIntegrationFooter::emit(raw_ostream &OS) {

Visited.insert(VD);
std::string TopShim = EmitShims(OS, ShimCounter, Policy, VD);
if (Util::isSyclDeviceGlobalType(VD->getType())) {
if (S.isTypeDecoratedWithDeclAttribute<SYCLDeviceGlobalAttr>(
VD->getType())) {
DeviceGlobalsEmitted = true;
DeviceGlobOS << "device_global_map::add(";
DeviceGlobOS << "(void *)&";
Expand Down Expand Up @@ -5189,18 +5188,6 @@ bool Util::isSyclSpecIdType(QualType Ty) {
return matchQualifiedTypeName(Ty, Scopes);
}

bool Util::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>();
}

bool Util::isSyclKernelHandlerType(QualType Ty) {
std::array<DeclContextDesc, 3> Scopes = {
Util::MakeDeclContextDesc(Decl::Kind::Namespace, "cl"),
Expand Down
4 changes: 3 additions & 1 deletion clang/test/CodeGenSYCL/Inputs/sycl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,13 @@ struct no_alias {
};
} // namespace property

// device_global type decorated with attributes
template <typename T>
class [[__sycl_detail__::device_global]] device_global {
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;
Expand Down
Loading