Skip to content

Commit 8ba9c79

Browse files
committed
Add support for sycl_special_class attribute.
Special classes such as accessor, sampler, and stream need additional implementation when they are passed from host to device. This patch is adding a new attribute “sycl_special_class” used to mark SYCL classes/struct that need the additional compiler handling.
1 parent 90f185c commit 8ba9c79

11 files changed

+199
-2
lines changed

clang/include/clang/AST/CXXRecordDeclDefinitionBits.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ FIELD(HasVariantMembers, 1, NO_MERGE)
112112
/// True if there no non-field members declared by the user.
113113
FIELD(HasOnlyCMembers, 1, NO_MERGE)
114114

115+
/// True if there is an '__init' method defined by the user.
116+
FIELD(HasInitMethod, 1, NO_MERGE)
117+
115118
/// True if any field has an in-class initializer, including those
116119
/// within anonymous unions or structs.
117120
FIELD(HasInClassInitializer, 1, NO_MERGE)

clang/include/clang/AST/DeclCXX.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,9 @@ class CXXRecordDecl : public RecordDecl {
11391139
/// \note This does NOT include a check for union-ness.
11401140
bool isEmpty() const { return data().Empty; }
11411141

1142+
void setInitMethod(bool Val) { data().HasInitMethod = Val; }
1143+
bool hasInitMethod() const { return data().HasInitMethod; }
1144+
11421145
bool hasPrivateFields() const {
11431146
return data().HasPrivateFields;
11441147
}

clang/include/clang/Basic/Attr.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,13 @@ def SYCLKernel : InheritableAttr {
11911191
let Documentation = [SYCLKernelDocs];
11921192
}
11931193

1194+
def SYCLSpecialClass: InheritableAttr {
1195+
let Spellings = [Clang<"sycl_special_class">];
1196+
let Subjects = SubjectList<[CXXRecord]>;
1197+
let LangOpts = [SYCL];
1198+
let Documentation = [SYCLSpecialClassDocs];
1199+
}
1200+
11941201
def C11NoReturn : InheritableAttr {
11951202
let Spellings = [Keyword<"_Noreturn">];
11961203
let Subjects = SubjectList<[Function], ErrorDiag>;

clang/include/clang/Basic/AttrDocs.td

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,71 @@ The SYCL kernel in the previous code sample meets these expectations.
409409
}];
410410
}
411411

412+
def SYCLSpecialClassDocs : Documentation {
413+
let Category = DocCatStmt;
414+
let Content = [{
415+
SYCL defines some special classes (accessor, sampler, and stream) which require
416+
specific handling during the generation of the SPIR entry point.
417+
The ``__attribute__((sycl_special_class))`` attribute is used in SYCL
418+
headers to indicate that a class or a struct needs a specific handling when
419+
it is passed from host to device.
420+
Special classes will have a mandatory ``__init`` method and an optional
421+
``__finalize`` method (the ``__finalize`` method is used only with the
422+
``stream`` type). Kernel parameters types are extract from the ``__init`` method
423+
parameters. The kernel function arguments list is derived from the
424+
arguments of the ``__init`` method. The arguments of the ``__init`` method are
425+
copied into the kernel function argument list and the ``__init`` and
426+
``__finalize`` methods are called at the beginning and the end of the kernel,
427+
respectively.
428+
The ``__init`` and ``__finalize`` methods must be defined inside the
429+
special class.
430+
Please note that this is an attribute that is used as an internal
431+
implementation detail and not intended to be used by external users.
432+
433+
The syntax of the attribute is as follows:
434+
435+
.. code-block:: c++
436+
437+
class __attribute__((sycl_special_class)) accessor {};
438+
class [[clang::sycl_special_class]] accessor {};
439+
440+
This is a code example that illustrates the use of the attribute:
441+
442+
.. code-block:: c++
443+
444+
class __attribute__((sycl_special_class)) SpecialType {
445+
int F1;
446+
int F2;
447+
void __init(int f1) {
448+
F1 = f1;
449+
F2 = f1;
450+
}
451+
void __finalize() {}
452+
public:
453+
SpecialType() = default;
454+
int getF2() const { return F2; }
455+
};
456+
457+
int main () {
458+
SpecialType T;
459+
cgh.single_task([=] {
460+
T.getF2();
461+
});
462+
}
463+
464+
This would trigger the following kernel entry point in the AST:
465+
466+
.. code-block:: c++
467+
468+
void __sycl_kernel(int f1) {
469+
SpecialType T;
470+
T.__init(f1);
471+
...
472+
T.__finalize()
473+
}
474+
}];
475+
}
476+
412477
def C11NoReturnDocs : Documentation {
413478
let Category = DocCatFunction;
414479
let Content = [{

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11448,6 +11448,9 @@ def warn_sycl_kernel_num_of_function_params : Warning<
1144811448
def warn_sycl_kernel_return_type : Warning<
1144911449
"function template with 'sycl_kernel' attribute must have a 'void' return type">,
1145011450
InGroup<IgnoredAttributes>;
11451+
def err_sycl_special_type_num_init_method : Error<
11452+
"types with 'sycl_special_class' attribute must have one and only one '__init' "
11453+
"method defined">;
1145111454

1145211455
def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must "
1145311456
"have a bit size of at least %select{2|1}0">;

clang/lib/AST/DeclCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
111111
HasDeclaredCopyAssignmentWithConstParam(false),
112112
IsAnyDestructorNoReturn(false), IsLambda(false),
113113
IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
114-
HasODRHash(false), Definition(D) {}
114+
HasODRHash(false), Definition(D), HasInitMethod(false) {}
115115

116116
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
117117
return Bases.get(Definition->getASTContext().getExternalSource());

clang/lib/Sema/SemaDecl.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9170,6 +9170,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
91709170
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union);
91719171
NewFD->setInvalidDecl();
91729172
}
9173+
if ((Parent->isClass() || Parent->isStruct()) &&
9174+
Parent->hasAttr<SYCLSpecialClassAttr>() &&
9175+
NewFD->getKind() == Decl::Kind::CXXMethod &&
9176+
NewFD->getName() == "__init" && D.isFunctionDefinition()) {
9177+
if (auto *Def = Parent->getDefinition())
9178+
Def->setInitMethod(true);
9179+
}
91739180
}
91749181

91759182
SetNestedNameSpecifier(*this, NewFD, D);
@@ -16729,8 +16736,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
1672916736
RD->completeDefinition();
1673016737
}
1673116738

16732-
if (isa<CXXRecordDecl>(Tag)) {
16739+
if (auto *RD = dyn_cast<CXXRecordDecl>(Tag)) {
1673316740
FieldCollector->FinishClass();
16741+
if (RD->hasAttr<SYCLSpecialClassAttr>()) {
16742+
auto *Def = RD->getDefinition();
16743+
assert(Def && "The record is expected to have a completed definition");
16744+
unsigned NumInitMethods = 0;
16745+
for (auto *Method : Def->methods()) {
16746+
if (!Method->getIdentifier())
16747+
continue;
16748+
if (Method->getName() == "__init")
16749+
NumInitMethods++;
16750+
}
16751+
if (NumInitMethods > 1 || !Def->hasInitMethod())
16752+
Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method);
16753+
}
1673416754
}
1673516755

1673616756
// Exit this scope of this tag's definition.

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8301,6 +8301,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
83018301
case ParsedAttr::AT_SYCLKernel:
83028302
handleSYCLKernelAttr(S, D, AL);
83038303
break;
8304+
case ParsedAttr::AT_SYCLSpecialClass:
8305+
handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
8306+
break;
83048307
case ParsedAttr::AT_Format:
83058308
handleFormatAttr(S, D, AL);
83068309
break;

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
156156
// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
157157
// CHECK-NEXT: ReturnsTwice (SubjectMatchRule_function)
158+
// CHECK-NEXT: SYCLSpecialClass (SubjectMatchRule_record)
158159
// CHECK-NEXT: ScopedLockable (SubjectMatchRule_record)
159160
// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
160161
// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fsycl-is-device -verify %s
2+
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -x c++ %s
3+
4+
#ifndef __SYCL_DEVICE_ONLY__
5+
// expected-warning@+5 {{'sycl_special_class' attribute ignored}}
6+
#else
7+
// expected-no-diagnostics
8+
#endif
9+
10+
class __attribute__((sycl_special_class)) special_class {
11+
void __init(){}
12+
};

0 commit comments

Comments
 (0)