[clang] [clang][SYCL] Decomposition support (PR #196128)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 6 10:33:14 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Mariya Podchishchaeva (Fznamznon)
<details>
<summary>Changes</summary>
WIP
---
Patch is 60.82 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/196128.diff
29 Files Affected:
- (modified) clang/include/clang/AST/ASTNodeTraverser.h (+3-1)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+1)
- (modified) clang/include/clang/AST/StmtSYCL.h (+19-7)
- (modified) clang/include/clang/Basic/Attr.td (+7)
- (modified) clang/include/clang/Sema/ScopeInfo.h (+4)
- (modified) clang/include/clang/Sema/SemaSYCL.h (+6-3)
- (modified) clang/lib/Sema/SemaDecl.cpp (+14-4)
- (modified) clang/lib/Sema/SemaDeclAttr.cpp (+3)
- (modified) clang/lib/Sema/SemaSYCL.cpp (+451-34)
- (modified) clang/lib/Sema/TreeTransform.h (+6-1)
- (modified) clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp (+3)
- (added) clang/test/ASTSYCL/ast-dump-sycl-kernel-decomposition.cpp (+141)
- (modified) clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp (+3)
- (modified) clang/test/ASTSYCL/ast-print-sycl-kernel-call.cpp (+3)
- (modified) clang/test/CodeGenSYCL/function-attrs.cpp (+3)
- (added) clang/test/CodeGenSYCL/kernel-arg-decomposition.cpp (+96)
- (modified) clang/test/CodeGenSYCL/kernel-caller-entry-point.cpp (+3)
- (modified) clang/test/CodeGenSYCL/sycl-kernel-entry-point-exceptions.cpp (+3)
- (modified) clang/test/CodeGenSYCL/unique_stable_name_windows_diff.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-device-odr-use.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-grammar.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-module.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name-pch.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-kernel-name.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-sfinae.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-entry-point-attr-this.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-launch-ms-compat.cpp (+3)
- (modified) clang/test/SemaSYCL/sycl-kernel-launch.cpp (+3)
``````````diff
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 5e9463d54747d..c4bafc2017609 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -858,8 +858,10 @@ class ASTNodeTraverser
void
VisitUnresolvedSYCLKernelCallStmt(const UnresolvedSYCLKernelCallStmt *Node) {
Visit(Node->getOriginalStmt());
- if (Traversal != TK_IgnoreUnlessSpelledInSource)
+ if (Traversal != TK_IgnoreUnlessSpelledInSource) {
Visit(Node->getKernelLaunchIdExpr());
+ Visit(Node->getSpecArgsIdExpr());
+ }
}
void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index b5be0910194bd..fdb828a7cb680 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -3034,6 +3034,7 @@ DEF_TRAVERSE_STMT(UnresolvedSYCLKernelCallStmt, {
if (getDerived().shouldVisitImplicitCode()) {
TRY_TO(TraverseStmt(S->getOriginalStmt()));
TRY_TO(TraverseStmt(S->getKernelLaunchIdExpr()));
+ TRY_TO(TraverseStmt(S->getSpecArgsIdExpr()));
ShouldVisitChildren = false;
}
})
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index 79ac88532e143..cd682f4cea594 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -105,12 +105,19 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
Stmt *OriginalStmt = nullptr;
// KernelLaunchIdExpr stores an UnresolvedLookupExpr or UnresolvedMemberExpr
// corresponding to the SYCL kernel launch function for which a call
- // will be synthesized during template instantiation.
+ // will be synthesized during template instantiation of the host code.
Expr *KernelLaunchIdExpr = nullptr;
-
- UnresolvedSYCLKernelCallStmt(CompoundStmt *CS, Expr *IdExpr)
+ // Similar to KernelLaunchIdExpr HandleSYCLSpecialParamsIdExpr stores an
+ // UnresolvedLookupExpr or UnresolvedMemberExpr corresponding to the fuction
+ // handling of special SYCL kernel parameters for which a call will be
+ // synthesized during template instantiation of the device code.
+ Expr *HandleSYCLSpecialParamsIdExpr = nullptr;
+
+ UnresolvedSYCLKernelCallStmt(CompoundStmt *CS, Expr *IdExpr,
+ Expr *HandleSYCLSpecialParamsIdExpr)
: Stmt(UnresolvedSYCLKernelCallStmtClass), OriginalStmt(CS),
- KernelLaunchIdExpr(IdExpr) {}
+ KernelLaunchIdExpr(IdExpr),
+ HandleSYCLSpecialParamsIdExpr(HandleSYCLSpecialParamsIdExpr) {}
void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
@@ -118,12 +125,13 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
public:
static UnresolvedSYCLKernelCallStmt *Create(const ASTContext &C,
- CompoundStmt *CS, Expr *IdExpr) {
- return new (C) UnresolvedSYCLKernelCallStmt(CS, IdExpr);
+ CompoundStmt *CS, Expr *IdExpr,
+ Expr *SpecArgsExpr) {
+ return new (C) UnresolvedSYCLKernelCallStmt(CS, IdExpr, SpecArgsExpr);
}
static UnresolvedSYCLKernelCallStmt *CreateEmpty(const ASTContext &C) {
- return new (C) UnresolvedSYCLKernelCallStmt(nullptr, nullptr);
+ return new (C) UnresolvedSYCLKernelCallStmt(nullptr, nullptr, nullptr);
}
CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
@@ -133,6 +141,10 @@ class UnresolvedSYCLKernelCallStmt : public Stmt {
Expr *getKernelLaunchIdExpr() { return KernelLaunchIdExpr; }
const Expr *getKernelLaunchIdExpr() const { return KernelLaunchIdExpr; }
+ Expr *getSpecArgsIdExpr() { return HandleSYCLSpecialParamsIdExpr; }
+ const Expr *getSpecArgsIdExpr() const {
+ return HandleSYCLSpecialParamsIdExpr;
+ }
SourceLocation getBeginLoc() const LLVM_READONLY {
return getOriginalStmt()->getBeginLoc();
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 70b5773f95b08..5f991590638f1 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1744,6 +1744,13 @@ def SYCLSpecialClass: InheritableAttr {
let Documentation = [SYCLSpecialClassDocs];
}
+def SYCLSpecialKernelParameter : InheritableAttr {
+ let Spellings = [CXX11<"clang", "sycl_special_kernel_parameter">];
+ let Subjects = SubjectList<[CXXRecord]>;
+ let LangOpts = [SYCLHost, SYCLDevice];
+ let Documentation = [Undocumented];
+}
+
def C11NoReturn : InheritableAttr {
let Spellings = [CustomKeyword<"_Noreturn">];
let Subjects = SubjectList<[Function], ErrorDiag>;
diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h
index f334f58ebd0a7..1e76e3c676385 100644
--- a/clang/include/clang/Sema/ScopeInfo.h
+++ b/clang/include/clang/Sema/ScopeInfo.h
@@ -249,6 +249,10 @@ class FunctionScopeInfo {
/// to a SYCL kernel launch function in a dependent context.
Expr *SYCLKernelLaunchIdExpr = nullptr;
+ /// An unresolved identifier lookup expression for an implicit call
+ /// to a handling function for SYCL kernel special parameters.
+ Expr *HandleSYCLSpecialParamsIdExpr = nullptr;
+
public:
/// Represents a simple identification of a weak object.
///
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index 4980aa44c3012..268f31d8947cb 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -83,19 +83,22 @@ class SemaSYCL : public SemaBase {
/// passed as the 'LaunchIdExpr' argument in a call to either
/// BuildSYCLKernelCallStmt() or BuildUnresolvedSYCLKernelCallStmt() after
/// the function body has been parsed.
- ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KernelName);
+ ExprResult BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD, QualType KernelName,
+ StringRef FuncName);
/// Builds a SYCLKernelCallStmt to wrap 'Body' and to be used as the body of
/// 'FD'. 'LaunchIdExpr' specifies the lookup result returned by a previous
/// call to BuildSYCLKernelLaunchIdExpr().
StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body,
- Expr *LaunchIdExpr);
+ Expr *LaunchIdExpr,
+ Expr *HandleSpecParamsExpr);
/// Builds an UnresolvedSYCLKernelCallStmt to wrap 'Body'. 'LaunchIdExpr'
/// specifies the lookup result returned by a previous call to
/// BuildSYCLKernelLaunchIdExpr().
StmtResult BuildUnresolvedSYCLKernelCallStmt(CompoundStmt *Body,
- Expr *LaunchIdExpr);
+ Expr *LaunchIdExpr,
+ Expr *HandleSpecParamsExpr);
};
} // namespace clang
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index eb5b6d65b4d58..744b120a775a0 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16466,7 +16466,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
if (!SKEPAttr->isInvalidAttr()) {
ExprResult LaunchIdExpr =
- SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName());
+ SYCL().BuildSYCLKernelLaunchIdExpr(FD, SKEPAttr->getKernelName(), "sycl_kernel_launch");
// Do not mark 'FD' as invalid if construction of `LaunchIDExpr` produces
// an invalid result. Name lookup failure for 'sycl_kernel_launch' is
// treated as an error in the definition of 'FD'; treating it as an error
@@ -16475,6 +16475,13 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
// 'LaunchIDExpr' failed, then 'SYCLKernelLaunchIdExpr' will be assigned
// a null pointer value below; that is expected.
getCurFunction()->SYCLKernelLaunchIdExpr = LaunchIdExpr.get();
+ if (!LaunchIdExpr.isInvalid() &&
+ !LaunchIdExpr.get()->getType()->isVoidType()) {
+ ExprResult HSPSPIdExpr = SYCL().BuildSYCLKernelLaunchIdExpr(
+ FD, SKEPAttr->getKernelName(),
+ "sycl_handle_special_kernel_parameters");
+ getCurFunction()->HandleSYCLSpecialParamsIdExpr = HSPSPIdExpr.get();
+ }
}
}
@@ -16690,7 +16697,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
// The function body should already be a SYCLKernelCallStmt in this
// case, but might not be if there were previous errors.
SR = Body;
- } else if (!getCurFunction()->SYCLKernelLaunchIdExpr) {
+ } else if (!getCurFunction()->SYCLKernelLaunchIdExpr ||
+ !getCurFunction()->HandleSYCLSpecialParamsIdExpr) {
// If name lookup for a template named sycl_kernel_launch failed
// earlier, don't try to build a SYCL kernel call statement as that
// would cause additional errors to be issued; just proceed with the
@@ -16698,11 +16706,13 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, bool IsInstantiation,
SR = Body;
} else if (FD->isTemplated()) {
SR = SYCL().BuildUnresolvedSYCLKernelCallStmt(
- cast<CompoundStmt>(Body), getCurFunction()->SYCLKernelLaunchIdExpr);
+ cast<CompoundStmt>(Body), getCurFunction()->SYCLKernelLaunchIdExpr,
+ getCurFunction()->HandleSYCLSpecialParamsIdExpr);
} else {
SR = SYCL().BuildSYCLKernelCallStmt(
FD, cast<CompoundStmt>(Body),
- getCurFunction()->SYCLKernelLaunchIdExpr);
+ getCurFunction()->SYCLKernelLaunchIdExpr,
+ getCurFunction()->HandleSYCLSpecialParamsIdExpr);
}
// If construction of the replacement body fails, just continue with the
// original function body. An early error return here is not valid; the
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 386651fa691e0..03f86ec1bf480 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -7753,6 +7753,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_SYCLSpecialClass:
handleSimpleAttribute<SYCLSpecialClassAttr>(S, D, AL);
break;
+ case ParsedAttr::AT_SYCLSpecialKernelParameter:
+ handleSimpleAttribute<SYCLSpecialKernelParameterAttr>(S, D, AL);
+ break;
case ParsedAttr::AT_Format:
handleFormatAttr(S, D, AL);
break;
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 112a6e4416df2..b3de40cfdd68c 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -425,7 +425,8 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
}
ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
- QualType KNT) {
+ QualType KNT,
+ StringRef FuncName) {
// The current context must be the function definition context to ensure
// that name lookup is performed within the correct scope.
assert(SemaRef.CurContext == FD && "The current declaration context does not "
@@ -440,12 +441,13 @@ ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
ASTContext &Ctx = SemaRef.getASTContext();
IdentifierInfo &SYCLKernelLaunchID =
- Ctx.Idents.get("sycl_kernel_launch", tok::TokenKind::identifier);
+ Ctx.Idents.get(FuncName, tok::TokenKind::identifier);
// Establish a code synthesis context for the implicit name lookup of
// a template named 'sycl_kernel_launch'. In the event of an error, this
// ensures an appropriate diagnostic note is issued to explain why the
// lookup was performed.
+ // FIXME: Extend diagnostics for handle special parameters function
Sema::CodeSynthesisContext CSC;
CSC.Kind = Sema::CodeSynthesisContext::SYCLKernelLaunchLookup;
CSC.Entity = FD;
@@ -492,16 +494,316 @@ ExprResult SemaSYCL::BuildSYCLKernelLaunchIdExpr(FunctionDecl *FD,
return IdExpr;
}
+static bool isSyclSpecialType(QualType Ty) {
+ if (const auto *RT = Ty->getAsRecordDecl())
+ return RT->getMostRecentDecl()->hasAttr<SYCLSpecialKernelParameterAttr>();
+ return false;
+}
+
namespace {
+/// A special visitor to visit subobjects within a type, i.e. fields of a
+/// class or elements of an array. Useful for SYCl because in SYCL kernels are
+/// defined via lambda expressions or named callable objects and kernel
+/// parameters are fields of these. These visitors will be used for diagnosing
+/// invalid kernel arugments as well as for functional transformations.
+class SubobjectVisitor {
+ ASTContext &Ctx;
+
+ // These enable handler execution only when previous Handlers succeed.
+ template <typename... Tn>
+ bool handleField(FieldDecl *FD, QualType FDTy, Tn &&...tn) {
+ bool result = true;
+ (void)std::initializer_list<int>{(result = result && tn(FD, FDTy), 0)...};
+ return result;
+ }
+ template <typename... Tn>
+ bool handleField(const CXXBaseSpecifier &BD, QualType BDTy, Tn &&...tn) {
+ bool result = true;
+ std::initializer_list<int>{(result = result && tn(BD, BDTy), 0)...};
+ return result;
+ }
+
+#define KF_FOR_EACH(FUNC, Item, Qt) \
+ handleField(Item, Qt, ([&](FieldDecl *FD, QualType FDTy) { \
+ return Handlers.FUNC(FD, FDTy); \
+ })...)
+
+ // Parent contains the FieldDecl or CXXBaseSpecifier that was used to enter
+ // the Wrapper structure that we're currently visiting. Owner is the parent
+ // type (which doesn't exist in cases where it is a FieldDecl in the
+ // 'root'), and Wrapper is the current struct being unwrapped.
+ template <typename ParentTy, typename... HandlerTys>
+ void visitComplexRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
+ const CXXRecordDecl *Wrapper, QualType RecordTy,
+ HandlerTys &...Handlers) {
+ (void)std::initializer_list<int>{
+ (Handlers.enterStruct(Owner, Parent, RecordTy), 0)...};
+ visitRecordHelper(Wrapper, Wrapper->bases(), Handlers...);
+ visitRecordHelper(Wrapper, Wrapper->fields(), Handlers...);
+ (void)std::initializer_list<int>{
+ (Handlers.leaveStruct(Owner, Parent, RecordTy), 0)...};
+ }
+
+ template <typename... HandlerTys>
+ void visitArray(const CXXRecordDecl *Owner, FieldDecl *Field,
+ QualType ArrayTy, HandlerTys &...Handlers) {
+ // TODO add support for simple array visiting, i.e. without entering array
+ // elements.
+ visitComplexArray(Owner, Field, ArrayTy, Handlers...);
+ }
+
+ template <typename ParentTy, typename... HandlerTys>
+ void visitRecord(const CXXRecordDecl *Owner, ParentTy &Parent,
+ const CXXRecordDecl *Wrapper, QualType RecordTy,
+ HandlerTys &...Handlers) {
+ // TODO add support for simple record visiting, i.e. without entering record
+ // fields.
+ visitComplexRecord(Owner, Parent, Wrapper, RecordTy, Handlers...);
+ }
+
+ template <typename... HandlerTys>
+ void visitRecordHelper(const CXXRecordDecl *Owner,
+ clang::CXXRecordDecl::base_class_const_range Range,
+ HandlerTys &...Handlers) {
+ for (const auto &Base : Range) {
+ QualType BaseTy = Base.getType();
+ visitRecord(Owner, Base, BaseTy->getAsCXXRecordDecl(), BaseTy,
+ Handlers...);
+ }
+ }
+
+ template <typename... HandlerTys>
+ void visitRecordHelper(const CXXRecordDecl *Owner, RecordDecl::field_range,
+ HandlerTys &...Handlers) {
+ visitRecordFields(Owner, Handlers...);
+ }
+
+ template <typename... HandlerTys>
+ void visitArrayElementImpl(const CXXRecordDecl *Owner, FieldDecl *ArrayField,
+ QualType ElementTy, uint64_t Index,
+ HandlerTys &...Handlers) {
+ visitField(Owner, ArrayField, ElementTy, Handlers...);
+ }
+
+ template <typename... HandlerTys>
+ void visitNthArrayElement(const CXXRecordDecl *Owner, FieldDecl *ArrayField,
+ QualType ElementTy, uint64_t Index,
+ HandlerTys &...Handlers) {
+ visitArrayElementImpl(Owner, ArrayField, ElementTy, Index, Handlers...);
+ }
+
+ template <typename... HandlerTys>
+ void visitComplexArray(const CXXRecordDecl *Owner, FieldDecl *Field,
+ QualType ArrayTy, HandlerTys &...Handlers) {
+ // Array workflow is:
+ // handleArrayType
+ // enterArray
+ // visitField (same as before, note that The FieldDecl is the of array
+ // itself, not the element)
+ // ... repeat per element, opt-out for duplicates.
+ // leaveArray
+
+ if (!KF_FOR_EACH(handleArrayType, Field, ArrayTy))
+ return;
+
+ const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(ArrayTy);
+ assert(CAT && "Should only be called on constant-size array.");
+ QualType ET = CAT->getElementType();
+ uint64_t ElemCount = CAT->getSize().getZExtValue();
+
+ (void)std::initializer_list<int>{
+ (Handlers.enterArray(Field, ArrayTy, ET), 0)...};
+
+ for (uint64_t Index = 0; Index < ElemCount; ++Index)
+ visitNthArrayElement(Owner, Field, ET, Index, Handlers...);
+
+ (void)std::initializer_list<int>{
+ (Handlers.leaveArray(Field, ArrayTy, ET), 0)...};
+ }
+
+ template <typename... HandlerTys>
+ void visitField(const CXXRecordDecl *Owner, FieldDecl *Field,
+ QualType FieldTy, HandlerTys &...Handlers) {
+ if (FieldTy->isStructureOrClassType()) {
+ if (KF_FOR_EACH(handleStructType, Field, FieldTy)) {
+ CXXRecordDecl *RD = FieldTy->getAsCXXRecordDecl();
+ visitRecord(Owner, Field, RD, FieldTy, Handlers...);
+ }
+ } else if (FieldTy->isUnionType())
+ KF_FOR_EACH(handleUnionType, Field, FieldTy);
+ else if (FieldTy->isReferenceType())
+ KF_FOR_EACH(handleReferenceType, Field, FieldTy);
+ else if (FieldTy->isPointerType())
+ KF_FOR_EACH(handlePointerType, Field, FieldTy);
+ else if (FieldTy->isArrayType())
+ visitArray(Owner, Field, FieldTy, Handlers...);
+ else if (FieldTy->isScalarType() || FieldTy->isVectorType())
+ KF_FOR_EACH(handleScalarType, Field, FieldTy);
+ else
+ KF_FOR_EACH(handleOtherType, Field, FieldTy);
+ }
+
+public:
+ SubobjectVisitor(ASTContext &C) : Ctx(C) {}
+
+ template <typename... HandlerTys>
+ void visitRecordBases(const CXXRecordDecl *KernelFunctor,
+ HandlerTys &...Handlers) {
+ visitRecordHelper(KernelFunctor, KernelFunctor->bases(), Handlers...);
+ }
+
+ template <typename... HandlerTys>
+ void visitRecordFields(const CXXRecordDecl *Owner, HandlerTys &...Handlers) {
+ for (const auto Field : Owner->fields())
+ visitField(Owner, Field, Field->getType(), Handlers...);
+ }
+
+#undef KF_FOR_EACH
+};
+
+class SyclKernelFieldHandlerBase {
+public:
+ virtual bool handleStructType(FieldDecl *, QualType) { return true; }
+ virtual bool handleUnionType(FieldDecl *, QualType) { return true; }
+ virtual bool handleReferenceType(FieldDecl *, QualType) { return true; }
+ virtual bool handlePointerType(FieldDecl *, QualType) { return true; }
+ virtual bool handleArrayType(FieldDecl *, QualType) { return true; }
+ virtual bool handleScalarType(FieldDecl *, QualType) { return true; }
+ // Most handlers shouldn't be handling this, just the field checker.
+ virtual bool handleOtherType(FieldDecl *, QualType) { return true; }
+
+ virtual bool enterStruct(const CXXRecordDecl *, FieldDecl *, QualType) {
+ return true;
+ }
+ virtual bool leaveStruct(const CXXRecordDecl *, FieldDecl *, QualType) {
+ return true;
+ }
+ virtual bool enterStruct(const CXXRecordDecl *, const CXXBaseSpecifier &,
+ QualType) {
+ return true;
+ }
+ virtual bool leaveStruct(const CXXRecordDecl *, const CXXBaseSpecifier &,
+ QualType) {
+ return true;
+ }
+ // The following are used for stepping th...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/196128
More information about the cfe-commits
mailing list