[clang] [SYCL] AST support for SYCL kernel entry point functions. (PR #122379)
Tom Honermann via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 22 10:02:49 PST 2025
https://github.com/tahonermann updated https://github.com/llvm/llvm-project/pull/122379
>From a6342615862c8ec48459ec95334d812bcb6a6e55 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 8 May 2024 14:31:36 -0700
Subject: [PATCH 1/6] [SYCL] AST support for SYCL kernel entry point functions.
A SYCL kernel entry point function is a non-member function or a static member
function declared with the `sycl_kernel_entry_point` attribute. Such functions
define a pattern for an offload kernel entry point function to be generated to
enable execution of a SYCL kernel on a device. A SYCL library implementation
orchestrates the invocation of these functions with corresponding SYCL kernel
arguments in response to calls to SYCL kernel invocation functions specified
by the SYCL 2020 specification.
The offload kernel entry point function (sometimes referred to as the SYCL
kernel caller function) is generated from the SYCL kernel entry point function
by a transformation of the function parameters followed by a transformation of
the function body to replace references to the original parameters with
references to the transformed ones. Exactly how parameters are transformed will
be explained in a future change that implements non-trivial transformations.
For now, it suffices to state that a given parameter of the SYCL kernel entry
point function may be transformed to multiple parameters of the offload kernel
entry point as needed to satisfy offload kernel argument passing requirements.
Parameters that are decomposed in this way are reconstituted as local variables
in the body of the generated offload kernel entry point function.
For example, given the following SYCL kernel entry point function definition:
template<typename KernelNameType, typename KernelType>
[[clang::sycl_kernel_entry_point(KernelNameType)]]
void sycl_kernel_entry_point(KernelType kernel) {
kernel();
}
and the following call:
struct Kernel {
int dm1;
int dm2;
void operator()() const;
};
Kernel k;
sycl_kernel_entry_point<class kernel_name>(k);
the corresponding offload kernel entry point function that is generated might
look as follows (assuming `Kernel` is a type that requires decomposition):
void offload_kernel_entry_point_for_kernel_name(int dm1, int dm2) {
Kernel kernel{dm1, dm2};
kernel();
}
Other details of the generated offload kernel entry point function, such as
its name and callng convention, are implementation details that need not be
reflected in the AST and may differ across target devices. For that reason,
only the transformation described above is represented in the AST; other
details will be filled in during code generation.
These transformations are represented using new AST nodes introduced with this
change. `OutlinedFunctionDecl` holds a sequence of `ImplicitParamDecl` nodes
and a sequence of statement nodes that correspond to the transformed
parameters and function body. `SYCLKernelCallStmt` wraps the original function
body and associates it with an `OutlinedFunctionDecl` instance. For the example
above, the AST generated for the `sycl_kernel_entry_point<kernel_name>`
specialization would look as follows:
FunctionDecl 'sycl_kernel_entry_point<kernel_name>(Kernel)'
TemplateArgument type 'kernel_name'
TemplateArgument type 'Kernel'
ParmVarDecl kernel 'Kernel'
SYCLKernelCallStmt
CompoundStmt
<original statements>
OutlinedFunctionDecl
ImplicitParamDecl 'dm1' 'int'
ImplicitParamDecl 'dm2' 'int'
CompoundStmt
VarDecl 'kernel' 'Kernel'
<initialization of 'kernel' with 'dm1' and 'dm2'>
<transformed statements with redirected references of 'kernel'>
Any ODR-use of the SYCL kernel entry point function will (with future changes)
suffice for the offload kernel entry point to be emitted. An actual call to
the SYCL kernel entry point function will result in a call to the function.
However, evaluation of a `SYCLKernelCallStmt` statement is a no-op, so such
calls will have no effect other than to trigger emission of the offload kernel
entry point.
---
clang/include/clang/AST/ASTNodeTraverser.h | 16 +-
clang/include/clang/AST/Decl.h | 90 ++++++
clang/include/clang/AST/RecursiveASTVisitor.h | 14 +
clang/include/clang/AST/StmtSYCL.h | 95 ++++++
clang/include/clang/AST/StmtVisitor.h | 1 +
clang/include/clang/Basic/DeclNodes.td | 1 +
clang/include/clang/Basic/StmtNodes.td | 1 +
clang/include/clang/Sema/SemaSYCL.h | 1 +
clang/include/clang/Sema/Template.h | 5 +-
.../include/clang/Serialization/ASTBitCodes.h | 6 +
clang/lib/AST/ASTStructuralEquivalence.cpp | 1 +
clang/lib/AST/Decl.cpp | 25 ++
clang/lib/AST/DeclBase.cpp | 4 +
clang/lib/AST/Stmt.cpp | 1 +
clang/lib/AST/StmtPrinter.cpp | 5 +
clang/lib/AST/StmtProfile.cpp | 4 +
clang/lib/CodeGen/CGDecl.cpp | 1 +
clang/lib/CodeGen/CGStmt.cpp | 18 ++
clang/lib/CodeGen/CodeGenFunction.h | 1 +
clang/lib/Sema/JumpDiagnostics.cpp | 1 +
clang/lib/Sema/SemaDecl.cpp | 10 +-
clang/lib/Sema/SemaExceptionSpec.cpp | 1 +
clang/lib/Sema/SemaSYCL.cpp | 94 ++++++
clang/lib/Sema/TreeTransform.h | 11 +
clang/lib/Serialization/ASTCommon.cpp | 2 +
clang/lib/Serialization/ASTReaderDecl.cpp | 14 +
clang/lib/Serialization/ASTReaderStmt.cpp | 11 +
clang/lib/Serialization/ASTWriterDecl.cpp | 11 +
clang/lib/Serialization/ASTWriterStmt.cpp | 8 +
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
.../ast-dump-sycl-kernel-call-stmt.cpp | 275 ++++++++++++++++++
.../ast-dump-sycl-kernel-entry-point.cpp | 6 +-
clang/tools/libclang/CIndex.cpp | 1 +
clang/tools/libclang/CXCursor.cpp | 4 +
34 files changed, 732 insertions(+), 8 deletions(-)
create mode 100644 clang/include/clang/AST/StmtSYCL.h
create mode 100644 clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index f5652b295de168..3bc0bdff2bdd12 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -158,8 +158,8 @@ class ASTNodeTraverser
ConstStmtVisitor<Derived>::Visit(S);
// Some statements have custom mechanisms for dumping their children.
- if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) ||
- isa<RequiresExpr>(S) || isa<OpenACCWaitConstruct>(S))
+ if (isa<DeclStmt, GenericSelectionExpr, RequiresExpr,
+ OpenACCWaitConstruct, SYCLKernelCallStmt>(S))
return;
if (Traversal == TK_IgnoreUnlessSpelledInSource &&
@@ -585,6 +585,12 @@ class ASTNodeTraverser
void VisitTopLevelStmtDecl(const TopLevelStmtDecl *D) { Visit(D->getStmt()); }
+ void VisitOutlinedFunctionDecl(const OutlinedFunctionDecl *D) {
+ for (const ImplicitParamDecl *Parameter : D->parameters())
+ Visit(Parameter);
+ Visit(D->getBody());
+ }
+
void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); }
void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) {
@@ -815,6 +821,12 @@ class ASTNodeTraverser
Visit(Node->getCapturedDecl());
}
+ void VisitSYCLKernelCallStmt(const SYCLKernelCallStmt *Node) {
+ Visit(Node->getOriginalStmt());
+ if (Traversal != TK_IgnoreUnlessSpelledInSource)
+ Visit(Node->getOutlinedFunctionDecl());
+ }
+
void VisitOMPExecutableDirective(const OMPExecutableDirective *Node) {
for (const auto *C : Node->clauses())
Visit(C);
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 186a3e7fca59db..5a785554d45492 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4688,6 +4688,96 @@ class BlockDecl : public Decl, public DeclContext {
}
};
+/// Represents a partial function definition.
+///
+/// An outlined function declaration contains the parameters and body of
+/// a function independent of other function definition concerns such
+/// as function name, type, and calling convention. Such declarations may
+/// be used to hold a parameterized and transformed sequence of statements
+/// used to generate a target dependent function definition without losing
+/// association with the original statements. See SYCLKernelCallStmt as an
+/// example.
+class OutlinedFunctionDecl final
+ : public Decl,
+ public DeclContext,
+ private llvm::TrailingObjects<OutlinedFunctionDecl, ImplicitParamDecl *> {
+protected:
+ size_t numTrailingObjects(OverloadToken<ImplicitParamDecl>) {
+ return NumParams;
+ }
+
+private:
+ /// The number of parameters to the outlined function.
+ unsigned NumParams;
+
+ /// The body of the outlined function.
+ llvm::PointerIntPair<Stmt *, 1, bool> BodyAndNothrow;
+
+ explicit OutlinedFunctionDecl(DeclContext *DC, unsigned NumParams);
+
+ ImplicitParamDecl *const *getParams() const {
+ return getTrailingObjects<ImplicitParamDecl *>();
+ }
+
+ ImplicitParamDecl **getParams() {
+ return getTrailingObjects<ImplicitParamDecl *>();
+ }
+
+public:
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+ friend TrailingObjects;
+
+ static OutlinedFunctionDecl *Create(ASTContext &C, DeclContext *DC,
+ unsigned NumParams);
+ static OutlinedFunctionDecl *CreateDeserialized(ASTContext &C,
+ GlobalDeclID ID,
+ unsigned NumParams);
+
+ Stmt *getBody() const override;
+ void setBody(Stmt *B);
+
+ bool isNothrow() const;
+ void setNothrow(bool Nothrow = true);
+
+ unsigned getNumParams() const { return NumParams; }
+
+ ImplicitParamDecl *getParam(unsigned i) const {
+ assert(i < NumParams);
+ return getParams()[i];
+ }
+ void setParam(unsigned i, ImplicitParamDecl *P) {
+ assert(i < NumParams);
+ getParams()[i] = P;
+ }
+
+ // ArrayRef interface to parameters.
+ ArrayRef<ImplicitParamDecl *> parameters() const {
+ return {getParams(), getNumParams()};
+ }
+ MutableArrayRef<ImplicitParamDecl *> parameters() {
+ return {getParams(), getNumParams()};
+ }
+
+ using param_iterator = ImplicitParamDecl *const *;
+ using param_range = llvm::iterator_range<param_iterator>;
+
+ /// Retrieve an iterator pointing to the first parameter decl.
+ param_iterator param_begin() const { return getParams(); }
+ /// Retrieve an iterator one past the last parameter decl.
+ param_iterator param_end() const { return getParams() + NumParams; }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == OutlinedFunction; }
+ static DeclContext *castToDeclContext(const OutlinedFunctionDecl *D) {
+ return static_cast<DeclContext *>(const_cast<OutlinedFunctionDecl *>(D));
+ }
+ static OutlinedFunctionDecl *castFromDeclContext(const DeclContext *DC) {
+ return static_cast<OutlinedFunctionDecl *>(const_cast<DeclContext *>(DC));
+ }
+};
+
/// Represents the body of a CapturedStmt, and serves as its DeclContext.
class CapturedDecl final
: public Decl,
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index d500f4eadef757..c4a1d03f1b3d10 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -37,6 +37,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
@@ -1581,6 +1582,11 @@ DEF_TRAVERSE_DECL(BlockDecl, {
ShouldVisitChildren = false;
})
+DEF_TRAVERSE_DECL(OutlinedFunctionDecl, {
+ TRY_TO(TraverseStmt(D->getBody()));
+ ShouldVisitChildren = false;
+})
+
DEF_TRAVERSE_DECL(CapturedDecl, {
TRY_TO(TraverseStmt(D->getBody()));
ShouldVisitChildren = false;
@@ -2904,6 +2910,14 @@ DEF_TRAVERSE_STMT(SEHFinallyStmt, {})
DEF_TRAVERSE_STMT(SEHLeaveStmt, {})
DEF_TRAVERSE_STMT(CapturedStmt, { TRY_TO(TraverseDecl(S->getCapturedDecl())); })
+DEF_TRAVERSE_STMT(SYCLKernelCallStmt, {
+ if (getDerived().shouldVisitImplicitCode()) {
+ TRY_TO(TraverseStmt(S->getOriginalStmt()));
+ TRY_TO(TraverseDecl(S->getOutlinedFunctionDecl()));
+ ShouldVisitChildren = false;
+ }
+})
+
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, {})
DEF_TRAVERSE_STMT(CXXRewrittenBinaryOperator, {
if (!getDerived().shouldVisitImplicitCode()) {
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
new file mode 100644
index 00000000000000..ac356cb0bf3841
--- /dev/null
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -0,0 +1,95 @@
+//===- StmtSYCL.h - Classes for SYCL kernel calls ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file defines SYCL AST classes used to represent calls to SYCL kernels.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_STMTSYCL_H
+#define LLVM_CLANG_AST_STMTSYCL_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+// AST classes for SYCL kernel calls.
+//===----------------------------------------------------------------------===//
+
+/// SYCLKernelCallStmt represents the transformation that is applied to the body
+/// of a function declared with the sycl_kernel_entry_point attribute. The body
+/// of such a function specifies the statements to be executed on a SYCL device
+/// to invoke a SYCL kernel with a particular set of kernel arguments. The
+/// SYCLKernelCallStmt associates an original statement (the compound statement
+/// that is the function body) with an OutlinedFunctionDecl that holds the
+/// kernel parameters and the transformed body. During code generation, the
+/// OutlinedFunctionDecl is used to emit an offload kernel entry point suitable
+/// for invocation from a SYCL library implementation. If executed, the
+/// SYCLKernelCallStmt behaves as a no-op; no code generation is performed for
+/// it.
+class SYCLKernelCallStmt : public Stmt {
+ friend class ASTStmtReader;
+ friend class ASTStmtWriter;
+
+private:
+ Stmt *OriginalStmt = nullptr;
+ OutlinedFunctionDecl *OFDecl = nullptr;
+
+public:
+ /// Construct a SYCL kernel call statement.
+ SYCLKernelCallStmt(Stmt *OS, OutlinedFunctionDecl *OFD)
+ : Stmt(SYCLKernelCallStmtClass), OriginalStmt(OS), OFDecl(OFD) {}
+
+ /// Construct an empty SYCL kernel call statement.
+ SYCLKernelCallStmt(EmptyShell Empty)
+ : Stmt(SYCLKernelCallStmtClass, Empty) {}
+
+ /// Retrieve the model statement.
+ Stmt *getOriginalStmt() { return OriginalStmt; }
+ const Stmt *getOriginalStmt() const { return OriginalStmt; }
+ void setOriginalStmt(Stmt *S) { OriginalStmt = S; }
+
+ /// Retrieve the outlined function declaration.
+ OutlinedFunctionDecl *getOutlinedFunctionDecl() { return OFDecl; }
+ const OutlinedFunctionDecl *getOutlinedFunctionDecl() const { return OFDecl; }
+
+ /// Set the outlined function declaration.
+ void setOutlinedFunctionDecl(OutlinedFunctionDecl *OFD) {
+ OFDecl = OFD;
+ }
+
+ SourceLocation getBeginLoc() const LLVM_READONLY {
+ return getOriginalStmt()->getBeginLoc();
+ }
+
+ SourceLocation getEndLoc() const LLVM_READONLY {
+ return getOriginalStmt()->getEndLoc();
+ }
+
+ SourceRange getSourceRange() const LLVM_READONLY {
+ return getOriginalStmt()->getSourceRange();
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == SYCLKernelCallStmtClass;
+ }
+
+ child_range children() {
+ return child_range(&OriginalStmt, &OriginalStmt + 1);
+ }
+
+ const_child_range children() const {
+ return const_child_range(&OriginalStmt, &OriginalStmt + 1);
+ }
+};
+
+} // end namespace clang
+
+#endif
diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h
index 990aa2df180d43..8b7b728deaff27 100644
--- a/clang/include/clang/AST/StmtVisitor.h
+++ b/clang/include/clang/AST/StmtVisitor.h
@@ -22,6 +22,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td
index 48396e85c5adac..723113dc2486e0 100644
--- a/clang/include/clang/Basic/DeclNodes.td
+++ b/clang/include/clang/Basic/DeclNodes.td
@@ -101,6 +101,7 @@ def Friend : DeclNode<Decl>;
def FriendTemplate : DeclNode<Decl>;
def StaticAssert : DeclNode<Decl>;
def Block : DeclNode<Decl, "blocks">, DeclContext;
+def OutlinedFunction : DeclNode<Decl>, DeclContext;
def Captured : DeclNode<Decl>, DeclContext;
def Import : DeclNode<Decl>;
def OMPThreadPrivate : DeclNode<Decl>;
diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td
index ce2c48bd3c84e9..53fc77bbbcecc1 100644
--- a/clang/include/clang/Basic/StmtNodes.td
+++ b/clang/include/clang/Basic/StmtNodes.td
@@ -24,6 +24,7 @@ def SwitchCase : StmtNode<Stmt, 1>;
def CaseStmt : StmtNode<SwitchCase>;
def DefaultStmt : StmtNode<SwitchCase>;
def CapturedStmt : StmtNode<Stmt>;
+def SYCLKernelCallStmt : StmtNode<Stmt>;
// Statements that might produce a value (for example, as the last non-null
// statement in a GNU statement-expression).
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index 5bb0de40c886c7..b4f607d1287bc7 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -65,6 +65,7 @@ class SemaSYCL : public SemaBase {
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
+ StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body);
};
} // namespace clang
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 9800f75f676aaf..4206bd50b13dd6 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -627,7 +627,10 @@ enum class TemplateSubstitutionKind : char {
#define EMPTY(DERIVED, BASE)
#define LIFETIMEEXTENDEDTEMPORARY(DERIVED, BASE)
- // Decls which use special-case instantiation code.
+// Decls which never appear inside a template.
+#define OUTLINEDFUNCTION(DERIVED, BASE)
+
+// Decls which use special-case instantiation code.
#define BLOCK(DERIVED, BASE)
#define CAPTURED(DERIVED, BASE)
#define IMPLICITPARAM(DERIVED, BASE)
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h
index d568d2fd7aa301..1b56ed2c9776b5 100644
--- a/clang/include/clang/Serialization/ASTBitCodes.h
+++ b/clang/include/clang/Serialization/ASTBitCodes.h
@@ -1316,6 +1316,9 @@ enum DeclCode {
/// A BlockDecl record.
DECL_BLOCK,
+ /// A OutlinedFunctionDecl record.
+ DECL_OUTLINEDFUNCTION,
+
/// A CapturedDecl record.
DECL_CAPTURED,
@@ -1600,6 +1603,9 @@ enum StmtCode {
/// A CapturedStmt record.
STMT_CAPTURED,
+ /// A SYCLKernelCallStmt record.
+ STMT_SYCLKERNELCALL,
+
/// A GCC-style AsmStmt record.
STMT_GCCASM,
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 308551c3061510..eaf0748395268b 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -76,6 +76,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
#include "clang/AST/Type.h"
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f641a72ed26448..e699d409be39bd 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5448,6 +5448,31 @@ BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
return new (C, ID) BlockDecl(nullptr, SourceLocation());
}
+
+OutlinedFunctionDecl::OutlinedFunctionDecl(DeclContext *DC, unsigned NumParams)
+ : Decl(OutlinedFunction, DC, SourceLocation()), DeclContext(OutlinedFunction),
+ NumParams(NumParams), BodyAndNothrow(nullptr, false) {}
+
+OutlinedFunctionDecl *OutlinedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
+ unsigned NumParams) {
+ return new (C, DC, additionalSizeToAlloc<ImplicitParamDecl *>(NumParams))
+ OutlinedFunctionDecl(DC, NumParams);
+}
+
+OutlinedFunctionDecl *OutlinedFunctionDecl::CreateDeserialized(ASTContext &C,
+ GlobalDeclID ID,
+ unsigned NumParams) {
+ return new (C, ID, additionalSizeToAlloc<ImplicitParamDecl *>(NumParams))
+ OutlinedFunctionDecl(nullptr, NumParams);
+}
+
+Stmt *OutlinedFunctionDecl::getBody() const { return BodyAndNothrow.getPointer(); }
+void OutlinedFunctionDecl::setBody(Stmt *B) { BodyAndNothrow.setPointer(B); }
+
+bool OutlinedFunctionDecl::isNothrow() const { return BodyAndNothrow.getInt(); }
+void OutlinedFunctionDecl::setNothrow(bool Nothrow) { BodyAndNothrow.setInt(Nothrow); }
+
+
CapturedDecl::CapturedDecl(DeclContext *DC, unsigned NumParams)
: Decl(Captured, DC, SourceLocation()), DeclContext(Captured),
NumParams(NumParams), ContextParam(0), BodyAndNothrow(nullptr, false) {}
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 2886aebdf52e9b..8506b95f761fe5 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -966,6 +966,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case PragmaDetectMismatch:
case Block:
case Captured:
+ case OutlinedFunction:
case TranslationUnit:
case ExternCContext:
case Decomposition:
@@ -1245,6 +1246,8 @@ template <class T> static Decl *getNonClosureContext(T *D) {
return getNonClosureContext(BD->getParent());
if (auto *CD = dyn_cast<CapturedDecl>(D))
return getNonClosureContext(CD->getParent());
+ if (auto *OFD = dyn_cast<OutlinedFunctionDecl>(D))
+ return getNonClosureContext(OFD->getParent());
return nullptr;
}
@@ -1437,6 +1440,7 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::TopLevelStmt:
case Decl::Block:
case Decl::Captured:
+ case Decl::OutlinedFunction:
case Decl::OMPDeclareReduction:
case Decl::OMPDeclareMapper:
case Decl::RequiresExprBody:
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index d6a351a78c7ba8..685c00d0cb44f8 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/LLVM.h"
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 52bcb5135d3513..b5def6fbe525c3 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
@@ -582,6 +583,10 @@ void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) {
PrintStmt(Node->getCapturedDecl()->getBody());
}
+void StmtPrinter::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *Node) {
+ PrintStmt(Node->getOutlinedFunctionDecl()->getBody());
+}
+
void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) {
Indent() << "@try";
if (auto *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 0f1ebc68a4f762..85b59f714ba845 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -392,6 +392,10 @@ void StmtProfiler::VisitCapturedStmt(const CapturedStmt *S) {
VisitStmt(S);
}
+void StmtProfiler::VisitSYCLKernelCallStmt(const SYCLKernelCallStmt *S) {
+ VisitStmt(S);
+}
+
void StmtProfiler::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) {
VisitStmt(S);
}
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index f85e0b2c404f92..60f67d4640370d 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -97,6 +97,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Friend:
case Decl::FriendTemplate:
case Decl::Block:
+ case Decl::OutlinedFunction:
case Decl::Captured:
case Decl::UsingShadow:
case Decl::ConstructorUsingShadow:
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 10d44e9c90b27e..7c944fe85a352d 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -114,6 +114,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::DefaultStmtClass:
case Stmt::CaseStmtClass:
case Stmt::SEHLeaveStmtClass:
+ case Stmt::SYCLKernelCallStmtClass:
llvm_unreachable("should have emitted these statements as simple");
#define STMT(Type, Base)
@@ -528,6 +529,23 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S,
case Stmt::SEHLeaveStmtClass:
EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S));
break;
+ case Stmt::SYCLKernelCallStmtClass:
+ // SYCL kernel call statements are generated as wrappers around the body
+ // of functions declared with the sycl_kernel_entry_point attribute. Such
+ // functions are used to specify how a SYCL kernel (a function object) is
+ // to be invoked; the SYCL kernel call statement contains a transformed
+ // variation of the function body and is used to generate a SYCL kernel
+ // caller function; a function that serves as the device side entry point
+ // used to execute the SYCL kernel. The sycl_kernel_entry_point attributed
+ // function is invoked by host code in order to trigger emission of the
+ // device side SYCL kernel caller function and to generate metadata needed
+ // by SYCL run-time library implementations; the function is otherwise
+ // intended to have no effect. As such, the function body is not evaluated
+ // as part of the invocation during host compilation (and the function
+ // should not be called or emitted during device compilation); the SYCL
+ // kernel call statement is thus handled as a null statement for the
+ // purpose of code generation.
+ break;
}
return true;
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index ba8ed040477cc9..fab27d4c22ed80 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -28,6 +28,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/Type.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/CapturedStmt.h"
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index d465599450e7ff..2361c567581e3e 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/BitVector.h"
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4b56a4dea05e5c..00f4bae3b75022 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15966,7 +15966,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
CheckCoroutineWrapper(FD);
}
- // Diagnose invalid SYCL kernel entry point function declarations.
+ // Diagnose invalid SYCL kernel entry point function declarations
+ // and build SYCLKernelCallStmts for valid ones.
if (FD && !FD->isInvalidDecl() && FD->hasAttr<SYCLKernelEntryPointAttr>()) {
SYCLKernelEntryPointAttr *SKEPAttr =
FD->getAttr<SYCLKernelEntryPointAttr>();
@@ -15983,6 +15984,13 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
<< /*coroutine*/ 7;
SKEPAttr->setInvalidAttr();
}
+
+ if (Body && !FD->isTemplated() && !SKEPAttr->isInvalidAttr()) {
+ StmtResult SR = SYCL().BuildSYCLKernelCallStmt(FD, Body);
+ if (SR.isInvalid())
+ return nullptr;
+ Body = SR.get();
+ }
}
{
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 254ad05c5ba74a..470d0d753b5580 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1427,6 +1427,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) {
case Stmt::AttributedStmtClass:
case Stmt::BreakStmtClass:
case Stmt::CapturedStmtClass:
+ case Stmt::SYCLKernelCallStmtClass:
case Stmt::CaseStmtClass:
case Stmt::CompoundStmtClass:
case Stmt::ContinueStmtClass:
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index ce53990fdcb18f..7f2ccb36bfad9e 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -8,8 +8,10 @@
// This implements Semantic Analysis for SYCL constructs.
//===----------------------------------------------------------------------===//
+#include "TreeTransform.h"
#include "clang/Sema/SemaSYCL.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/SYCLKernelInfo.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
@@ -362,3 +364,95 @@ void SemaSYCL::CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD) {
}
}
}
+
+namespace {
+
+// The body of a function declared with the [[sycl_kernel_entry_point]]
+// attribute is cloned and transformed to substitute references to the original
+// function parameters with references to replacement variables that stand in
+// for SYCL kernel parameters or local variables that reconstitute a decomposed
+// SYCL kernel argument.
+class OutlinedFunctionDeclBodyInstantiator
+ : public TreeTransform<OutlinedFunctionDeclBodyInstantiator> {
+public:
+ using ParmDeclMap = llvm::DenseMap<ParmVarDecl*, VarDecl*>;
+
+ OutlinedFunctionDeclBodyInstantiator(Sema &S, ParmDeclMap &M)
+ : TreeTransform<OutlinedFunctionDeclBodyInstantiator>(S),
+ SemaRef(S), MapRef(M) {}
+
+ // A new set of AST nodes is always required.
+ bool AlwaysRebuild() {
+ return true;
+ }
+
+ // Transform ParmVarDecl references to the supplied replacement variables.
+ ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) {
+ const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl());
+ if (PVD) {
+ ParmDeclMap::iterator I = MapRef.find(PVD);
+ if (I != MapRef.end()) {
+ VarDecl *VD = I->second;
+ assert(SemaRef.getASTContext().hasSameUnqualifiedType(PVD->getType(),
+ VD->getType()));
+ assert(!VD->getType().isMoreQualifiedThan(PVD->getType(),
+ SemaRef.getASTContext()));
+ VD->setIsUsed();
+ return DeclRefExpr::Create(
+ SemaRef.getASTContext(), DRE->getQualifierLoc(),
+ DRE->getTemplateKeywordLoc(), VD, false, DRE->getNameInfo(),
+ DRE->getType(), DRE->getValueKind());
+ }
+ }
+ return DRE;
+ }
+
+private:
+ Sema &SemaRef;
+ ParmDeclMap &MapRef;
+};
+
+} // unnamed namespace
+
+StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body) {
+ assert(!FD->isInvalidDecl());
+ assert(!FD->isTemplated());
+ assert(FD->hasPrototype());
+
+ const auto *SKEPAttr = FD->getAttr<SYCLKernelEntryPointAttr>();
+ assert(SKEPAttr && "Missing sycl_kernel_entry_point attribute");
+ assert(!SKEPAttr->isInvalidAttr() &&
+ "sycl_kernel_entry_point attribute is invalid");
+
+ // Ensure that the kernel name was previously registered and that the
+ // stored declaration matches.
+ const SYCLKernelInfo &SKI =
+ getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName());
+ assert(declaresSameEntity(SKI.getKernelEntryPointDecl(), FD) &&
+ "SYCL kernel name conflict");
+
+ using ParmDeclMap = OutlinedFunctionDeclBodyInstantiator::ParmDeclMap;
+ ParmDeclMap ParmMap;
+
+ assert(SemaRef.CurContext == FD);
+ OutlinedFunctionDecl *OFD =
+ OutlinedFunctionDecl::Create(getASTContext(), FD, FD->getNumParams());
+ unsigned i = 0;
+ for (ParmVarDecl *PVD : FD->parameters()) {
+ ImplicitParamDecl *IPD =
+ ImplicitParamDecl::Create(getASTContext(), OFD, SourceLocation(),
+ PVD->getIdentifier(), PVD->getType(),
+ ImplicitParamKind::Other);
+ OFD->setParam(i, IPD);
+ ParmMap[PVD] = IPD;
+ ++i;
+ }
+
+ OutlinedFunctionDeclBodyInstantiator OFDBodyInstantiator(SemaRef, ParmMap);
+ Stmt *OFDBody = OFDBodyInstantiator.TransformStmt(Body).get();
+ OFD->setBody(OFDBody);
+ OFD->setNothrow();
+ Stmt *NewBody = new (getASTContext()) SYCLKernelCallStmt(Body, OFD);
+
+ return NewBody;
+}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 7dc88a1ae23b98..0e5440f2f62a7e 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -29,6 +29,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Sema/Designator.h"
@@ -17416,6 +17417,16 @@ TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
return getSema().ActOnCapturedRegionEnd(Body.get());
}
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
+ // SYCLKernelCallStmt nodes are inserted upon completion of a (non-template)
+ // function definition or instantiation of a function template specialization
+ // and will therefore never appear in a dependent context.
+ llvm_unreachable("SYCL kernel call statement cannot appear in dependent "
+ "context");
+}
+
template <typename Derived>
ExprResult TreeTransform<Derived>::TransformHLSLOutArgExpr(HLSLOutArgExpr *E) {
// We can transform the base expression and allow argument resolution to fill
diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp
index ec18e84255ca8e..3a62c4ea5595be 100644
--- a/clang/lib/Serialization/ASTCommon.cpp
+++ b/clang/lib/Serialization/ASTCommon.cpp
@@ -338,6 +338,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) {
case Decl::CXXConversion:
case Decl::ObjCMethod:
case Decl::Block:
+ case Decl::OutlinedFunction:
case Decl::Captured:
// Objective C categories, category implementations, and class
// implementations can only be defined in one place.
@@ -439,6 +440,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::FriendTemplate:
case Decl::StaticAssert:
case Decl::Block:
+ case Decl::OutlinedFunction:
case Decl::Captured:
case Decl::Import:
case Decl::OMPThreadPrivate:
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index de834285fa76b2..180cd1038849af 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -409,6 +409,7 @@ class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *BD);
+ void VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D);
void VisitCapturedDecl(CapturedDecl *CD);
void VisitEmptyDecl(EmptyDecl *D);
void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
@@ -1795,6 +1796,16 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
BD->setCaptures(Reader.getContext(), captures, capturesCXXThis);
}
+void ASTDeclReader::VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D) {
+ // NumParams is deserialized by OutlinedFunctionDecl::CreateDeserialized().
+ VisitDecl(D);
+ D->setNothrow(Record.readInt() != 0);
+ for (unsigned I = 0; I < D->NumParams; ++I) {
+ D->setParam(I, readDeclAs<ImplicitParamDecl>());
+ }
+ D->setBody(cast_or_null<Stmt>(Record.readStmt()));
+}
+
void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) {
VisitDecl(CD);
unsigned ContextParamPos = Record.readInt();
@@ -4132,6 +4143,9 @@ Decl *ASTReader::ReadDeclRecord(GlobalDeclID ID) {
case DECL_TEMPLATE_PARAM_OBJECT:
D = TemplateParamObjectDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_OUTLINEDFUNCTION:
+ D = OutlinedFunctionDecl::CreateDeserialized(Context, ID, Record.readInt());
+ break;
case DECL_CAPTURED:
D = CapturedDecl::CreateDeserialized(Context, ID, Record.readInt());
break;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 4766f34e9f3a82..484a89462dc630 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -33,6 +33,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenMP.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
@@ -528,6 +529,12 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
}
}
+void ASTStmtReader::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
+ VisitStmt(S);
+ S->setOriginalStmt(Record.readSubStmt());
+ S->setOutlinedFunctionDecl(readDeclAs<OutlinedFunctionDecl>());
+}
+
void ASTStmtReader::VisitExpr(Expr *E) {
VisitStmt(E);
CurrentUnpackingBits.emplace(Record.readInt());
@@ -3112,6 +3119,10 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Context, Record[ASTStmtReader::NumStmtFields]);
break;
+ case STMT_SYCLKERNELCALL:
+ S = new (Context) SYCLKernelCallStmt(Empty);
+ break;
+
case EXPR_CONSTANT:
S = ConstantExpr::CreateEmpty(
Context, static_cast<ConstantResultStorageKind>(
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 30b28057f4c10f..170bae5a373194 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -132,6 +132,7 @@ namespace clang {
void VisitFriendTemplateDecl(FriendTemplateDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitBlockDecl(BlockDecl *D);
+ void VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D);
void VisitCapturedDecl(CapturedDecl *D);
void VisitEmptyDecl(EmptyDecl *D);
void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D);
@@ -1377,6 +1378,16 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
Code = serialization::DECL_BLOCK;
}
+void ASTDeclWriter::VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D) {
+ Record.push_back(D->getNumParams());
+ VisitDecl(D);
+ Record.push_back(D->isNothrow() ? 1 : 0);
+ for (unsigned I = 0; I < D->getNumParams(); ++I)
+ Record.AddDeclRef(D->getParam(I));
+ Record.AddStmt(D->getBody());
+ Code = serialization::DECL_OUTLINEDFUNCTION;
+}
+
void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *CD) {
Record.push_back(CD->getNumParams());
VisitDecl(CD);
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index 7eedf7da7d3fc8..651553244812f2 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -609,6 +609,14 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
Code = serialization::STMT_CAPTURED;
}
+void ASTStmtWriter::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
+ VisitStmt(S);
+ Record.AddStmt(S->getOriginalStmt());
+ Record.AddDeclRef(S->getOutlinedFunctionDecl());
+
+ Code = serialization::STMT_SYCLKERNELCALL;
+}
+
void ASTStmtWriter::VisitExpr(Expr *E) {
VisitStmt(E);
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index ff8bdcea9a2201..140c77790496d9 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1822,6 +1822,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPParallelGenericLoopDirectiveClass:
case Stmt::OMPTargetParallelGenericLoopDirectiveClass:
case Stmt::CapturedStmtClass:
+ case Stmt::SYCLKernelCallStmtClass:
case Stmt::OpenACCComputeConstructClass:
case Stmt::OpenACCLoopConstructClass:
case Stmt::OpenACCCombinedConstructClass:
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
new file mode 100644
index 00000000000000..27604e237adbb1
--- /dev/null
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-call-stmt.cpp
@@ -0,0 +1,275 @@
+// Tests without serialization:
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \
+// RUN: -ast-dump %s \
+// RUN: | FileCheck --match-full-lines %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
+// RUN: -ast-dump %s \
+// RUN: | FileCheck --match-full-lines %s
+//
+// Tests with serialization:
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \
+// RUN: -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-device \
+// RUN: -include-pch %t -ast-dump-all /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
+// RUN: | FileCheck --match-full-lines %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
+// RUN: -emit-pch -o %t %s
+// RUN: %clang_cc1 -x c++ -std=c++17 -triple x86_64-unknown-unknown -fsycl-is-host \
+// RUN: -include-pch %t -ast-dump-all /dev/null \
+// RUN: | sed -e "s/ <undeserialized declarations>//" -e "s/ imported//" \
+// RUN: | FileCheck --match-full-lines %s
+
+// These tests validate the AST body produced for functions declared with the
+// sycl_kernel_entry_point attribute.
+
+// CHECK: TranslationUnitDecl {{.*}}
+
+// A unique kernel name type is required for each declared kernel entry point.
+template<int> struct KN;
+
+// A unique invocable type for use with each declared kernel entry point.
+template<int> struct K {
+ template<typename... Ts>
+ void operator()(Ts...) const {}
+};
+
+
+[[clang::sycl_kernel_entry_point(KN<1>)]]
+void skep1() {
+}
+// CHECK: |-FunctionDecl {{.*}} skep1 'void ()'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<1>
+
+template<typename KNT, typename KT>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void skep2(KT k) {
+ k();
+}
+template
+void skep2<KN<2>>(K<2>);
+// CHECK: |-FunctionTemplateDecl {{.*}} skep2
+// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KNT
+// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KT
+// CHECK-NEXT: | |-FunctionDecl {{.*}} skep2 'void (KT)'
+// CHECK-NEXT: | | |-ParmVarDecl {{.*}} k 'KT'
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
+// CHECK-NEXT: | | `-SYCLKernelEntryPointAttr {{.*}} KNT
+
+// CHECK-NEXT: | `-FunctionDecl {{.*}} skep2 'void (K<2>)' explicit_instantiation_definition
+// CHECK-NEXT: | |-TemplateArgument type 'KN<2>'
+// CHECK-NEXT: | | `-RecordType {{.*}} 'KN<2>'
+// CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'KN'
+// CHECK-NEXT: | |-TemplateArgument type 'K<2>'
+// CHECK-NEXT: | | `-RecordType {{.*}} 'K<2>'
+// CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'K'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'K<2>'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<2>' lvalue ParmVar {{.*}} 'k' 'K<2>'
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<2>'
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const K<2>' lvalue <NoOp>
+// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'K<2>' lvalue ImplicitParam {{.*}} 'k' 'K<2>'
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<2>
+
+template<typename KNT, typename KT>
+[[clang::sycl_kernel_entry_point(KNT)]]
+void skep3(KT k) {
+ k();
+}
+template<>
+[[clang::sycl_kernel_entry_point(KN<3>)]]
+void skep3<KN<3>>(K<3> k) {
+ k();
+}
+// CHECK: |-FunctionTemplateDecl {{.*}} skep3
+// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KNT
+// CHECK-NEXT: | |-TemplateTypeParmDecl {{.*}} KT
+// CHECK-NEXT: | |-FunctionDecl {{.*}} skep3 'void (KT)'
+// CHECK-NEXT: | | |-ParmVarDecl {{.*}} k 'KT'
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CallExpr {{.*}} '<dependent type>'
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'KT' lvalue ParmVar {{.*}} 'k' 'KT'
+// CHECK-NEXT: | | `-SYCLKernelEntryPointAttr {{.*}} KNT
+
+// CHECK-NEXT: | `-Function {{.*}} 'skep3' 'void (K<3>)'
+// CHECK-NEXT: |-FunctionDecl {{.*}} skep3 'void (K<3>)' explicit_specialization
+// CHECK-NEXT: | |-TemplateArgument type 'KN<3>'
+// CHECK-NEXT: | | `-RecordType {{.*}} 'KN<3>'
+// CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'KN'
+// CHECK-NEXT: | |-TemplateArgument type 'K<3>'
+// CHECK-NEXT: | | `-RecordType {{.*}} 'K<3>'
+// CHECK-NEXT: | | `-ClassTemplateSpecialization {{.*}} 'K'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'K<3>'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<3>' lvalue ParmVar {{.*}} 'k' 'K<3>'
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<3>'
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const K<3>' lvalue <NoOp>
+// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'K<3>' lvalue ImplicitParam {{.*}} 'k' 'K<3>'
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<3>
+
+[[clang::sycl_kernel_entry_point(KN<4>)]]
+void skep4(K<4> k, int p1, int p2) {
+ k(p1, p2);
+}
+// CHECK: |-FunctionDecl {{.*}} skep4 'void (K<4>, int, int)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'K<4>'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} p1 'int'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} p2 'int'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int) const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'K<4>' lvalue ParmVar {{.*}} 'k' 'K<4>'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p1' 'int'
+// CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'p2' 'int'
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<4>'
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used p1 'int'
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used p2 'int'
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int) const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int) const'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const K<4>' lvalue <NoOp>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<4>' lvalue ImplicitParam {{.*}} 'k' 'K<4>'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'p1' 'int'
+// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'p2' 'int'
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<4>
+
+[[clang::sycl_kernel_entry_point(KN<5>)]]
+void skep5(int unused1, K<5> k, int unused2, int p, int unused3) {
+ static int slv = 0;
+ int lv = 4;
+ k(slv, 1, p, 3, lv, 5, []{ return 6; });
+}
+// CHECK: |-FunctionDecl {{.*}} skep5 'void (int, K<5>, int, int, int)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} unused1 'int'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'K<5>'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} unused2 'int'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} used p 'int'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} unused3 'int'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit unused1 'int'
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'K<5>'
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit unused2 'int'
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used p 'int'
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit unused3 'int'
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | `-VarDecl {{.*}} used slv 'int' static cinit
+// CHECK-NEXT: | | | `-IntegerLiteral {{.*}} 'int' 0
+// CHECK-NEXT: | | |-DeclStmt {{.*}}
+// CHECK-NEXT: | | | `-VarDecl {{.*}} used lv 'int' cinit
+// CHECK-NEXT: | | | `-IntegerLiteral {{.*}} 'int' 4
+// CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)(int, int, int, int, int, int, (lambda {{.*}}) const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void (int, int, int, int, int, int, (lambda {{.*}})) const' lvalue CXXMethod {{.*}} 'operator()' 'void (int, int, int, int, int, int, (lambda {{.*}})) const'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'const K<5>' lvalue <NoOp>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'K<5>' lvalue ImplicitParam {{.*}} 'k' 'K<5>'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'slv' 'int'
+// CHECK-NEXT: | | |-IntegerLiteral {{.*}} 'int' 1
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue ImplicitParam {{.*}} 'p' 'int'
+// CHECK-NEXT: | | |-IntegerLiteral {{.*}} 'int' 3
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'int' <LValueToRValue>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'int' lvalue Var {{.*}} 'lv' 'int'
+// CHECK-NEXT: | | |-IntegerLiteral {{.*}} 'int' 5
+// CHECK-NEXT: | | `-LambdaExpr {{.*}} '(lambda {{.*}})'
+// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<5>
+
+struct S6 {
+ void operator()() const;
+};
+[[clang::sycl_kernel_entry_point(KN<6>)]]
+void skep6(const S6 &k) {
+ k();
+}
+// CHECK: |-FunctionDecl {{.*}} skep6 'void (const S6 &)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'const S6 &'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'const S6' lvalue ParmVar {{.*}} 'k' 'const S6 &'
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'const S6 &'
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'const S6' lvalue ImplicitParam {{.*}} 'k' 'const S6 &'
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<6>
+
+// Parameter types are not required to be complete at the point of a
+// non-defining declaration.
+struct S7;
+[[clang::sycl_kernel_entry_point(KN<7>)]]
+void skep7(S7 k);
+struct S7 {
+ void operator()() const;
+};
+[[clang::sycl_kernel_entry_point(KN<7>)]]
+void skep7(S7 k) {
+ k();
+}
+// CHECK: |-FunctionDecl {{.*}} skep7 'void (S7)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} k 'S7'
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7>
+// CHECK: |-FunctionDecl {{.*}} prev {{.*}} skep7 'void (S7)'
+// CHECK-NEXT: | |-ParmVarDecl {{.*}} used k 'S7'
+// CHECK-NEXT: | |-SYCLKernelCallStmt {{.*}}
+// CHECK-NEXT: | | |-CompoundStmt {{.*}}
+// CHECK-NEXT: | | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | | `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'S7' lvalue ParmVar {{.*}} 'k' 'S7'
+// CHECK-NEXT: | | `-OutlinedFunctionDecl {{.*}}
+// CHECK-NEXT: | | |-ImplicitParamDecl {{.*}} implicit used k 'S7'
+// CHECK-NEXT: | | `-CompoundStmt {{.*}}
+// CHECK-NEXT: | | `-CXXOperatorCallExpr {{.*}} 'void' '()'
+// CHECK-NEXT: | | |-ImplicitCastExpr {{.*}} 'void (*)() const' <FunctionToPointerDecay>
+// CHECK-NEXT: | | | `-DeclRefExpr {{.*}} 'void () const' lvalue CXXMethod {{.*}} 'operator()' 'void () const'
+// CHECK-NEXT: | | `-ImplicitCastExpr {{.*}} 'const S7' lvalue <NoOp>
+// CHECK-NEXT: | | `-DeclRefExpr {{.*}} 'S7' lvalue ImplicitParam {{.*}} 'k' 'S7'
+// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7>
+
+
+void the_end() {}
+// CHECK: `-FunctionDecl {{.*}} the_end 'void ()'
diff --git a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
index 0189cf0402d3a3..b112e9e1db8505 100644
--- a/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
+++ b/clang/test/ASTSYCL/ast-dump-sycl-kernel-entry-point.cpp
@@ -143,16 +143,14 @@ void skep6() {
// CHECK: |-FunctionDecl {{.*}} skep6 'void ()'
// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<6>
// CHECK-NEXT: |-FunctionDecl {{.*}} prev {{.*}} skep6 'void ()'
-// CHECK-NEXT: | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<6>
+// CHECK: | `-SYCLKernelEntryPointAttr {{.*}} KN<6>
// Ensure that matching attributes from the same declaration are ok.
[[clang::sycl_kernel_entry_point(KN<7>), clang::sycl_kernel_entry_point(KN<7>)]]
void skep7() {
}
// CHECK: |-FunctionDecl {{.*}} skep7 'void ()'
-// CHECK-NEXT: | |-CompoundStmt {{.*}}
-// CHECK-NEXT: | |-SYCLKernelEntryPointAttr {{.*}} KN<7>
+// CHECK: | |-SYCLKernelEntryPointAttr {{.*}} KN<7>
// CHECK-NEXT: | `-SYCLKernelEntryPointAttr {{.*}} KN<7>
void the_end() {}
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index e175aab4499fff..42f095fea2db26 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -7202,6 +7202,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::TopLevelStmt:
case Decl::StaticAssert:
case Decl::Block:
+ case Decl::OutlinedFunction:
case Decl::Captured:
case Decl::OMPCapturedExpr:
case Decl::Label: // FIXME: Is this right??
diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp
index ee276d8e4e1481..b9f0b089e41b00 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -375,6 +375,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
K = CXCursor_UnexposedStmt;
break;
+ case Stmt::SYCLKernelCallStmtClass:
+ K = CXCursor_UnexposedStmt;
+ break;
+
case Stmt::IntegerLiteralClass:
K = CXCursor_IntegerLiteral;
break;
>From 51951a7d882521a8cad7fe562a2a080af2e9325d Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Thu, 9 Jan 2025 17:33:24 -0800
Subject: [PATCH 2/6] Squash; address the non-dumb clang-format complaints.
---
clang/include/clang/AST/Decl.h | 5 ++---
clang/include/clang/AST/StmtSYCL.h | 7 ++-----
clang/lib/AST/Decl.cpp | 26 +++++++++++++++-----------
clang/lib/Sema/SemaSYCL.cpp | 23 ++++++++++-------------
clang/lib/Sema/TreeTransform.h | 7 +++----
5 files changed, 32 insertions(+), 36 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 5a785554d45492..e8aac66877dbb0 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4730,9 +4730,8 @@ class OutlinedFunctionDecl final
static OutlinedFunctionDecl *Create(ASTContext &C, DeclContext *DC,
unsigned NumParams);
- static OutlinedFunctionDecl *CreateDeserialized(ASTContext &C,
- GlobalDeclID ID,
- unsigned NumParams);
+ static OutlinedFunctionDecl *
+ CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumParams);
Stmt *getBody() const override;
void setBody(Stmt *B);
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index ac356cb0bf3841..468a580053a431 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -48,8 +48,7 @@ class SYCLKernelCallStmt : public Stmt {
: Stmt(SYCLKernelCallStmtClass), OriginalStmt(OS), OFDecl(OFD) {}
/// Construct an empty SYCL kernel call statement.
- SYCLKernelCallStmt(EmptyShell Empty)
- : Stmt(SYCLKernelCallStmtClass, Empty) {}
+ SYCLKernelCallStmt(EmptyShell Empty) : Stmt(SYCLKernelCallStmtClass, Empty) {}
/// Retrieve the model statement.
Stmt *getOriginalStmt() { return OriginalStmt; }
@@ -61,9 +60,7 @@ class SYCLKernelCallStmt : public Stmt {
const OutlinedFunctionDecl *getOutlinedFunctionDecl() const { return OFDecl; }
/// Set the outlined function declaration.
- void setOutlinedFunctionDecl(OutlinedFunctionDecl *OFD) {
- OFDecl = OFD;
- }
+ void setOutlinedFunctionDecl(OutlinedFunctionDecl *OFD) { OFDecl = OFD; }
SourceLocation getBeginLoc() const LLVM_READONLY {
return getOriginalStmt()->getBeginLoc();
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index e699d409be39bd..2241d0ef6d6e61 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -5448,30 +5448,34 @@ BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
return new (C, ID) BlockDecl(nullptr, SourceLocation());
}
-
OutlinedFunctionDecl::OutlinedFunctionDecl(DeclContext *DC, unsigned NumParams)
- : Decl(OutlinedFunction, DC, SourceLocation()), DeclContext(OutlinedFunction),
- NumParams(NumParams), BodyAndNothrow(nullptr, false) {}
+ : Decl(OutlinedFunction, DC, SourceLocation()),
+ DeclContext(OutlinedFunction), NumParams(NumParams),
+ BodyAndNothrow(nullptr, false) {}
-OutlinedFunctionDecl *OutlinedFunctionDecl::Create(ASTContext &C, DeclContext *DC,
- unsigned NumParams) {
+OutlinedFunctionDecl *OutlinedFunctionDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ unsigned NumParams) {
return new (C, DC, additionalSizeToAlloc<ImplicitParamDecl *>(NumParams))
OutlinedFunctionDecl(DC, NumParams);
}
-OutlinedFunctionDecl *OutlinedFunctionDecl::CreateDeserialized(ASTContext &C,
- GlobalDeclID ID,
- unsigned NumParams) {
+OutlinedFunctionDecl *
+OutlinedFunctionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID,
+ unsigned NumParams) {
return new (C, ID, additionalSizeToAlloc<ImplicitParamDecl *>(NumParams))
OutlinedFunctionDecl(nullptr, NumParams);
}
-Stmt *OutlinedFunctionDecl::getBody() const { return BodyAndNothrow.getPointer(); }
+Stmt *OutlinedFunctionDecl::getBody() const {
+ return BodyAndNothrow.getPointer();
+}
void OutlinedFunctionDecl::setBody(Stmt *B) { BodyAndNothrow.setPointer(B); }
bool OutlinedFunctionDecl::isNothrow() const { return BodyAndNothrow.getInt(); }
-void OutlinedFunctionDecl::setNothrow(bool Nothrow) { BodyAndNothrow.setInt(Nothrow); }
-
+void OutlinedFunctionDecl::setNothrow(bool Nothrow) {
+ BodyAndNothrow.setInt(Nothrow);
+}
CapturedDecl::CapturedDecl(DeclContext *DC, unsigned NumParams)
: Decl(Captured, DC, SourceLocation()), DeclContext(Captured),
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 7f2ccb36bfad9e..f88e81d718fe7e 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -8,11 +8,11 @@
// This implements Semantic Analysis for SYCL constructs.
//===----------------------------------------------------------------------===//
-#include "TreeTransform.h"
#include "clang/Sema/SemaSYCL.h"
+#include "TreeTransform.h"
#include "clang/AST/Mangle.h"
-#include "clang/AST/StmtSYCL.h"
#include "clang/AST/SYCLKernelInfo.h"
+#include "clang/AST/StmtSYCL.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Sema/Attr.h"
@@ -375,16 +375,14 @@ namespace {
class OutlinedFunctionDeclBodyInstantiator
: public TreeTransform<OutlinedFunctionDeclBodyInstantiator> {
public:
- using ParmDeclMap = llvm::DenseMap<ParmVarDecl*, VarDecl*>;
+ using ParmDeclMap = llvm::DenseMap<ParmVarDecl *, VarDecl *>;
OutlinedFunctionDeclBodyInstantiator(Sema &S, ParmDeclMap &M)
- : TreeTransform<OutlinedFunctionDeclBodyInstantiator>(S),
- SemaRef(S), MapRef(M) {}
+ : TreeTransform<OutlinedFunctionDeclBodyInstantiator>(S), SemaRef(S),
+ MapRef(M) {}
// A new set of AST nodes is always required.
- bool AlwaysRebuild() {
- return true;
- }
+ bool AlwaysRebuild() { return true; }
// Transform ParmVarDecl references to the supplied replacement variables.
ExprResult TransformDeclRefExpr(DeclRefExpr *DRE) {
@@ -427,7 +425,7 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body) {
// Ensure that the kernel name was previously registered and that the
// stored declaration matches.
const SYCLKernelInfo &SKI =
- getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName());
+ getASTContext().getSYCLKernelInfo(SKEPAttr->getKernelName());
assert(declaresSameEntity(SKI.getKernelEntryPointDecl(), FD) &&
"SYCL kernel name conflict");
@@ -439,10 +437,9 @@ StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body) {
OutlinedFunctionDecl::Create(getASTContext(), FD, FD->getNumParams());
unsigned i = 0;
for (ParmVarDecl *PVD : FD->parameters()) {
- ImplicitParamDecl *IPD =
- ImplicitParamDecl::Create(getASTContext(), OFD, SourceLocation(),
- PVD->getIdentifier(), PVD->getType(),
- ImplicitParamKind::Other);
+ ImplicitParamDecl *IPD = ImplicitParamDecl::Create(
+ getASTContext(), OFD, SourceLocation(), PVD->getIdentifier(),
+ PVD->getType(), ImplicitParamKind::Other);
OFD->setParam(i, IPD);
ParmMap[PVD] = IPD;
++i;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0e5440f2f62a7e..12680843a434a0 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -17058,10 +17058,9 @@ QualType TreeTransform<Derived>::RebuildDependentSizedMatrixType(
AttributeLoc);
}
-template<typename Derived>
+template <typename Derived>
QualType TreeTransform<Derived>::RebuildFunctionProtoType(
- QualType T,
- MutableArrayRef<QualType> ParamTypes,
+ QualType T, MutableArrayRef<QualType> ParamTypes,
const FunctionProtoType::ExtProtoInfo &EPI) {
return SemaRef.BuildFunctionType(T, ParamTypes,
getDerived().getBaseLocation(),
@@ -17417,7 +17416,7 @@ TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
return getSema().ActOnCapturedRegionEnd(Body.get());
}
-template<typename Derived>
+template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
// SYCLKernelCallStmt nodes are inserted upon completion of a (non-template)
>From cef61770b46cb74fc32e1ddca14dda28ed5ce39a Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Sat, 18 Jan 2025 19:50:29 -0800
Subject: [PATCH 3/6] Addressed the first round of code review comments from
Erich Keane.
---
clang/include/clang/AST/Decl.h | 26 ++++++-----------------
clang/include/clang/AST/StmtSYCL.h | 12 ++++++-----
clang/include/clang/Sema/SemaSYCL.h | 2 +-
clang/lib/Sema/SemaDecl.cpp | 3 ++-
clang/lib/Sema/SemaSYCL.cpp | 3 ++-
clang/lib/Serialization/ASTReaderDecl.cpp | 5 ++---
clang/lib/Serialization/ASTReaderStmt.cpp | 2 +-
clang/lib/Serialization/ASTWriterDecl.cpp | 2 +-
8 files changed, 23 insertions(+), 32 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index e8aac66877dbb0..37d4114982356a 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4701,11 +4701,6 @@ class OutlinedFunctionDecl final
: public Decl,
public DeclContext,
private llvm::TrailingObjects<OutlinedFunctionDecl, ImplicitParamDecl *> {
-protected:
- size_t numTrailingObjects(OverloadToken<ImplicitParamDecl>) {
- return NumParams;
- }
-
private:
/// The number of parameters to the outlined function.
unsigned NumParams;
@@ -4750,21 +4745,14 @@ class OutlinedFunctionDecl final
getParams()[i] = P;
}
- // ArrayRef interface to parameters.
- ArrayRef<ImplicitParamDecl *> parameters() const {
- return {getParams(), getNumParams()};
+ // Range interface to parameters.
+ using parameter_const_iterator = const ImplicitParamDecl * const *;
+ using parameter_const_range = llvm::iterator_range<parameter_const_iterator>;
+ parameter_const_range parameters() const {
+ return {param_begin(), param_end()};
}
- MutableArrayRef<ImplicitParamDecl *> parameters() {
- return {getParams(), getNumParams()};
- }
-
- using param_iterator = ImplicitParamDecl *const *;
- using param_range = llvm::iterator_range<param_iterator>;
-
- /// Retrieve an iterator pointing to the first parameter decl.
- param_iterator param_begin() const { return getParams(); }
- /// Retrieve an iterator one past the last parameter decl.
- param_iterator param_end() const { return getParams() + NumParams; }
+ parameter_const_iterator param_begin() const { return getParams(); }
+ parameter_const_iterator param_end() const { return getParams() + NumParams; }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index 468a580053a431..4da6e219d4224f 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -44,16 +44,18 @@ class SYCLKernelCallStmt : public Stmt {
public:
/// Construct a SYCL kernel call statement.
- SYCLKernelCallStmt(Stmt *OS, OutlinedFunctionDecl *OFD)
- : Stmt(SYCLKernelCallStmtClass), OriginalStmt(OS), OFDecl(OFD) {}
+ SYCLKernelCallStmt(CompoundStmt *CS, OutlinedFunctionDecl *OFD)
+ : Stmt(SYCLKernelCallStmtClass), OriginalStmt(CS), OFDecl(OFD) {}
/// Construct an empty SYCL kernel call statement.
SYCLKernelCallStmt(EmptyShell Empty) : Stmt(SYCLKernelCallStmtClass, Empty) {}
/// Retrieve the model statement.
- Stmt *getOriginalStmt() { return OriginalStmt; }
- const Stmt *getOriginalStmt() const { return OriginalStmt; }
- void setOriginalStmt(Stmt *S) { OriginalStmt = S; }
+ CompoundStmt *getOriginalStmt() { return cast<CompoundStmt>(OriginalStmt); }
+ const CompoundStmt *getOriginalStmt() const {
+ return cast<CompoundStmt>(OriginalStmt);
+ }
+ void setOriginalStmt(CompoundStmt *CS) { OriginalStmt = CS; }
/// Retrieve the outlined function declaration.
OutlinedFunctionDecl *getOutlinedFunctionDecl() { return OFDecl; }
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
index b4f607d1287bc7..b47b2f155ef93b 100644
--- a/clang/include/clang/Sema/SemaSYCL.h
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -65,7 +65,7 @@ class SemaSYCL : public SemaBase {
void handleKernelEntryPointAttr(Decl *D, const ParsedAttr &AL);
void CheckSYCLEntryPointFunctionDecl(FunctionDecl *FD);
- StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body);
+ StmtResult BuildSYCLKernelCallStmt(FunctionDecl *FD, CompoundStmt *Body);
};
} // namespace clang
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 00f4bae3b75022..567cf627a9b0d1 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15986,7 +15986,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
if (Body && !FD->isTemplated() && !SKEPAttr->isInvalidAttr()) {
- StmtResult SR = SYCL().BuildSYCLKernelCallStmt(FD, Body);
+ StmtResult SR = SYCL().BuildSYCLKernelCallStmt(FD,
+ cast<CompoundStmt>(Body));
if (SR.isInvalid())
return nullptr;
Body = SR.get();
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index f88e81d718fe7e..5efbd66c66f8d4 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -412,7 +412,8 @@ class OutlinedFunctionDeclBodyInstantiator
} // unnamed namespace
-StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD, Stmt *Body) {
+StmtResult SemaSYCL::BuildSYCLKernelCallStmt(FunctionDecl *FD,
+ CompoundStmt *Body) {
assert(!FD->isInvalidDecl());
assert(!FD->isTemplated());
assert(FD->hasPrototype());
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 180cd1038849af..bf33222d3c96e7 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -1799,10 +1799,9 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
void ASTDeclReader::VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D) {
// NumParams is deserialized by OutlinedFunctionDecl::CreateDeserialized().
VisitDecl(D);
- D->setNothrow(Record.readInt() != 0);
- for (unsigned I = 0; I < D->NumParams; ++I) {
+ for (unsigned I = 0; I < D->NumParams; ++I)
D->setParam(I, readDeclAs<ImplicitParamDecl>());
- }
+ D->setNothrow(Record.readInt() != 0);
D->setBody(cast_or_null<Stmt>(Record.readStmt()));
}
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 484a89462dc630..990235a310d902 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -531,7 +531,7 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
void ASTStmtReader::VisitSYCLKernelCallStmt(SYCLKernelCallStmt *S) {
VisitStmt(S);
- S->setOriginalStmt(Record.readSubStmt());
+ S->setOriginalStmt(cast<CompoundStmt>(Record.readSubStmt()));
S->setOutlinedFunctionDecl(readDeclAs<OutlinedFunctionDecl>());
}
diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index 170bae5a373194..54570dedb0b227 100644
--- a/clang/lib/Serialization/ASTWriterDecl.cpp
+++ b/clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1381,9 +1381,9 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
void ASTDeclWriter::VisitOutlinedFunctionDecl(OutlinedFunctionDecl *D) {
Record.push_back(D->getNumParams());
VisitDecl(D);
- Record.push_back(D->isNothrow() ? 1 : 0);
for (unsigned I = 0; I < D->getNumParams(); ++I)
Record.AddDeclRef(D->getParam(I));
+ Record.push_back(D->isNothrow() ? 1 : 0);
Record.AddStmt(D->getBody());
Code = serialization::DECL_OUTLINEDFUNCTION;
}
>From 7077a87a9ae5f506374ec429d7d1777f3432054e Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Sat, 18 Jan 2025 19:53:35 -0800
Subject: [PATCH 4/6] Disallow applying the sycl_kernel_entry_point attribute
to functions with a function-try-block.
The SYCL 2020 specification prohibits the use of C++ exceptions in device
functions. Even if exceptions were not prohibited, it is unclear what the
semantics would be for an exception that escapes the SYCL kernel entry point
function; the boundary between host and device code could be an implicit
noexcept boundary that results in program termination if violated, or the
exception could perhaps be propagated to host code via the SYCL library.
The semantics of function-try-blocks is that an exception raised in the
function body that escapes to a function-try-block handler is implicitly
rethrown. Pending support for C++ exceptions in device code and clear
semantics for handling them at the host-device boundary, this change makes
use of the sycl_kernel_entry_point attribute with a function defined with
a function-try-block an error.
---
clang/include/clang/Basic/AttrDocs.td | 1 +
clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 ++-
clang/lib/Sema/SemaDecl.cpp | 4 ++++
.../sycl-kernel-entry-point-attr-appertainment.cpp | 9 +++++++++
4 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 56a817892bbbaa..a8b588169725a2 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -487,6 +487,7 @@ following requirements.
* Is not a C variadic function.
* Is not a coroutine.
* Is not defined as deleted or as defaulted.
+* Is not defined with a function try block.
* Is not declared with the ``constexpr`` or ``consteval`` specifiers.
* Is not declared with the ``[[noreturn]]`` attribute.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 0175c20daf241e..36b693c6a304e7 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12457,7 +12457,8 @@ def err_sycl_entry_point_invalid : Error<
"'sycl_kernel_entry_point' attribute cannot be applied to a"
" %select{non-static member function|variadic function|deleted function|"
"defaulted function|constexpr function|consteval function|"
- "function declared with the 'noreturn' attribute|coroutine}0">;
+ "function declared with the 'noreturn' attribute|coroutine|"
+ "function defined with a function try block}0">;
def err_sycl_entry_point_invalid_redeclaration : Error<
"'sycl_kernel_entry_point' kernel name argument does not match prior"
" declaration%diff{: $ vs $|}0,1">;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 567cf627a9b0d1..b273ef99672a80 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15983,6 +15983,10 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
<< /*coroutine*/ 7;
SKEPAttr->setInvalidAttr();
+ } else if (Body && isa<CXXTryStmt>(Body)) {
+ Diag(SKEPAttr->getLocation(), diag::err_sycl_entry_point_invalid)
+ << /*function defined with a function try block*/ 8;
+ SKEPAttr->setInvalidAttr();
}
if (Body && !FD->isTemplated() && !SKEPAttr->isInvalidAttr()) {
diff --git a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
index a87af7ca298ac3..d06b40c5bf02d2 100644
--- a/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
+++ b/clang/test/SemaSYCL/sycl-kernel-entry-point-attr-appertainment.cpp
@@ -350,3 +350,12 @@ auto bad36 = [] [[clang::sycl_kernel_entry_point(BADKN<36>)]] static {};
// expected-error at +1 {{'sycl_kernel_entry_point' attribute cannot be applied to a coroutine}}
auto bad37 = [] [[clang::sycl_kernel_entry_point(BADKN<37>)]] static -> void { co_return; };
#endif
+
+// expected-error at +1 {{'sycl_kernel_entry_point' attribute cannot be applied to a function defined with a function try block}}
+[[clang::sycl_kernel_entry_point(BADKN<38>)]]
+void bad38() try {} catch(...) {}
+
+// expected-error at +2 {{'sycl_kernel_entry_point' attribute cannot be applied to a function defined with a function try block}}
+template<typename>
+[[clang::sycl_kernel_entry_point(BADKN<39>)]]
+void bad39() try {} catch(...) {}
>From dc93ffadb8e5f230be6a5800c0887d295d5dff85 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Tue, 21 Jan 2025 22:03:54 -0800
Subject: [PATCH 5/6] Addressed the second round of code review comments from
Erich Keane.
---
clang/include/clang/AST/StmtSYCL.h | 2 +-
clang/lib/Sema/JumpDiagnostics.cpp | 1 -
2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/include/clang/AST/StmtSYCL.h b/clang/include/clang/AST/StmtSYCL.h
index 4da6e219d4224f..28ace12d7916b4 100644
--- a/clang/include/clang/AST/StmtSYCL.h
+++ b/clang/include/clang/AST/StmtSYCL.h
@@ -91,4 +91,4 @@ class SYCLKernelCallStmt : public Stmt {
} // end namespace clang
-#endif
+#endif // LLVM_CLANG_AST_STMTSYCL_H
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp
index 2361c567581e3e..d465599450e7ff 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -18,7 +18,6 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
-#include "clang/AST/StmtSYCL.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/BitVector.h"
>From 48b62dcd5acc8873a57886d98c6d2ce724dfd218 Mon Sep 17 00:00:00 2001
From: Tom Honermann <tom.honermann at intel.com>
Date: Wed, 22 Jan 2025 10:01:31 -0800
Subject: [PATCH 6/6] clang-format is a harsh mistress.
---
clang/include/clang/AST/Decl.h | 2 +-
clang/lib/Sema/SemaDecl.cpp | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 37d4114982356a..d01681483a9189 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -4746,7 +4746,7 @@ class OutlinedFunctionDecl final
}
// Range interface to parameters.
- using parameter_const_iterator = const ImplicitParamDecl * const *;
+ using parameter_const_iterator = const ImplicitParamDecl *const *;
using parameter_const_range = llvm::iterator_range<parameter_const_iterator>;
parameter_const_range parameters() const {
return {param_begin(), param_end()};
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b273ef99672a80..ad49eac66e98e5 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15990,8 +15990,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
}
if (Body && !FD->isTemplated() && !SKEPAttr->isInvalidAttr()) {
- StmtResult SR = SYCL().BuildSYCLKernelCallStmt(FD,
- cast<CompoundStmt>(Body));
+ StmtResult SR =
+ SYCL().BuildSYCLKernelCallStmt(FD, cast<CompoundStmt>(Body));
if (SR.isInvalid())
return nullptr;
Body = SR.get();
More information about the cfe-commits
mailing list