xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/CodeGen/CGOpenCLRuntime.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This provides an abstract class for OpenCL code generation.  Concrete
107330f729Sjoerg // subclasses of this implement code generation for specific OpenCL
117330f729Sjoerg // runtime libraries.
127330f729Sjoerg //
137330f729Sjoerg //===----------------------------------------------------------------------===//
147330f729Sjoerg 
157330f729Sjoerg #include "CGOpenCLRuntime.h"
167330f729Sjoerg #include "CodeGenFunction.h"
177330f729Sjoerg #include "TargetInfo.h"
187330f729Sjoerg #include "clang/CodeGen/ConstantInitBuilder.h"
197330f729Sjoerg #include "llvm/IR/DerivedTypes.h"
207330f729Sjoerg #include "llvm/IR/GlobalValue.h"
217330f729Sjoerg #include <assert.h>
227330f729Sjoerg 
237330f729Sjoerg using namespace clang;
247330f729Sjoerg using namespace CodeGen;
257330f729Sjoerg 
~CGOpenCLRuntime()267330f729Sjoerg CGOpenCLRuntime::~CGOpenCLRuntime() {}
277330f729Sjoerg 
EmitWorkGroupLocalVarDecl(CodeGenFunction & CGF,const VarDecl & D)287330f729Sjoerg void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
297330f729Sjoerg                                                 const VarDecl &D) {
307330f729Sjoerg   return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
317330f729Sjoerg }
327330f729Sjoerg 
convertOpenCLSpecificType(const Type * T)337330f729Sjoerg llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
347330f729Sjoerg   assert(T->isOpenCLSpecificType() &&
357330f729Sjoerg          "Not an OpenCL specific type!");
367330f729Sjoerg 
377330f729Sjoerg   llvm::LLVMContext& Ctx = CGM.getLLVMContext();
387330f729Sjoerg   uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
397330f729Sjoerg       CGM.getContext().getOpenCLTypeAddrSpace(T));
407330f729Sjoerg   switch (cast<BuiltinType>(T)->getKind()) {
417330f729Sjoerg   default:
427330f729Sjoerg     llvm_unreachable("Unexpected opencl builtin type!");
437330f729Sjoerg     return nullptr;
447330f729Sjoerg #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
457330f729Sjoerg   case BuiltinType::Id: \
467330f729Sjoerg     return llvm::PointerType::get( \
477330f729Sjoerg         llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \
487330f729Sjoerg         AddrSpc);
497330f729Sjoerg #include "clang/Basic/OpenCLImageTypes.def"
507330f729Sjoerg   case BuiltinType::OCLSampler:
517330f729Sjoerg     return getSamplerType(T);
527330f729Sjoerg   case BuiltinType::OCLEvent:
537330f729Sjoerg     return llvm::PointerType::get(
547330f729Sjoerg         llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc);
557330f729Sjoerg   case BuiltinType::OCLClkEvent:
567330f729Sjoerg     return llvm::PointerType::get(
577330f729Sjoerg         llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc);
587330f729Sjoerg   case BuiltinType::OCLQueue:
597330f729Sjoerg     return llvm::PointerType::get(
607330f729Sjoerg         llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc);
617330f729Sjoerg   case BuiltinType::OCLReserveID:
627330f729Sjoerg     return llvm::PointerType::get(
637330f729Sjoerg         llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc);
647330f729Sjoerg #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
657330f729Sjoerg   case BuiltinType::Id: \
667330f729Sjoerg     return llvm::PointerType::get( \
677330f729Sjoerg         llvm::StructType::create(Ctx, "opencl." #ExtType), AddrSpc);
687330f729Sjoerg #include "clang/Basic/OpenCLExtensionTypes.def"
697330f729Sjoerg   }
707330f729Sjoerg }
717330f729Sjoerg 
getPipeType(const PipeType * T)727330f729Sjoerg llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
737330f729Sjoerg   if (T->isReadOnly())
747330f729Sjoerg     return getPipeType(T, "opencl.pipe_ro_t", PipeROTy);
757330f729Sjoerg   else
767330f729Sjoerg     return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy);
777330f729Sjoerg }
787330f729Sjoerg 
getPipeType(const PipeType * T,StringRef Name,llvm::Type * & PipeTy)797330f729Sjoerg llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name,
807330f729Sjoerg                                          llvm::Type *&PipeTy) {
817330f729Sjoerg   if (!PipeTy)
827330f729Sjoerg     PipeTy = llvm::PointerType::get(llvm::StructType::create(
837330f729Sjoerg       CGM.getLLVMContext(), Name),
847330f729Sjoerg       CGM.getContext().getTargetAddressSpace(
857330f729Sjoerg           CGM.getContext().getOpenCLTypeAddrSpace(T)));
867330f729Sjoerg   return PipeTy;
877330f729Sjoerg }
887330f729Sjoerg 
getSamplerType(const Type * T)897330f729Sjoerg llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
907330f729Sjoerg   if (!SamplerTy)
917330f729Sjoerg     SamplerTy = llvm::PointerType::get(llvm::StructType::create(
927330f729Sjoerg       CGM.getLLVMContext(), "opencl.sampler_t"),
937330f729Sjoerg       CGM.getContext().getTargetAddressSpace(
947330f729Sjoerg           CGM.getContext().getOpenCLTypeAddrSpace(T)));
957330f729Sjoerg   return SamplerTy;
967330f729Sjoerg }
977330f729Sjoerg 
getPipeElemSize(const Expr * PipeArg)987330f729Sjoerg llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
99*e038c9c4Sjoerg   const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
1007330f729Sjoerg   // The type of the last (implicit) argument to be passed.
1017330f729Sjoerg   llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
1027330f729Sjoerg   unsigned TypeSize = CGM.getContext()
1037330f729Sjoerg                           .getTypeSizeInChars(PipeTy->getElementType())
1047330f729Sjoerg                           .getQuantity();
1057330f729Sjoerg   return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
1067330f729Sjoerg }
1077330f729Sjoerg 
getPipeElemAlign(const Expr * PipeArg)1087330f729Sjoerg llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
109*e038c9c4Sjoerg   const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
1107330f729Sjoerg   // The type of the last (implicit) argument to be passed.
1117330f729Sjoerg   llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
1127330f729Sjoerg   unsigned TypeSize = CGM.getContext()
1137330f729Sjoerg                           .getTypeAlignInChars(PipeTy->getElementType())
1147330f729Sjoerg                           .getQuantity();
1157330f729Sjoerg   return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
1167330f729Sjoerg }
1177330f729Sjoerg 
getGenericVoidPointerType()1187330f729Sjoerg llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
1197330f729Sjoerg   assert(CGM.getLangOpts().OpenCL);
1207330f729Sjoerg   return llvm::IntegerType::getInt8PtrTy(
1217330f729Sjoerg       CGM.getLLVMContext(),
1227330f729Sjoerg       CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
1237330f729Sjoerg }
1247330f729Sjoerg 
1257330f729Sjoerg // Get the block literal from an expression derived from the block expression.
1267330f729Sjoerg // OpenCL v2.0 s6.12.5:
1277330f729Sjoerg // Block variable declarations are implicitly qualified with const. Therefore
1287330f729Sjoerg // all block variables must be initialized at declaration time and may not be
1297330f729Sjoerg // reassigned.
getBlockExpr(const Expr * E)1307330f729Sjoerg static const BlockExpr *getBlockExpr(const Expr *E) {
1317330f729Sjoerg   const Expr *Prev = nullptr; // to make sure we do not stuck in infinite loop.
1327330f729Sjoerg   while(!isa<BlockExpr>(E) && E != Prev) {
1337330f729Sjoerg     Prev = E;
1347330f729Sjoerg     E = E->IgnoreCasts();
1357330f729Sjoerg     if (auto DR = dyn_cast<DeclRefExpr>(E)) {
1367330f729Sjoerg       E = cast<VarDecl>(DR->getDecl())->getInit();
1377330f729Sjoerg     }
1387330f729Sjoerg   }
1397330f729Sjoerg   return cast<BlockExpr>(E);
1407330f729Sjoerg }
1417330f729Sjoerg 
1427330f729Sjoerg /// Record emitted llvm invoke function and llvm block literal for the
1437330f729Sjoerg /// corresponding block expression.
recordBlockInfo(const BlockExpr * E,llvm::Function * InvokeF,llvm::Value * Block)1447330f729Sjoerg void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
1457330f729Sjoerg                                       llvm::Function *InvokeF,
1467330f729Sjoerg                                       llvm::Value *Block) {
1477330f729Sjoerg   assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() &&
1487330f729Sjoerg          "Block expression emitted twice");
1497330f729Sjoerg   assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
1507330f729Sjoerg   assert(Block->getType()->isPointerTy() && "Invalid block literal type");
1517330f729Sjoerg   EnqueuedBlockMap[E].InvokeFunc = InvokeF;
1527330f729Sjoerg   EnqueuedBlockMap[E].BlockArg = Block;
1537330f729Sjoerg   EnqueuedBlockMap[E].Kernel = nullptr;
1547330f729Sjoerg }
1557330f729Sjoerg 
getInvokeFunction(const Expr * E)1567330f729Sjoerg llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) {
1577330f729Sjoerg   return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc;
1587330f729Sjoerg }
1597330f729Sjoerg 
1607330f729Sjoerg CGOpenCLRuntime::EnqueuedBlockInfo
emitOpenCLEnqueuedBlock(CodeGenFunction & CGF,const Expr * E)1617330f729Sjoerg CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
1627330f729Sjoerg   CGF.EmitScalarExpr(E);
1637330f729Sjoerg 
1647330f729Sjoerg   // The block literal may be assigned to a const variable. Chasing down
1657330f729Sjoerg   // to get the block literal.
1667330f729Sjoerg   const BlockExpr *Block = getBlockExpr(E);
1677330f729Sjoerg 
1687330f729Sjoerg   assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() &&
1697330f729Sjoerg          "Block expression not emitted");
1707330f729Sjoerg 
1717330f729Sjoerg   // Do not emit the block wrapper again if it has been emitted.
1727330f729Sjoerg   if (EnqueuedBlockMap[Block].Kernel) {
1737330f729Sjoerg     return EnqueuedBlockMap[Block];
1747330f729Sjoerg   }
1757330f729Sjoerg 
1767330f729Sjoerg   auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
1777330f729Sjoerg       CGF, EnqueuedBlockMap[Block].InvokeFunc,
1787330f729Sjoerg       EnqueuedBlockMap[Block].BlockArg->stripPointerCasts());
1797330f729Sjoerg 
1807330f729Sjoerg   // The common part of the post-processing of the kernel goes here.
1817330f729Sjoerg   F->addFnAttr(llvm::Attribute::NoUnwind);
1827330f729Sjoerg   F->setCallingConv(
1837330f729Sjoerg       CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
1847330f729Sjoerg   EnqueuedBlockMap[Block].Kernel = F;
1857330f729Sjoerg   return EnqueuedBlockMap[Block];
1867330f729Sjoerg }
187