106f32e7eSjoerg //===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // This provides an abstract class for OpenCL code generation.  Concrete
1006f32e7eSjoerg // subclasses of this implement code generation for specific OpenCL
1106f32e7eSjoerg // runtime libraries.
1206f32e7eSjoerg //
1306f32e7eSjoerg //===----------------------------------------------------------------------===//
1406f32e7eSjoerg 
1506f32e7eSjoerg #include "CGOpenCLRuntime.h"
1606f32e7eSjoerg #include "CodeGenFunction.h"
1706f32e7eSjoerg #include "TargetInfo.h"
1806f32e7eSjoerg #include "clang/CodeGen/ConstantInitBuilder.h"
1906f32e7eSjoerg #include "llvm/IR/DerivedTypes.h"
2006f32e7eSjoerg #include "llvm/IR/GlobalValue.h"
2106f32e7eSjoerg #include <assert.h>
2206f32e7eSjoerg 
2306f32e7eSjoerg using namespace clang;
2406f32e7eSjoerg using namespace CodeGen;
2506f32e7eSjoerg 
~CGOpenCLRuntime()2606f32e7eSjoerg CGOpenCLRuntime::~CGOpenCLRuntime() {}
2706f32e7eSjoerg 
EmitWorkGroupLocalVarDecl(CodeGenFunction & CGF,const VarDecl & D)2806f32e7eSjoerg void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
2906f32e7eSjoerg                                                 const VarDecl &D) {
3006f32e7eSjoerg   return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
3106f32e7eSjoerg }
3206f32e7eSjoerg 
convertOpenCLSpecificType(const Type * T)3306f32e7eSjoerg llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
3406f32e7eSjoerg   assert(T->isOpenCLSpecificType() &&
3506f32e7eSjoerg          "Not an OpenCL specific type!");
3606f32e7eSjoerg 
3706f32e7eSjoerg   llvm::LLVMContext& Ctx = CGM.getLLVMContext();
3806f32e7eSjoerg   uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
3906f32e7eSjoerg       CGM.getContext().getOpenCLTypeAddrSpace(T));
4006f32e7eSjoerg   switch (cast<BuiltinType>(T)->getKind()) {
4106f32e7eSjoerg   default:
4206f32e7eSjoerg     llvm_unreachable("Unexpected opencl builtin type!");
4306f32e7eSjoerg     return nullptr;
4406f32e7eSjoerg #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
4506f32e7eSjoerg   case BuiltinType::Id: \
4606f32e7eSjoerg     return llvm::PointerType::get( \
4706f32e7eSjoerg         llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \
4806f32e7eSjoerg         AddrSpc);
4906f32e7eSjoerg #include "clang/Basic/OpenCLImageTypes.def"
5006f32e7eSjoerg   case BuiltinType::OCLSampler:
5106f32e7eSjoerg     return getSamplerType(T);
5206f32e7eSjoerg   case BuiltinType::OCLEvent:
5306f32e7eSjoerg     return llvm::PointerType::get(
5406f32e7eSjoerg         llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc);
5506f32e7eSjoerg   case BuiltinType::OCLClkEvent:
5606f32e7eSjoerg     return llvm::PointerType::get(
5706f32e7eSjoerg         llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc);
5806f32e7eSjoerg   case BuiltinType::OCLQueue:
5906f32e7eSjoerg     return llvm::PointerType::get(
6006f32e7eSjoerg         llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc);
6106f32e7eSjoerg   case BuiltinType::OCLReserveID:
6206f32e7eSjoerg     return llvm::PointerType::get(
6306f32e7eSjoerg         llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc);
6406f32e7eSjoerg #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
6506f32e7eSjoerg   case BuiltinType::Id: \
6606f32e7eSjoerg     return llvm::PointerType::get( \
6706f32e7eSjoerg         llvm::StructType::create(Ctx, "opencl." #ExtType), AddrSpc);
6806f32e7eSjoerg #include "clang/Basic/OpenCLExtensionTypes.def"
6906f32e7eSjoerg   }
7006f32e7eSjoerg }
7106f32e7eSjoerg 
getPipeType(const PipeType * T)7206f32e7eSjoerg llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
7306f32e7eSjoerg   if (T->isReadOnly())
7406f32e7eSjoerg     return getPipeType(T, "opencl.pipe_ro_t", PipeROTy);
7506f32e7eSjoerg   else
7606f32e7eSjoerg     return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy);
7706f32e7eSjoerg }
7806f32e7eSjoerg 
getPipeType(const PipeType * T,StringRef Name,llvm::Type * & PipeTy)7906f32e7eSjoerg llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name,
8006f32e7eSjoerg                                          llvm::Type *&PipeTy) {
8106f32e7eSjoerg   if (!PipeTy)
8206f32e7eSjoerg     PipeTy = llvm::PointerType::get(llvm::StructType::create(
8306f32e7eSjoerg       CGM.getLLVMContext(), Name),
8406f32e7eSjoerg       CGM.getContext().getTargetAddressSpace(
8506f32e7eSjoerg           CGM.getContext().getOpenCLTypeAddrSpace(T)));
8606f32e7eSjoerg   return PipeTy;
8706f32e7eSjoerg }
8806f32e7eSjoerg 
getSamplerType(const Type * T)8906f32e7eSjoerg llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
9006f32e7eSjoerg   if (!SamplerTy)
9106f32e7eSjoerg     SamplerTy = llvm::PointerType::get(llvm::StructType::create(
9206f32e7eSjoerg       CGM.getLLVMContext(), "opencl.sampler_t"),
9306f32e7eSjoerg       CGM.getContext().getTargetAddressSpace(
9406f32e7eSjoerg           CGM.getContext().getOpenCLTypeAddrSpace(T)));
9506f32e7eSjoerg   return SamplerTy;
9606f32e7eSjoerg }
9706f32e7eSjoerg 
getPipeElemSize(const Expr * PipeArg)9806f32e7eSjoerg llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
99*13fbcb42Sjoerg   const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
10006f32e7eSjoerg   // The type of the last (implicit) argument to be passed.
10106f32e7eSjoerg   llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
10206f32e7eSjoerg   unsigned TypeSize = CGM.getContext()
10306f32e7eSjoerg                           .getTypeSizeInChars(PipeTy->getElementType())
10406f32e7eSjoerg                           .getQuantity();
10506f32e7eSjoerg   return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
10606f32e7eSjoerg }
10706f32e7eSjoerg 
getPipeElemAlign(const Expr * PipeArg)10806f32e7eSjoerg llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
109*13fbcb42Sjoerg   const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
11006f32e7eSjoerg   // The type of the last (implicit) argument to be passed.
11106f32e7eSjoerg   llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
11206f32e7eSjoerg   unsigned TypeSize = CGM.getContext()
11306f32e7eSjoerg                           .getTypeAlignInChars(PipeTy->getElementType())
11406f32e7eSjoerg                           .getQuantity();
11506f32e7eSjoerg   return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
11606f32e7eSjoerg }
11706f32e7eSjoerg 
getGenericVoidPointerType()11806f32e7eSjoerg llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
11906f32e7eSjoerg   assert(CGM.getLangOpts().OpenCL);
12006f32e7eSjoerg   return llvm::IntegerType::getInt8PtrTy(
12106f32e7eSjoerg       CGM.getLLVMContext(),
12206f32e7eSjoerg       CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
12306f32e7eSjoerg }
12406f32e7eSjoerg 
12506f32e7eSjoerg // Get the block literal from an expression derived from the block expression.
12606f32e7eSjoerg // OpenCL v2.0 s6.12.5:
12706f32e7eSjoerg // Block variable declarations are implicitly qualified with const. Therefore
12806f32e7eSjoerg // all block variables must be initialized at declaration time and may not be
12906f32e7eSjoerg // reassigned.
getBlockExpr(const Expr * E)13006f32e7eSjoerg static const BlockExpr *getBlockExpr(const Expr *E) {
13106f32e7eSjoerg   const Expr *Prev = nullptr; // to make sure we do not stuck in infinite loop.
13206f32e7eSjoerg   while(!isa<BlockExpr>(E) && E != Prev) {
13306f32e7eSjoerg     Prev = E;
13406f32e7eSjoerg     E = E->IgnoreCasts();
13506f32e7eSjoerg     if (auto DR = dyn_cast<DeclRefExpr>(E)) {
13606f32e7eSjoerg       E = cast<VarDecl>(DR->getDecl())->getInit();
13706f32e7eSjoerg     }
13806f32e7eSjoerg   }
13906f32e7eSjoerg   return cast<BlockExpr>(E);
14006f32e7eSjoerg }
14106f32e7eSjoerg 
14206f32e7eSjoerg /// Record emitted llvm invoke function and llvm block literal for the
14306f32e7eSjoerg /// corresponding block expression.
recordBlockInfo(const BlockExpr * E,llvm::Function * InvokeF,llvm::Value * Block)14406f32e7eSjoerg void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
14506f32e7eSjoerg                                       llvm::Function *InvokeF,
14606f32e7eSjoerg                                       llvm::Value *Block) {
14706f32e7eSjoerg   assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() &&
14806f32e7eSjoerg          "Block expression emitted twice");
14906f32e7eSjoerg   assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
15006f32e7eSjoerg   assert(Block->getType()->isPointerTy() && "Invalid block literal type");
15106f32e7eSjoerg   EnqueuedBlockMap[E].InvokeFunc = InvokeF;
15206f32e7eSjoerg   EnqueuedBlockMap[E].BlockArg = Block;
15306f32e7eSjoerg   EnqueuedBlockMap[E].Kernel = nullptr;
15406f32e7eSjoerg }
15506f32e7eSjoerg 
getInvokeFunction(const Expr * E)15606f32e7eSjoerg llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) {
15706f32e7eSjoerg   return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc;
15806f32e7eSjoerg }
15906f32e7eSjoerg 
16006f32e7eSjoerg CGOpenCLRuntime::EnqueuedBlockInfo
emitOpenCLEnqueuedBlock(CodeGenFunction & CGF,const Expr * E)16106f32e7eSjoerg CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
16206f32e7eSjoerg   CGF.EmitScalarExpr(E);
16306f32e7eSjoerg 
16406f32e7eSjoerg   // The block literal may be assigned to a const variable. Chasing down
16506f32e7eSjoerg   // to get the block literal.
16606f32e7eSjoerg   const BlockExpr *Block = getBlockExpr(E);
16706f32e7eSjoerg 
16806f32e7eSjoerg   assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() &&
16906f32e7eSjoerg          "Block expression not emitted");
17006f32e7eSjoerg 
17106f32e7eSjoerg   // Do not emit the block wrapper again if it has been emitted.
17206f32e7eSjoerg   if (EnqueuedBlockMap[Block].Kernel) {
17306f32e7eSjoerg     return EnqueuedBlockMap[Block];
17406f32e7eSjoerg   }
17506f32e7eSjoerg 
17606f32e7eSjoerg   auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
17706f32e7eSjoerg       CGF, EnqueuedBlockMap[Block].InvokeFunc,
17806f32e7eSjoerg       EnqueuedBlockMap[Block].BlockArg->stripPointerCasts());
17906f32e7eSjoerg 
18006f32e7eSjoerg   // The common part of the post-processing of the kernel goes here.
18106f32e7eSjoerg   F->addFnAttr(llvm::Attribute::NoUnwind);
18206f32e7eSjoerg   F->setCallingConv(
18306f32e7eSjoerg       CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
18406f32e7eSjoerg   EnqueuedBlockMap[Block].Kernel = F;
18506f32e7eSjoerg   return EnqueuedBlockMap[Block];
18606f32e7eSjoerg }
187