1//===----- CGCUDARuntime.cpp - Interface to CUDA Runtimes -----------------===//
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 provides an abstract class for CUDA code generation. Concrete
10// subclasses of this implement code generation for specific CUDA
11// runtime libraries.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CGCUDARuntime.h"
16#include "CGCall.h"
17#include "CodeGenFunction.h"
18#include "clang/AST/ExprCXX.h"
19
20using namespace clang;
21using namespace CodeGen;
22
23CGCUDARuntime::~CGCUDARuntime() {}
24
25static llvm::Value *emitGetParamBuf(CodeGenFunction &CGF,
26 const CUDAKernelCallExpr *E) {
27 auto *GetParamBuf = CGF.getContext().getcudaGetParameterBufferDecl();
28 const FunctionProtoType *GetParamBufProto =
29 GetParamBuf->getType()->getAs<FunctionProtoType>();
30
31 DeclRefExpr *DRE = DeclRefExpr::Create(
32 Context: CGF.getContext(), QualifierLoc: {}, TemplateKWLoc: {}, D: GetParamBuf,
33 /*RefersToEnclosingVariableOrCapture=*/false, NameInfo: GetParamBuf->getNameInfo(),
34 T: GetParamBuf->getType(), VK: VK_PRValue);
35 auto *ImpCast = ImplicitCastExpr::Create(
36 Context: CGF.getContext(), T: CGF.getContext().getPointerType(T: GetParamBuf->getType()),
37 Kind: CK_FunctionToPointerDecay, Operand: DRE, BasePath: nullptr, Cat: VK_PRValue, FPO: FPOptionsOverride());
38
39 CGCallee Callee = CGF.EmitCallee(E: ImpCast);
40 CallArgList Args;
41 // Use 64B alignment.
42 Args.add(rvalue: RValue::get(V: CGF.CGM.getSize(numChars: CharUnits::fromQuantity(Quantity: 64))),
43 type: CGF.getContext().getSizeType());
44 // Calculate parameter sizes.
45 const PointerType *PT = E->getCallee()->getType()->getAs<PointerType>();
46 const FunctionProtoType *FTP =
47 PT->getPointeeType()->getAs<FunctionProtoType>();
48 CharUnits Offset = CharUnits::Zero();
49 for (auto ArgTy : FTP->getParamTypes()) {
50 auto TInfo = CGF.CGM.getContext().getTypeInfoInChars(T: ArgTy);
51 Offset = Offset.alignTo(Align: TInfo.Align) + TInfo.Width;
52 }
53 Args.add(rvalue: RValue::get(V: CGF.CGM.getSize(numChars: Offset)),
54 type: CGF.getContext().getSizeType());
55 const CGFunctionInfo &CallInfo = CGF.CGM.getTypes().arrangeFreeFunctionCall(
56 Args, Ty: GetParamBufProto, /*ChainCall=*/false,
57 ABIInfoFD: CGF.getCurrentFunctionDecl());
58 auto Ret = CGF.EmitCall(CallInfo, Callee, /*ReturnValue=*/{}, Args);
59
60 return Ret.getScalarVal();
61}
62
63RValue CGCUDARuntime::EmitCUDADeviceKernelCallExpr(
64 CodeGenFunction &CGF, const CUDAKernelCallExpr *E,
65 ReturnValueSlot ReturnValue, llvm::CallBase **CallOrInvoke) {
66 assert(CGM.getContext().getcudaLaunchDeviceDecl() ==
67 E->getConfig()->getDirectCallee());
68
69 llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock(name: "dkcall.configok");
70 llvm::BasicBlock *ContBlock = CGF.createBasicBlock(name: "dkcall.end");
71
72 llvm::Value *Config = emitGetParamBuf(CGF, E);
73 CGF.Builder.CreateCondBr(
74 Cond: CGF.Builder.CreateICmpNE(LHS: Config,
75 RHS: llvm::Constant::getNullValue(Ty: Config->getType())),
76 True: ConfigOKBlock, False: ContBlock);
77
78 CodeGenFunction::ConditionalEvaluation eval(CGF);
79
80 eval.begin(CGF);
81 CGF.EmitBlock(BB: ConfigOKBlock);
82
83 QualType KernelCalleeFuncTy =
84 E->getCallee()->getType()->getAs<PointerType>()->getPointeeType();
85 CGCallee KernelCallee = CGF.EmitCallee(E: E->getCallee());
86 // Emit kernel arguments.
87 CallArgList KernelCallArgs;
88 CGF.EmitCallArgs(Args&: KernelCallArgs,
89 Prototype: KernelCalleeFuncTy->getAs<FunctionProtoType>(),
90 ArgRange: E->arguments(), AC: E->getDirectCallee());
91 // Copy emitted kernel arguments into that parameter buffer.
92 RawAddress CfgBase(Config, CGM.Int8Ty,
93 /*Alignment=*/CharUnits::fromQuantity(Quantity: 64));
94 CharUnits Offset = CharUnits::Zero();
95 for (auto &Arg : KernelCallArgs) {
96 auto TInfo = CGM.getContext().getTypeInfoInChars(T: Arg.getType());
97 Offset = Offset.alignTo(Align: TInfo.Align);
98 Address Addr =
99 CGF.Builder.CreateConstInBoundsGEP(Addr: CfgBase, Index: Offset.getQuantity());
100 Arg.copyInto(CGF, A: Addr);
101 Offset += TInfo.Width;
102 }
103 // Make `cudaLaunchDevice` call, i.e. E->getConfig().
104 const CallExpr *LaunchCall = E->getConfig();
105 QualType LaunchCalleeFuncTy = LaunchCall->getCallee()
106 ->getType()
107 ->getAs<PointerType>()
108 ->getPointeeType();
109 CGCallee LaunchCallee = CGF.EmitCallee(E: LaunchCall->getCallee());
110 CallArgList LaunchCallArgs;
111 CGF.EmitCallArgs(Args&: LaunchCallArgs,
112 Prototype: LaunchCalleeFuncTy->getAs<FunctionProtoType>(),
113 ArgRange: LaunchCall->arguments(), AC: LaunchCall->getDirectCallee());
114 // Replace func and paramterbuffer arguments.
115 LaunchCallArgs[0] = CallArg(RValue::get(V: KernelCallee.getFunctionPointer()),
116 CGM.getContext().VoidPtrTy);
117 LaunchCallArgs[1] = CallArg(RValue::get(V: Config), CGM.getContext().VoidPtrTy);
118 const CGFunctionInfo &LaunchCallInfo = CGM.getTypes().arrangeFreeFunctionCall(
119 Args: LaunchCallArgs, Ty: LaunchCalleeFuncTy->getAs<FunctionProtoType>(),
120 /*ChainCall=*/false, ABIInfoFD: CGF.getCurrentFunctionDecl());
121 CGF.EmitCall(CallInfo: LaunchCallInfo, Callee: LaunchCallee, ReturnValue, Args: LaunchCallArgs,
122 CallOrInvoke,
123 /*IsMustTail=*/false, Loc: E->getExprLoc());
124 CGF.EmitBranch(Block: ContBlock);
125
126 CGF.EmitBlock(BB: ContBlock);
127 eval.end(CGF);
128
129 return RValue::get(V: nullptr);
130}
131
132RValue CGCUDARuntime::EmitCUDAKernelCallExpr(CodeGenFunction &CGF,
133 const CUDAKernelCallExpr *E,
134 ReturnValueSlot ReturnValue,
135 llvm::CallBase **CallOrInvoke) {
136 llvm::BasicBlock *ConfigOKBlock = CGF.createBasicBlock(name: "kcall.configok");
137 llvm::BasicBlock *ContBlock = CGF.createBasicBlock(name: "kcall.end");
138
139 CodeGenFunction::ConditionalEvaluation eval(CGF);
140 CGF.EmitBranchOnBoolExpr(Cond: E->getConfig(), TrueBlock: ContBlock, FalseBlock: ConfigOKBlock,
141 /*TrueCount=*/0);
142
143 eval.begin(CGF);
144 CGF.EmitBlock(BB: ConfigOKBlock);
145 CGF.EmitSimpleCallExpr(E, ReturnValue, CallOrInvoke);
146 CGF.EmitBranch(Block: ContBlock);
147
148 CGF.EmitBlock(BB: ContBlock);
149 eval.end(CGF);
150
151 return RValue::get(V: nullptr);
152}
153