1//===--------- CodeGenSYCL.cpp - Code for SYCL kernel generation ----------===//
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 generation of SYCL kernel caller offload
10// entry point functions.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CodeGenFunction.h"
15#include "CodeGenModule.h"
16#include <cassert>
17
18using namespace clang;
19using namespace CodeGen;
20
21void CodeGenFunction::EmitSYCLKernelCallStmt(const SYCLKernelCallStmt &S) {
22 // SYCLKernelCallStmt instances are only injected in the definitions of
23 // functions declared with the sycl_kernel_entry_point attribute. ODR-use of
24 // such a function in code emitted during device compilation should be
25 // diagnosed. Thus, any attempt to emit a SYCLKernelCallStmt during device
26 // compilation indicates a missing diagnostic.
27 assert(!getLangOpts().SYCLIsDevice &&
28 "Attempt to emit a SYCL kernel call statement during device"
29 " compilation");
30 EmitStmt(S: S.getKernelLaunchStmt());
31}
32
33static void SetSYCLKernelAttributes(llvm::Function *Fn, CodeGenFunction &CGF) {
34 // SYCL 2020 device language restrictions require forward progress and
35 // disallow recursion.
36 Fn->setDoesNotRecurse();
37 if (CGF.checkIfFunctionMustProgress())
38 Fn->addFnAttr(Kind: llvm::Attribute::MustProgress);
39}
40
41void CodeGenModule::EmitSYCLKernelCaller(const FunctionDecl *KernelEntryPointFn,
42 ASTContext &Ctx) {
43 assert(Ctx.getLangOpts().SYCLIsDevice &&
44 "SYCL kernel caller offload entry point functions can only be emitted"
45 " during device compilation");
46
47 const auto *KernelEntryPointAttr =
48 KernelEntryPointFn->getAttr<SYCLKernelEntryPointAttr>();
49 assert(KernelEntryPointAttr && "Missing sycl_kernel_entry_point attribute");
50 assert(!KernelEntryPointAttr->isInvalidAttr() &&
51 "sycl_kernel_entry_point attribute is invalid");
52
53 // Find the SYCLKernelCallStmt.
54 SYCLKernelCallStmt *KernelCallStmt =
55 cast<SYCLKernelCallStmt>(Val: KernelEntryPointFn->getBody());
56
57 // Retrieve the SYCL kernel caller parameters from the OutlinedFunctionDecl.
58 FunctionArgList Args;
59 const OutlinedFunctionDecl *OutlinedFnDecl =
60 KernelCallStmt->getOutlinedFunctionDecl();
61 Args.append(in_start: OutlinedFnDecl->param_begin(), in_end: OutlinedFnDecl->param_end());
62
63 // Compute the function info and LLVM function type.
64 const CGFunctionInfo &FnInfo =
65 getTypes().arrangeDeviceKernelCallerDeclaration(resultType: Ctx.VoidTy, args: Args);
66 llvm::FunctionType *FnTy = getTypes().GetFunctionType(Info: FnInfo);
67
68 // Retrieve the generated name for the SYCL kernel caller function.
69 CanQualType KernelNameType =
70 Ctx.getCanonicalType(T: KernelEntryPointAttr->getKernelName());
71 const SYCLKernelInfo &KernelInfo = Ctx.getSYCLKernelInfo(T: KernelNameType);
72 auto *Fn = llvm::Function::Create(Ty: FnTy, Linkage: llvm::Function::ExternalLinkage,
73 N: KernelInfo.GetKernelName(), M: &getModule());
74
75 // Emit the SYCL kernel caller function.
76 CodeGenFunction CGF(*this);
77 SetLLVMFunctionAttributes(GD: GlobalDecl(), Info: FnInfo, F: Fn, IsThunk: false);
78 SetSYCLKernelAttributes(Fn, CGF);
79 CGF.StartFunction(GD: GlobalDecl(), RetTy: Ctx.VoidTy, Fn, FnInfo, Args,
80 Loc: SourceLocation(), StartLoc: SourceLocation());
81 CGF.EmitFunctionBody(Body: OutlinedFnDecl->getBody());
82 setDSOLocal(Fn);
83 SetLLVMFunctionAttributesForDefinition(D: cast<Decl>(Val: OutlinedFnDecl), F: Fn);
84 CGF.FinishFunction();
85}
86