From 846e694b8518fb3421790a0c1f893eeed3f83056 Mon Sep 17 00:00:00 2001 From: Mariya Podchishchaeva Date: Fri, 10 Jul 2020 18:22:56 +0300 Subject: [PATCH] [SYCL] Implement sycl_special_class attribute This attribute is used in SYCL headers to mark SYCL classes which need additional compiler handling when passed from host to device. Attribute can be applied to struct/class and can have optional argument which indicates kind of SYCL special class, so it can be used to implement handling of some generic case of SYCL special class as well as implement different handling for each kind of SYCL special class. Usage: ``` class __attribute__((sycl_special_class(accessor))) accessor { ... } ``` --- clang/include/clang/Basic/Attr.td | 14 +++++++++++++ clang/lib/Sema/SemaDeclAttr.cpp | 28 +++++++++++++++++++++++++ clang/lib/Sema/SemaSYCL.cpp | 23 +++++++++++++++++--- clang/test/CodeGenSYCL/Inputs/sycl.hpp | 8 +++---- clang/test/SemaSYCL/Inputs/sycl.hpp | 6 +++--- sycl/include/CL/sycl/accessor.hpp | 14 ++++++------- sycl/include/CL/sycl/detail/defines.hpp | 6 ++++++ sycl/include/CL/sycl/sampler.hpp | 2 +- sycl/include/CL/sycl/stream.hpp | 2 +- 9 files changed, 84 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 5a607dbc2396d..4f13e02ec1f95 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1135,6 +1135,20 @@ def SYCLKernel : InheritableAttr { let Documentation = [SYCLKernelDocs]; } +def SYCLSpecialClass: InheritableAttr { + let Spellings = [Clang<"sycl_special_class">]; + let Subjects = SubjectList<[CXXRecord]>; + let LangOpts = [SYCLIsDevice, SYCLIsHost]; + // TODO: Add doc + let Documentation = [Undocumented]; + let Args = [ + EnumArgument<"SpecialClassKind", "SpecialClassKind", + [ "accessor", "sampler", "stream", "" ], + [ "Accessor", "Sampler", "Stream", "Generic" ], 1> + ]; + let PragmaAttributeSupport = 0; +} + // Marks functions which must not be vectorized via horizontal SIMT widening, // e.g. because the function is already vectorized. Used to mark SYCL // explicit SIMD kernels and functions. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b5170932ae739..5a6e2a6775513 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7219,6 +7219,31 @@ static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute(S, D, AL); } +static void handleSYCLSpecialClassAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (S.LangOpts.SYCLIsHost) + return; + + SYCLSpecialClassAttr::SpecialClassKind Kind; + if (AL.getNumArgs() == 0) + Kind = SYCLSpecialClassAttr::Generic; + else { + // Check the attribute arguments. + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 0 << AANT_ArgumentIdentifier; + return; + } + + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + if (!SYCLSpecialClassAttr::ConvertStrToSpecialClassKind(II->getName(), + Kind)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; + return; + } + } + D->addAttr(::new (S.Context) SYCLSpecialClassAttr(S.Context, AL, Kind)); +} + static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (!cast(D)->hasGlobalStorage()) { S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var) @@ -7600,6 +7625,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_SYCLSimd: handleSimpleAttribute(S, D, AL); break; + case ParsedAttr::AT_SYCLSpecialClass: + handleSYCLSpecialClassAttr(S, D, AL); + break; case ParsedAttr::AT_SYCLDevice: handleSYCLDeviceAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 443ed62c30edd..ae8f3aa091c4c 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -2692,17 +2692,33 @@ SYCLIntegrationHeader::SYCLIntegrationHeader(DiagnosticsEngine &_Diag, // ----------------------------------------------------------------------------- bool Util::isSyclAccessorType(const QualType &Ty) { - return isSyclType(Ty, "accessor", true /*Tmpl*/); + const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl(); + if (!RecTy) + return false; // only classes/structs supported + if (const auto *A = RecTy->getAttr()) + return A->getSpecialClassKind() == SYCLSpecialClassAttr::Accessor; + return false; } bool Util::isSyclSamplerType(const QualType &Ty) { - return isSyclType(Ty, "sampler"); + const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl(); + if (!RecTy) + return false; // only classes/structs supported + if (const auto *A = RecTy->getAttr()) + return A->getSpecialClassKind() == SYCLSpecialClassAttr::Sampler; + return false; } bool Util::isSyclStreamType(const QualType &Ty) { - return isSyclType(Ty, "stream"); + const CXXRecordDecl *RecTy = Ty->getAsCXXRecordDecl(); + if (!RecTy) + return false; // only classes/structs supported + if (const auto *A = RecTy->getAttr()) + return A->getSpecialClassKind() == SYCLSpecialClassAttr::Stream; + return false; } +// TODO: Remove this once structs decomposing is optimized bool Util::isSyclHalfType(const QualType &Ty) { const StringRef &Name = "half"; std::array Scopes = { @@ -2714,6 +2730,7 @@ bool Util::isSyclHalfType(const QualType &Ty) { return matchQualifiedTypeName(Ty, Scopes); } +// TODO: Do we need an attribute for this one as well? bool Util::isSyclSpecConstantType(const QualType &Ty) { const StringRef &Name = "spec_constant"; std::array Scopes = { diff --git a/clang/test/CodeGenSYCL/Inputs/sycl.hpp b/clang/test/CodeGenSYCL/Inputs/sycl.hpp index 3184c58edcbfc..04302bb4ff971 100644 --- a/clang/test/CodeGenSYCL/Inputs/sycl.hpp +++ b/clang/test/CodeGenSYCL/Inputs/sycl.hpp @@ -11,7 +11,7 @@ struct sampler_impl { #endif }; -class sampler { +class __attribute__((sycl_special_class(sampler))) sampler { struct sampler_impl impl; #ifdef __SYCL_DEVICE_ONLY__ void __init(__ocl_sampler_t Sampler) { impl.m_Sampler = Sampler; } @@ -128,7 +128,7 @@ struct _ImplT { template -class accessor { +class __attribute__((sycl_special_class(accessor))) accessor { public: void use(void) const {} @@ -189,7 +189,7 @@ struct _ImageImplT { }; template -class accessor { +class __attribute__((sycl_special_class(accessor))) accessor { public: void use(void) const {} template @@ -310,7 +310,7 @@ class handler { } }; -class stream { +class __attribute__((sycl_special_class(stream))) stream { public: stream(unsigned long BufferSize, unsigned long MaxStatementSize, handler &CGH) {} diff --git a/clang/test/SemaSYCL/Inputs/sycl.hpp b/clang/test/SemaSYCL/Inputs/sycl.hpp index 9e3efc6321096..01329e2e12838 100644 --- a/clang/test/SemaSYCL/Inputs/sycl.hpp +++ b/clang/test/SemaSYCL/Inputs/sycl.hpp @@ -87,7 +87,7 @@ struct DeviceValueType { template -class accessor { +class __attribute__((sycl_special_class(accessor))) accessor { public: void use(void) const {} @@ -146,7 +146,7 @@ struct _ImageImplT { }; template -class accessor { +class __attribute__((sycl_special_class(accessor))) accessor { public: void use(void) const {} template @@ -165,7 +165,7 @@ struct sampler_impl { #endif }; -class sampler { +class __attribute__((sycl_special_class(sampler))) sampler { struct sampler_impl impl; #ifdef __SYCL_DEVICE_ONLY__ void __init(__ocl_sampler_t Sampler) { impl.m_Sampler = Sampler; } diff --git a/sycl/include/CL/sycl/accessor.hpp b/sycl/include/CL/sycl/accessor.hpp index 0b39a2c090c76..b1a6a89f8b90f 100644 --- a/sycl/include/CL/sycl/accessor.hpp +++ b/sycl/include/CL/sycl/accessor.hpp @@ -730,7 +730,7 @@ class __image_array_slice__ { /// \ingroup sycl_api_acc template -class accessor : +class __SYCL_SPECIAL_CLASS(accessor) accessor : #ifndef __SYCL_DEVICE_ONLY__ public detail::AccessorBaseHost, #endif @@ -1350,8 +1350,8 @@ accessor(buffer, handler, Type1, Type2, Type3, /// \ingroup sycl_api_acc template -class accessor : +class __SYCL_SPECIAL_CLASS(accessor) accessor< + DataT, Dimensions, AccessMode, access::target::local, IsPlaceholder> : #ifndef __SYCL_DEVICE_ONLY__ public detail::LocalAccessorBaseHost, #endif @@ -1516,8 +1516,8 @@ class accessor -class accessor +class __SYCL_SPECIAL_CLASS(accessor) accessor< + DataT, Dimensions, AccessMode, access::target::image, IsPlaceholder> : public detail::image_accessor { public: @@ -1580,8 +1580,8 @@ class accessor -class accessor +class __SYCL_SPECIAL_CLASS(accessor) accessor< + DataT, Dimensions, AccessMode, access::target::image_array, IsPlaceholder> : public detail::image_accessor { #ifdef __SYCL_DEVICE_ONLY__ diff --git a/sycl/include/CL/sycl/detail/defines.hpp b/sycl/include/CL/sycl/detail/defines.hpp index c26b2e18d2b9b..e36066ad55fdf 100644 --- a/sycl/include/CL/sycl/detail/defines.hpp +++ b/sycl/include/CL/sycl/detail/defines.hpp @@ -59,3 +59,9 @@ #else #define __SYCL_INLINE_CONSTEXPR static constexpr #endif + +#if __has_attribute(sycl_special_class) +#define __SYCL_SPECIAL_CLASS(kind) __attribute__((sycl_special_class(kind))) +#else +#define __SYCL_SPECIAL_CLASS(kind) +#endif diff --git a/sycl/include/CL/sycl/sampler.hpp b/sycl/include/CL/sycl/sampler.hpp index 5843b0a47bc33..b7ab4ff970296 100644 --- a/sycl/include/CL/sycl/sampler.hpp +++ b/sycl/include/CL/sycl/sampler.hpp @@ -45,7 +45,7 @@ class image_accessor; /// \sa sycl_api_acc /// /// \ingroup sycl_api -class __SYCL_EXPORT sampler { +class __SYCL_EXPORT __SYCL_SPECIAL_CLASS(sampler) sampler { public: sampler(coordinate_normalization_mode normalizationMode, addressing_mode addressingMode, filtering_mode filteringMode); diff --git a/sycl/include/CL/sycl/stream.hpp b/sycl/include/CL/sycl/stream.hpp index 58f038980545d..544cd38cdd88d 100644 --- a/sycl/include/CL/sycl/stream.hpp +++ b/sycl/include/CL/sycl/stream.hpp @@ -94,7 +94,7 @@ inline __width_manipulator__ setw(int Width) { /// vector and SYCL types to the console. /// /// \ingroup sycl_api -class __SYCL_EXPORT stream { +class __SYCL_EXPORT __SYCL_SPECIAL_CLASS(stream) stream { public: stream(size_t BufferSize, size_t MaxStatementSize, handler &CGH);