clang 24.0.0git
CIRGenSYCL.cpp
Go to the documentation of this file.
1//===--------- CIRGenSYCL.cpp - Emit CIR for SYCL kernels -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This contains code required for the generation of SYCL kernel code.
10//
11//===----------------------------------------------------------------------===//
12
13#include "CIRGenFunction.h"
14#include "CIRGenModule.h"
15
17#include "clang/AST/Attr.h"
18#include "clang/AST/Decl.h"
20#include "clang/AST/StmtSYCL.h"
21
22#include "llvm/Support/SaveAndRestore.h"
23
24using namespace clang;
25using namespace clang::CIRGen;
26
27mlir::LogicalResult
29 // SYCLKernelCallStmt nodes are only present in the bodies of functions
30 // declared with the sycl_kernel_entry_point attribute. ODR-use of such a
31 // function in code emitted during device compilation should be diagnosed.
32 // During device compilation, the offload kernel entry point is emitted in
33 // place of such a function (see CIRGenModule::emitDeferred), so this
34 // function is only reached during host compilation.
35 assert(!getLangOpts().SYCLIsDevice &&
36 "Attempt to emit a SYCL kernel call statement during device "
37 "compilation");
38
39 // During host compilation, the kernel launch statement is emitted in place
40 // of the original function body.
41 return emitStmt(s.getKernelLaunchStmt(), /*useCurrentScope=*/true);
42}
43
44// Emit the body of a SYCL kernel caller offload entry point. Mirrors the tail
45// of generateCode, but is driven by an OutlinedFunctionDecl and an explicit
46// argument list rather than a FunctionDecl.
48 const OutlinedFunctionDecl *outlinedFnDecl, cir::FuncOp funcOp,
49 cir::FuncType funcType, FunctionArgList &args) {
50 const Stmt *body = outlinedFnDecl->getBody();
51 SourceLocation loc = outlinedFnDecl->getLocation();
52 SourceRange bodyRange = body->getSourceRange();
53
54 // Synthesized entry point: no FunctionDecl, emitted with an empty GlobalDecl.
55 curGD = GlobalDecl();
56
57 SourceLocRAIIObject fnLoc{*this, loc};
58
59 mlir::Location fusedLoc = getLoc(bodyRange);
60 mlir::Block *entryBB = funcOp.addEntryBlock();
61
63 {
64 LexicalScope lexScope(*this, fusedLoc, entryBB);
65 startFunction(GlobalDecl(), getContext().VoidTy, funcOp, funcType, args,
66 loc, bodyRange.getBegin());
67 if (mlir::failed(emitFunctionBody(body)))
68 return;
69 if (mlir::failed(funcOp.verifyBody()))
70 return;
72 }
73
75}
76
77static void setSYCLKernelAttributes(CIRGenFunction &cgf, cir::FuncOp fn) {
78 mlir::MLIRContext *ctx = &cgf.getMLIRContext();
79 // SYCL 2020 device language restrictions require forward progress and
80 // disallow recursion.
81 fn->setAttr(cir::CIRDialect::getNoRecurseAttrName(),
82 mlir::UnitAttr::get(ctx));
84 fn->setAttr(cir::CIRDialect::getMustProgressAttrName(),
85 mlir::UnitAttr::get(ctx));
86}
87
89 assert(getLangOpts().SYCLIsDevice);
90 // Classic CodeGen uses the LLVM module identifier, which is the main input
91 // file name. CIR stores that as the module's symbol name; fall back to the
92 // main file name so the attribute is never empty, matching classic CodeGen.
93 StringRef moduleId =
94 theModule.getSymName().value_or(codeGenOpts.MainFileName);
95 fn->setAttr(cir::CIRDialect::getSYCLModuleIdAttrName(),
96 mlir::StringAttr::get(&getMLIRContext(), moduleId));
97}
98
99void CIRGenModule::emitSYCLKernelCaller(const FunctionDecl *kernelEntryPointFn,
100 ASTContext &ctx) {
101 assert(ctx.getLangOpts().SYCLIsDevice &&
102 "SYCL kernel caller offload entry point functions can only be emitted"
103 " during device compilation");
104
105 const auto *kernelEntryPointAttr =
106 kernelEntryPointFn->getAttr<SYCLKernelEntryPointAttr>();
107 assert(kernelEntryPointAttr && "Missing sycl_kernel_entry_point attribute");
108 assert(!kernelEntryPointAttr->isInvalidAttr() &&
109 "sycl_kernel_entry_point attribute is invalid");
110
111 // Find the SYCLKernelCallStmt.
112 SYCLKernelCallStmt *kernelCallStmt =
113 cast<SYCLKernelCallStmt>(kernelEntryPointFn->getBody());
114
115 // Retrieve the SYCL kernel caller parameters from the OutlinedFunctionDecl.
116 FunctionArgList args;
117 const OutlinedFunctionDecl *outlinedFnDecl =
118 kernelCallStmt->getOutlinedFunctionDecl();
119 args.append(outlinedFnDecl->param_begin(), outlinedFnDecl->param_end());
120
121 // Compute the function info and CIR function type.
122 const CIRGenFunctionInfo &fnInfo =
124 cir::FuncType funcType = getTypes().getFunctionType(fnInfo);
125
126 // Retrieve the generated name for the SYCL kernel caller function.
127 CanQualType kernelNameType =
128 ctx.getCanonicalType(kernelEntryPointAttr->getKernelName());
129 const SYCLKernelInfo &kernelInfo = ctx.getSYCLKernelInfo(kernelNameType);
130
131 // Synthesized from the OutlinedFunctionDecl, not a FunctionDecl, so create
132 // the function directly with a null FunctionDecl (mirrors classic CodeGen's
133 // llvm::Function::Create).
134 cir::FuncOp funcOp = createCIRFunction(
135 getLoc(kernelEntryPointFn->getSourceRange()), kernelInfo.GetKernelName(),
136 funcType, /*funcDecl=*/nullptr);
137 funcOp.setLinkage(cir::GlobalLinkageKind::ExternalLinkage);
138
139 // Emit as a device kernel (e.g. spir_kernel). Classic CodeGen derives this
140 // from CC_DeviceKernel via SetLLVMFunctionAttributes; CIR does not yet route
141 // opFuncCallingConv onto the FuncOp, so set it from the target hook.
142 funcOp.setCallingConv(getTargetCIRGenInfo().getDeviceKernelCallingConv());
143
144 CIRGenFunction cgf(*this, builder);
145
146 // Route through the shared attribute path so generic function attributes
147 // (e.g. convergent) are applied, matching classic CodeGen's
148 // SetLLVMFunctionAttributes. There is no FunctionDecl, so pass an empty
149 // GlobalDecl.
150 setCIRFunctionAttributes(GlobalDecl(), fnInfo, funcOp, /*isThunk=*/false);
151
152 setSYCLKernelAttributes(cgf, funcOp);
153 addSYCLModuleIdAttr(funcOp);
154
156
157 // Emit the SYCL kernel caller function.
158 llvm::SaveAndRestore<CIRGenFunction *> savedCGF(curCGF, &cgf);
159 {
160 mlir::OpBuilder::InsertionGuard guard(builder);
161 cgf.emitSYCLKernelCaller(outlinedFnDecl, funcOp, funcType, args);
162 }
163
164 setDSOLocal(static_cast<mlir::Operation *>(funcOp));
165
166 setNonAliasAttributes(GlobalDecl(), funcOp);
167 // CIR's setter takes a FunctionDecl; nullptr skips OutlinedFunctionDecl-
168 // derived attributes (e.g. inline hints), not yet handled.
170 setCIRFunctionAttributesForDefinition(/*fd=*/nullptr, funcOp);
171}
Defines the clang::ASTContext interface.
static void setSYCLKernelAttributes(CIRGenFunction &cgf, cir::FuncOp fn)
This file declares types used to describe SYCL kernels.
This file defines SYCL AST classes used to represent calls to SYCL kernels.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
const LangOptions & getLangOpts() const
CanQualType VoidTy
const SYCLKernelInfo & getSYCLKernelInfo(QualType T) const
Given a type used as a SYCL kernel name, returns a reference to the metadata generated from the corre...
clang::GlobalDecl curGD
The GlobalDecl for the current function being compiled or the global variable currently being initial...
const clang::LangOptions & getLangOpts() const
mlir::Location getLoc(clang::SourceLocation srcLoc)
Helpers to convert Clang's SourceLocation to a MLIR Location.
llvm::ScopedHashTableScope< const clang::Decl *, mlir::Value > SymTableScopeTy
void finishFunction(SourceLocation endLoc)
mlir::LogicalResult emitFunctionBody(const clang::Stmt *body)
void startFunction(clang::GlobalDecl gd, clang::QualType returnType, cir::FuncOp fn, cir::FuncType funcType, FunctionArgList args, clang::SourceLocation loc, clang::SourceLocation startLoc)
Emit code for the start of a function.
mlir::MLIRContext & getMLIRContext()
static void eraseEmptyAndUnusedBlocks(cir::FuncOp func)
Remove leftover empty and unreachable blocks from an emitted function.
clang::ASTContext & getContext() const
void emitSYCLKernelCaller(const clang::OutlinedFunctionDecl *outlinedFnDecl, cir::FuncOp funcOp, cir::FuncType funcType, FunctionArgList &args)
mlir::LogicalResult emitStmt(const clang::Stmt *s, bool useCurrentScope, llvm::ArrayRef< const Attr * > attrs={})
mlir::LogicalResult emitSYCLKernelCallStmt(const SYCLKernelCallStmt &s)
void addSYCLModuleIdAttr(cir::FuncOp fn)
void setDSOLocal(mlir::Operation *op) const
void setCIRFunctionAttributes(GlobalDecl gd, const CIRGenFunctionInfo &info, cir::FuncOp func, bool isThunk)
Set the CIR function attributes (Sext, zext, etc).
const clang::LangOptions & getLangOpts() const
cir::FuncOp createCIRFunction(mlir::Location loc, llvm::StringRef name, cir::FuncType funcType, const clang::FunctionDecl *funcDecl)
const TargetCIRGenInfo & getTargetCIRGenInfo()
mlir::Location getLoc(clang::SourceLocation cLoc)
Helpers to convert the presumed location of Clang's SourceLocation to an MLIR Location.
mlir::MLIRContext & getMLIRContext()
void emitSYCLKernelCaller(const clang::FunctionDecl *kernelEntryPointFn, clang::ASTContext &ctx)
Emit the SYCL kernel caller offload entry point function generated for a function declared with the s...
void setCIRFunctionAttributesForDefinition(const clang::FunctionDecl *fd, cir::FuncOp f)
Set extra attributes (inline, etc.) for a function.
cir::FuncType getFunctionType(const CIRGenFunctionInfo &info)
Get the CIR function type for.
const CIRGenFunctionInfo & arrangeDeviceKernelCallerDeclaration(clang::QualType resultType, const FunctionArgList &args)
Arrange the function info for a device kernel caller entry point (e.g.
Type for representing both the decl and type of parameters to a function.
Definition CIRGenCall.h:193
T * getAttr() const
Definition DeclBase.h:581
SourceLocation getLocation() const
Definition DeclBase.h:447
Represents a function declaration or definition.
Definition Decl.h:2059
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition Decl.cpp:3271
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:4613
GlobalDecl - represents a global declaration.
Definition GlobalDecl.h:60
Represents a partial function definition.
Definition Decl.h:5017
parameter_const_iterator param_end() const
Definition Decl.h:5065
Stmt * getBody() const override
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition Decl.cpp:5753
parameter_const_iterator param_begin() const
Definition Decl.h:5064
SYCLKernelCallStmt represents the transformation that is applied to the body of a function declared w...
Definition StmtSYCL.h:36
OutlinedFunctionDecl * getOutlinedFunctionDecl()
Definition StmtSYCL.h:66
const std::string & GetKernelName() const
Encodes a location in the source.
A trivial tuple used to represent a source range.
SourceLocation getBegin() const
Stmt - This represents one statement.
Definition Stmt.h:85
SourceLocation getEndLoc() const LLVM_READONLY
Definition Stmt.cpp:367
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
U cast(CodeGen::Address addr)
Definition Address.h:327
static bool opFuncExtraAttrs()
static bool setLLVMFunctionFEnvAttributes()
Represents a scope, including function bodies, compound statements, and the substatements of if/while...