12dbb708bSPeter Collingbourne //===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
22dbb708bSPeter Collingbourne //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62dbb708bSPeter Collingbourne //
72dbb708bSPeter Collingbourne //===----------------------------------------------------------------------===//
82dbb708bSPeter Collingbourne //
92dbb708bSPeter Collingbourne // This provides an abstract class for OpenCL code generation. Concrete
102dbb708bSPeter Collingbourne // subclasses of this implement code generation for specific OpenCL
112dbb708bSPeter Collingbourne // runtime libraries.
122dbb708bSPeter Collingbourne //
132dbb708bSPeter Collingbourne //===----------------------------------------------------------------------===//
142dbb708bSPeter Collingbourne
152dbb708bSPeter Collingbourne #include "CGOpenCLRuntime.h"
162dbb708bSPeter Collingbourne #include "CodeGenFunction.h"
1737ceedeaSYaxun Liu #include "TargetInfo.h"
18c2a87a05SYaxun Liu #include "clang/CodeGen/ConstantInitBuilder.h"
19ffd5551bSChandler Carruth #include "llvm/IR/DerivedTypes.h"
20ffd5551bSChandler Carruth #include "llvm/IR/GlobalValue.h"
21d8a08ea9SGuy Benyei #include <assert.h>
222dbb708bSPeter Collingbourne
232dbb708bSPeter Collingbourne using namespace clang;
242dbb708bSPeter Collingbourne using namespace CodeGen;
252dbb708bSPeter Collingbourne
~CGOpenCLRuntime()26637d1e66SAngel Garcia Gomez CGOpenCLRuntime::~CGOpenCLRuntime() {}
272dbb708bSPeter Collingbourne
EmitWorkGroupLocalVarDecl(CodeGenFunction & CGF,const VarDecl & D)282dbb708bSPeter Collingbourne void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
292dbb708bSPeter Collingbourne const VarDecl &D) {
302dbb708bSPeter Collingbourne return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
312dbb708bSPeter Collingbourne }
32d8a08ea9SGuy Benyei
convertOpenCLSpecificType(const Type * T)33d8a08ea9SGuy Benyei llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
34d8a08ea9SGuy Benyei assert(T->isOpenCLSpecificType() &&
35d8a08ea9SGuy Benyei "Not an OpenCL specific type!");
36d8a08ea9SGuy Benyei
37d8a08ea9SGuy Benyei switch (cast<BuiltinType>(T)->getKind()) {
38d8a08ea9SGuy Benyei default:
39d8a08ea9SGuy Benyei llvm_unreachable("Unexpected opencl builtin type!");
408a13c418SCraig Topper return nullptr;
41954ba21fSAlexey Bader #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
42954ba21fSAlexey Bader case BuiltinType::Id: \
432724c153SArthur Eubanks return getPointerType(T, "opencl." #ImgType "_" #Suffix "_t");
44b62f1440SAlexey Bader #include "clang/Basic/OpenCLImageTypes.def"
4561054198SGuy Benyei case BuiltinType::OCLSampler:
46efb4d4c7SSven van Haastregt return getSamplerType(T);
471b4fb3e0SGuy Benyei case BuiltinType::OCLEvent:
482724c153SArthur Eubanks return getPointerType(T, "opencl.event_t");
499c8453fbSAlexey Bader case BuiltinType::OCLClkEvent:
502724c153SArthur Eubanks return getPointerType(T, "opencl.clk_event_t");
519c8453fbSAlexey Bader case BuiltinType::OCLQueue:
522724c153SArthur Eubanks return getPointerType(T, "opencl.queue_t");
539c8453fbSAlexey Bader case BuiltinType::OCLReserveID:
542724c153SArthur Eubanks return getPointerType(T, "opencl.reserve_id_t");
553fee3518SAndrew Savonichev #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
563fee3518SAndrew Savonichev case BuiltinType::Id: \
572724c153SArthur Eubanks return getPointerType(T, "opencl." #ExtType);
583fee3518SAndrew Savonichev #include "clang/Basic/OpenCLExtensionTypes.def"
59d8a08ea9SGuy Benyei }
60d8a08ea9SGuy Benyei }
619c14e282SXiuli Pan
getPointerType(const Type * T,StringRef Name)622724c153SArthur Eubanks llvm::PointerType *CGOpenCLRuntime::getPointerType(const Type *T,
632724c153SArthur Eubanks StringRef Name) {
642724c153SArthur Eubanks auto I = CachedTys.find(Name);
652724c153SArthur Eubanks if (I != CachedTys.end())
662724c153SArthur Eubanks return I->second;
672724c153SArthur Eubanks
682724c153SArthur Eubanks llvm::LLVMContext &Ctx = CGM.getLLVMContext();
692724c153SArthur Eubanks uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
702724c153SArthur Eubanks CGM.getContext().getOpenCLTypeAddrSpace(T));
712724c153SArthur Eubanks auto *PTy =
722724c153SArthur Eubanks llvm::PointerType::get(llvm::StructType::create(Ctx, Name), AddrSpc);
732724c153SArthur Eubanks CachedTys[Name] = PTy;
742724c153SArthur Eubanks return PTy;
752724c153SArthur Eubanks }
762724c153SArthur Eubanks
getPipeType(const PipeType * T)77efb4d4c7SSven van Haastregt llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
784700faa2SSven van Haastregt if (T->isReadOnly())
794700faa2SSven van Haastregt return getPipeType(T, "opencl.pipe_ro_t", PipeROTy);
804700faa2SSven van Haastregt else
814700faa2SSven van Haastregt return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy);
829c14e282SXiuli Pan }
839c14e282SXiuli Pan
getPipeType(const PipeType * T,StringRef Name,llvm::Type * & PipeTy)844700faa2SSven van Haastregt llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name,
854700faa2SSven van Haastregt llvm::Type *&PipeTy) {
864700faa2SSven van Haastregt if (!PipeTy)
874700faa2SSven van Haastregt PipeTy = llvm::PointerType::get(llvm::StructType::create(
884700faa2SSven van Haastregt CGM.getLLVMContext(), Name),
894700faa2SSven van Haastregt CGM.getContext().getTargetAddressSpace(
904700faa2SSven van Haastregt CGM.getContext().getOpenCLTypeAddrSpace(T)));
919c14e282SXiuli Pan return PipeTy;
929c14e282SXiuli Pan }
930bc4b2d3SYaxun Liu
getSamplerType(const Type * T)94efb4d4c7SSven van Haastregt llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
950bc4b2d3SYaxun Liu if (!SamplerTy)
960bc4b2d3SYaxun Liu SamplerTy = llvm::PointerType::get(llvm::StructType::create(
970bc4b2d3SYaxun Liu CGM.getLLVMContext(), "opencl.sampler_t"),
980bc4b2d3SYaxun Liu CGM.getContext().getTargetAddressSpace(
993bb7eaf7SSven van Haastregt CGM.getContext().getOpenCLTypeAddrSpace(T)));
1000bc4b2d3SYaxun Liu return SamplerTy;
101465c1897SAlexey Bader }
102465c1897SAlexey Bader
getPipeElemSize(const Expr * PipeArg)103465c1897SAlexey Bader llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
1045936717fSSimon Pilgrim const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
105465c1897SAlexey Bader // The type of the last (implicit) argument to be passed.
106465c1897SAlexey Bader llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
107465c1897SAlexey Bader unsigned TypeSize = CGM.getContext()
108465c1897SAlexey Bader .getTypeSizeInChars(PipeTy->getElementType())
109465c1897SAlexey Bader .getQuantity();
110465c1897SAlexey Bader return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
111465c1897SAlexey Bader }
112465c1897SAlexey Bader
getPipeElemAlign(const Expr * PipeArg)113465c1897SAlexey Bader llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
1145936717fSSimon Pilgrim const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
115465c1897SAlexey Bader // The type of the last (implicit) argument to be passed.
116465c1897SAlexey Bader llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
117465c1897SAlexey Bader unsigned TypeSize = CGM.getContext()
118465c1897SAlexey Bader .getTypeAlignInChars(PipeTy->getElementType())
119465c1897SAlexey Bader .getQuantity();
120465c1897SAlexey Bader return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
1210bc4b2d3SYaxun Liu }
12210712d92SYaxun Liu
getGenericVoidPointerType()12310712d92SYaxun Liu llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
12410712d92SYaxun Liu assert(CGM.getLangOpts().OpenCL);
12510712d92SYaxun Liu return llvm::IntegerType::getInt8PtrTy(
12610712d92SYaxun Liu CGM.getLLVMContext(),
12710712d92SYaxun Liu CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
12810712d92SYaxun Liu }
129c2a87a05SYaxun Liu
13043fceb27SAndrew Savonichev // Get the block literal from an expression derived from the block expression.
13143fceb27SAndrew Savonichev // OpenCL v2.0 s6.12.5:
13243fceb27SAndrew Savonichev // Block variable declarations are implicitly qualified with const. Therefore
13343fceb27SAndrew Savonichev // all block variables must be initialized at declaration time and may not be
13443fceb27SAndrew Savonichev // reassigned.
getBlockExpr(const Expr * E)13543fceb27SAndrew Savonichev static const BlockExpr *getBlockExpr(const Expr *E) {
13643fceb27SAndrew Savonichev const Expr *Prev = nullptr; // to make sure we do not stuck in infinite loop.
13743fceb27SAndrew Savonichev while(!isa<BlockExpr>(E) && E != Prev) {
13843fceb27SAndrew Savonichev Prev = E;
13943fceb27SAndrew Savonichev E = E->IgnoreCasts();
14043fceb27SAndrew Savonichev if (auto DR = dyn_cast<DeclRefExpr>(E)) {
14143fceb27SAndrew Savonichev E = cast<VarDecl>(DR->getDecl())->getInit();
14243fceb27SAndrew Savonichev }
14343fceb27SAndrew Savonichev }
14443fceb27SAndrew Savonichev return cast<BlockExpr>(E);
14543fceb27SAndrew Savonichev }
14643fceb27SAndrew Savonichev
147fa13d015SYaxun Liu /// Record emitted llvm invoke function and llvm block literal for the
148fa13d015SYaxun Liu /// corresponding block expression.
recordBlockInfo(const BlockExpr * E,llvm::Function * InvokeF,llvm::Value * Block,llvm::Type * BlockTy)149fa13d015SYaxun Liu void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
150fa13d015SYaxun Liu llvm::Function *InvokeF,
151*6e1e99dcSNikita Popov llvm::Value *Block, llvm::Type *BlockTy) {
152fa13d015SYaxun Liu assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() &&
153fa13d015SYaxun Liu "Block expression emitted twice");
154fa13d015SYaxun Liu assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
155fa13d015SYaxun Liu assert(Block->getType()->isPointerTy() && "Invalid block literal type");
156fa13d015SYaxun Liu EnqueuedBlockMap[E].InvokeFunc = InvokeF;
157fa13d015SYaxun Liu EnqueuedBlockMap[E].BlockArg = Block;
158*6e1e99dcSNikita Popov EnqueuedBlockMap[E].BlockTy = BlockTy;
159fa13d015SYaxun Liu EnqueuedBlockMap[E].Kernel = nullptr;
160fa13d015SYaxun Liu }
161fa13d015SYaxun Liu
getInvokeFunction(const Expr * E)16243fceb27SAndrew Savonichev llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) {
16343fceb27SAndrew Savonichev return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc;
16443fceb27SAndrew Savonichev }
16543fceb27SAndrew Savonichev
166c2a87a05SYaxun Liu CGOpenCLRuntime::EnqueuedBlockInfo
emitOpenCLEnqueuedBlock(CodeGenFunction & CGF,const Expr * E)167c2a87a05SYaxun Liu CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
168fa13d015SYaxun Liu CGF.EmitScalarExpr(E);
169fa13d015SYaxun Liu
170da3b6320SSven van Haastregt // The block literal may be assigned to a const variable. Chasing down
171da3b6320SSven van Haastregt // to get the block literal.
17243fceb27SAndrew Savonichev const BlockExpr *Block = getBlockExpr(E);
173da3b6320SSven van Haastregt
174fa13d015SYaxun Liu assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() &&
175fa13d015SYaxun Liu "Block expression not emitted");
176fa13d015SYaxun Liu
177fa13d015SYaxun Liu // Do not emit the block wrapper again if it has been emitted.
178fa13d015SYaxun Liu if (EnqueuedBlockMap[Block].Kernel) {
179fa13d015SYaxun Liu return EnqueuedBlockMap[Block];
180c2a87a05SYaxun Liu }
181c2a87a05SYaxun Liu
182c2a87a05SYaxun Liu auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
183*6e1e99dcSNikita Popov CGF, EnqueuedBlockMap[Block].InvokeFunc, EnqueuedBlockMap[Block].BlockTy);
184c2a87a05SYaxun Liu
185c2a87a05SYaxun Liu // The common part of the post-processing of the kernel goes here.
186c2a87a05SYaxun Liu F->addFnAttr(llvm::Attribute::NoUnwind);
187c2a87a05SYaxun Liu F->setCallingConv(
188c2a87a05SYaxun Liu CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
189fa13d015SYaxun Liu EnqueuedBlockMap[Block].Kernel = F;
190fa13d015SYaxun Liu return EnqueuedBlockMap[Block];
191c2a87a05SYaxun Liu }
192