forked from OSchip/llvm-project
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.
This commit is contained in:
parent
90f185c964
commit
8ba9c794fe
|
@ -112,6 +112,9 @@ FIELD(HasVariantMembers, 1, NO_MERGE)
|
|||
/// True if there no non-field members declared by the user.
|
||||
FIELD(HasOnlyCMembers, 1, NO_MERGE)
|
||||
|
||||
/// True if there is an '__init' method defined by the user.
|
||||
FIELD(HasInitMethod, 1, NO_MERGE)
|
||||
|
||||
/// True if any field has an in-class initializer, including those
|
||||
/// within anonymous unions or structs.
|
||||
FIELD(HasInClassInitializer, 1, NO_MERGE)
|
||||
|
|
|
@ -1139,6 +1139,9 @@ public:
|
|||
/// \note This does NOT include a check for union-ness.
|
||||
bool isEmpty() const { return data().Empty; }
|
||||
|
||||
void setInitMethod(bool Val) { data().HasInitMethod = Val; }
|
||||
bool hasInitMethod() const { return data().HasInitMethod; }
|
||||
|
||||
bool hasPrivateFields() const {
|
||||
return data().HasPrivateFields;
|
||||
}
|
||||
|
|
|
@ -1191,6 +1191,13 @@ def SYCLKernel : InheritableAttr {
|
|||
let Documentation = [SYCLKernelDocs];
|
||||
}
|
||||
|
||||
def SYCLSpecialClass: InheritableAttr {
|
||||
let Spellings = [Clang<"sycl_special_class">];
|
||||
let Subjects = SubjectList<[CXXRecord]>;
|
||||
let LangOpts = [SYCL];
|
||||
let Documentation = [SYCLSpecialClassDocs];
|
||||
}
|
||||
|
||||
def C11NoReturn : InheritableAttr {
|
||||
let Spellings = [Keyword<"_Noreturn">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
|
|
|
@ -409,6 +409,71 @@ The SYCL kernel in the previous code sample meets these expectations.
|
|||
}];
|
||||
}
|
||||
|
||||
def SYCLSpecialClassDocs : Documentation {
|
||||
let Category = DocCatStmt;
|
||||
let Content = [{
|
||||
SYCL defines some special classes (accessor, sampler, and stream) which require
|
||||
specific handling during the generation of the SPIR entry point.
|
||||
The ``__attribute__((sycl_special_class))`` attribute is used in SYCL
|
||||
headers to indicate that a class or a struct needs a specific handling when
|
||||
it is passed from host to device.
|
||||
Special classes will have a mandatory ``__init`` method and an optional
|
||||
``__finalize`` method (the ``__finalize`` method is used only with the
|
||||
``stream`` type). Kernel parameters types are extract from the ``__init`` method
|
||||
parameters. The kernel function arguments list is derived from the
|
||||
arguments of the ``__init`` method. The arguments of the ``__init`` method are
|
||||
copied into the kernel function argument list and the ``__init`` and
|
||||
``__finalize`` methods are called at the beginning and the end of the kernel,
|
||||
respectively.
|
||||
The ``__init`` and ``__finalize`` methods must be defined inside the
|
||||
special class.
|
||||
Please note that this is an attribute that is used as an internal
|
||||
implementation detail and not intended to be used by external users.
|
||||
|
||||
The syntax of the attribute is as follows:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
class __attribute__((sycl_special_class)) accessor {};
|
||||
class [[clang::sycl_special_class]] accessor {};
|
||||
|
||||
This is a code example that illustrates the use of the attribute:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
class __attribute__((sycl_special_class)) SpecialType {
|
||||
int F1;
|
||||
int F2;
|
||||
void __init(int f1) {
|
||||
F1 = f1;
|
||||
F2 = f1;
|
||||
}
|
||||
void __finalize() {}
|
||||
public:
|
||||
SpecialType() = default;
|
||||
int getF2() const { return F2; }
|
||||
};
|
||||
|
||||
int main () {
|
||||
SpecialType T;
|
||||
cgh.single_task([=] {
|
||||
T.getF2();
|
||||
});
|
||||
}
|
||||
|
||||
This would trigger the following kernel entry point in the AST:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void __sycl_kernel(int f1) {
|
||||
SpecialType T;
|
||||
T.__init(f1);
|
||||
...
|
||||
T.__finalize()
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
def C11NoReturnDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
|
|
@ -11448,6 +11448,9 @@ def warn_sycl_kernel_num_of_function_params : Warning<
|
|||
def warn_sycl_kernel_return_type : Warning<
|
||||
"function template with 'sycl_kernel' attribute must have a 'void' return type">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def err_sycl_special_type_num_init_method : Error<
|
||||
"types with 'sycl_special_class' attribute must have one and only one '__init' "
|
||||
"method defined">;
|
||||
|
||||
def err_bit_int_bad_size : Error<"%select{signed|unsigned}0 _BitInt must "
|
||||
"have a bit size of at least %select{2|1}0">;
|
||||
|
|
|
@ -111,7 +111,7 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
|||
HasDeclaredCopyAssignmentWithConstParam(false),
|
||||
IsAnyDestructorNoReturn(false), IsLambda(false),
|
||||
IsParsingBaseSpecifiers(false), ComputedVisibleConversions(false),
|
||||
HasODRHash(false), Definition(D) {}
|
||||
HasODRHash(false), Definition(D), HasInitMethod(false) {}
|
||||
|
||||
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
|
||||
return Bases.get(Definition->getASTContext().getExternalSource());
|
||||
|
|
|
@ -9170,6 +9170,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
|||
Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union);
|
||||
NewFD->setInvalidDecl();
|
||||
}
|
||||
if ((Parent->isClass() || Parent->isStruct()) &&
|
||||
Parent->hasAttr<SYCLSpecialClassAttr>() &&
|
||||
NewFD->getKind() == Decl::Kind::CXXMethod &&
|
||||
NewFD->getName() == "__init" && D.isFunctionDefinition()) {
|
||||
if (auto *Def = Parent->getDefinition())
|
||||
Def->setInitMethod(true);
|
||||
}
|
||||
}
|
||||
|
||||
SetNestedNameSpecifier(*this, NewFD, D);
|
||||
|
@ -16729,8 +16736,21 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
|
|||
RD->completeDefinition();
|
||||
}
|
||||
|
||||
if (isa<CXXRecordDecl>(Tag)) {
|
||||
if (auto *RD = dyn_cast<CXXRecordDecl>(Tag)) {
|
||||
FieldCollector->FinishClass();
|
||||
if (RD->hasAttr<SYCLSpecialClassAttr>()) {
|
||||
auto *Def = RD->getDefinition();
|
||||
assert(Def && "The record is expected to have a completed definition");
|
||||
unsigned NumInitMethods = 0;
|
||||
for (auto *Method : Def->methods()) {
|
||||
if (!Method->getIdentifier())
|
||||
continue;
|
||||
if (Method->getName() == "__init")
|
||||
NumInitMethods++;
|
||||
}
|
||||
if (NumInitMethods > 1 || !Def->hasInitMethod())
|
||||
Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method);
|
||||
}
|
||||
}
|
||||
|
||||
// Exit this scope of this tag's definition.
|
||||
|
|
|
@ -8301,6 +8301,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_SYCLKernel:
|
||||
handleSYCLKernelAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_SYCLSpecialClass:
|
||||
handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Format:
|
||||
handleFormatAttr(S, D, AL);
|
||||
break;
|
||||
|
|
|
@ -155,6 +155,7 @@
|
|||
// CHECK-NEXT: ReturnTypestate (SubjectMatchRule_function, SubjectMatchRule_variable_is_parameter)
|
||||
// CHECK-NEXT: ReturnsNonNull (SubjectMatchRule_objc_method, SubjectMatchRule_function)
|
||||
// CHECK-NEXT: ReturnsTwice (SubjectMatchRule_function)
|
||||
// CHECK-NEXT: SYCLSpecialClass (SubjectMatchRule_record)
|
||||
// CHECK-NEXT: ScopedLockable (SubjectMatchRule_record)
|
||||
// CHECK-NEXT: Section (SubjectMatchRule_function, SubjectMatchRule_variable_is_global, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property)
|
||||
// CHECK-NEXT: SetTypestate (SubjectMatchRule_function_is_member)
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fsycl-is-device -verify %s
|
||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -x c++ %s
|
||||
|
||||
#ifndef __SYCL_DEVICE_ONLY__
|
||||
// expected-warning@+5 {{'sycl_special_class' attribute ignored}}
|
||||
#else
|
||||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
class __attribute__((sycl_special_class)) special_class {
|
||||
void __init(){}
|
||||
};
|
|
@ -0,0 +1,80 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fsycl-is-device -verify %s
|
||||
|
||||
// No diagnostics
|
||||
class [[clang::sycl_special_class]] class1 {
|
||||
void __init(){}
|
||||
};
|
||||
class __attribute__((sycl_special_class)) class2 {
|
||||
void __init(){}
|
||||
};
|
||||
|
||||
class class3;
|
||||
class [[clang::sycl_special_class]] class3 {
|
||||
void __init(){}
|
||||
};
|
||||
|
||||
class class4;
|
||||
class __attribute__((sycl_special_class)) class4 {
|
||||
void __init(){}
|
||||
};
|
||||
|
||||
struct [[clang::sycl_special_class]] struct1 {
|
||||
void __init(){}
|
||||
};
|
||||
struct __attribute__((sycl_special_class)) struct2 {
|
||||
void __init(){}
|
||||
};
|
||||
|
||||
class __attribute__((sycl_special_class)) class5;
|
||||
class class5 {
|
||||
void __init(){}
|
||||
};
|
||||
|
||||
// Must have one and only one __init method defined
|
||||
class __attribute__((sycl_special_class)) class6 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
class6() {}
|
||||
};
|
||||
class [[clang::sycl_special_class]] class7 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
void __init();
|
||||
};
|
||||
|
||||
class [[clang::sycl_special_class]] class8 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
void __init();
|
||||
int func() {}
|
||||
void __init(int a){}
|
||||
};
|
||||
|
||||
struct __attribute__((sycl_special_class)) struct3;
|
||||
struct struct3 {}; // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
|
||||
// Only classes
|
||||
[[clang::sycl_special_class]] int var1 = 0; // expected-warning {{'sycl_special_class' attribute only applies to classes}}
|
||||
__attribute__((sycl_special_class)) int var2 = 0; // expected-warning {{'sycl_special_class' attribute only applies to classes}}
|
||||
|
||||
[[clang::sycl_special_class]] void foo1(); // expected-warning {{'sycl_special_class' attribute only applies to classes}}
|
||||
__attribute__((sycl_special_class)) void foo2(); // expected-warning {{'sycl_special_class' attribute only applies to classes}}
|
||||
|
||||
// Attribute takes no arguments
|
||||
class [[clang::sycl_special_class(1)]] class9{}; // expected-error {{'sycl_special_class' attribute takes no arguments}}
|
||||
class __attribute__((sycl_special_class(1))) class10 {}; // expected-error {{'sycl_special_class' attribute takes no arguments}}
|
||||
|
||||
// __init method must be defined inside the CXXRecordDecl.
|
||||
class [[clang::sycl_special_class]] class11 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
void __init();
|
||||
};
|
||||
void class11::__init(){}
|
||||
|
||||
class __attribute__((sycl_special_class)) class12 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
void __init();
|
||||
};
|
||||
void class12::__init(){}
|
||||
|
||||
struct [[clang::sycl_special_class]] struct4 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
void __init();
|
||||
};
|
||||
void struct4::__init(){}
|
||||
|
||||
struct __attribute__((sycl_special_class)) struct5 { // expected-error {{types with 'sycl_special_class' attribute must have one and only one '__init' method defined}}
|
||||
void __init();
|
||||
};
|
||||
void struct5::__init(){}
|
Loading…
Reference in New Issue