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