1*0b57cec5SDimitry Andric //===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This provides an abstract class for OpenCL code generation. Concrete 10*0b57cec5SDimitry Andric // subclasses of this implement code generation for specific OpenCL 11*0b57cec5SDimitry Andric // runtime libraries. 12*0b57cec5SDimitry Andric // 13*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "CGOpenCLRuntime.h" 16*0b57cec5SDimitry Andric #include "CodeGenFunction.h" 17*0b57cec5SDimitry Andric #include "TargetInfo.h" 18*0b57cec5SDimitry Andric #include "clang/CodeGen/ConstantInitBuilder.h" 19*0b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h" 20*0b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h" 21*0b57cec5SDimitry Andric #include <assert.h> 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric using namespace clang; 24*0b57cec5SDimitry Andric using namespace CodeGen; 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric CGOpenCLRuntime::~CGOpenCLRuntime() {} 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF, 29*0b57cec5SDimitry Andric const VarDecl &D) { 30*0b57cec5SDimitry Andric return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); 31*0b57cec5SDimitry Andric } 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) { 34*0b57cec5SDimitry Andric assert(T->isOpenCLSpecificType() && 35*0b57cec5SDimitry Andric "Not an OpenCL specific type!"); 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric llvm::LLVMContext& Ctx = CGM.getLLVMContext(); 38*0b57cec5SDimitry Andric uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace( 39*0b57cec5SDimitry Andric CGM.getContext().getOpenCLTypeAddrSpace(T)); 40*0b57cec5SDimitry Andric switch (cast<BuiltinType>(T)->getKind()) { 41*0b57cec5SDimitry Andric default: 42*0b57cec5SDimitry Andric llvm_unreachable("Unexpected opencl builtin type!"); 43*0b57cec5SDimitry Andric return nullptr; 44*0b57cec5SDimitry Andric #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ 45*0b57cec5SDimitry Andric case BuiltinType::Id: \ 46*0b57cec5SDimitry Andric return llvm::PointerType::get( \ 47*0b57cec5SDimitry Andric llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \ 48*0b57cec5SDimitry Andric AddrSpc); 49*0b57cec5SDimitry Andric #include "clang/Basic/OpenCLImageTypes.def" 50*0b57cec5SDimitry Andric case BuiltinType::OCLSampler: 51*0b57cec5SDimitry Andric return getSamplerType(T); 52*0b57cec5SDimitry Andric case BuiltinType::OCLEvent: 53*0b57cec5SDimitry Andric return llvm::PointerType::get( 54*0b57cec5SDimitry Andric llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc); 55*0b57cec5SDimitry Andric case BuiltinType::OCLClkEvent: 56*0b57cec5SDimitry Andric return llvm::PointerType::get( 57*0b57cec5SDimitry Andric llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc); 58*0b57cec5SDimitry Andric case BuiltinType::OCLQueue: 59*0b57cec5SDimitry Andric return llvm::PointerType::get( 60*0b57cec5SDimitry Andric llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc); 61*0b57cec5SDimitry Andric case BuiltinType::OCLReserveID: 62*0b57cec5SDimitry Andric return llvm::PointerType::get( 63*0b57cec5SDimitry Andric llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc); 64*0b57cec5SDimitry Andric #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ 65*0b57cec5SDimitry Andric case BuiltinType::Id: \ 66*0b57cec5SDimitry Andric return llvm::PointerType::get( \ 67*0b57cec5SDimitry Andric llvm::StructType::create(Ctx, "opencl." #ExtType), AddrSpc); 68*0b57cec5SDimitry Andric #include "clang/Basic/OpenCLExtensionTypes.def" 69*0b57cec5SDimitry Andric } 70*0b57cec5SDimitry Andric } 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) { 73*0b57cec5SDimitry Andric if (T->isReadOnly()) 74*0b57cec5SDimitry Andric return getPipeType(T, "opencl.pipe_ro_t", PipeROTy); 75*0b57cec5SDimitry Andric else 76*0b57cec5SDimitry Andric return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy); 77*0b57cec5SDimitry Andric } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name, 80*0b57cec5SDimitry Andric llvm::Type *&PipeTy) { 81*0b57cec5SDimitry Andric if (!PipeTy) 82*0b57cec5SDimitry Andric PipeTy = llvm::PointerType::get(llvm::StructType::create( 83*0b57cec5SDimitry Andric CGM.getLLVMContext(), Name), 84*0b57cec5SDimitry Andric CGM.getContext().getTargetAddressSpace( 85*0b57cec5SDimitry Andric CGM.getContext().getOpenCLTypeAddrSpace(T))); 86*0b57cec5SDimitry Andric return PipeTy; 87*0b57cec5SDimitry Andric } 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) { 90*0b57cec5SDimitry Andric if (!SamplerTy) 91*0b57cec5SDimitry Andric SamplerTy = llvm::PointerType::get(llvm::StructType::create( 92*0b57cec5SDimitry Andric CGM.getLLVMContext(), "opencl.sampler_t"), 93*0b57cec5SDimitry Andric CGM.getContext().getTargetAddressSpace( 94*0b57cec5SDimitry Andric CGM.getContext().getOpenCLTypeAddrSpace(T))); 95*0b57cec5SDimitry Andric return SamplerTy; 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) { 99*0b57cec5SDimitry Andric const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>(); 100*0b57cec5SDimitry Andric // The type of the last (implicit) argument to be passed. 101*0b57cec5SDimitry Andric llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext()); 102*0b57cec5SDimitry Andric unsigned TypeSize = CGM.getContext() 103*0b57cec5SDimitry Andric .getTypeSizeInChars(PipeTy->getElementType()) 104*0b57cec5SDimitry Andric .getQuantity(); 105*0b57cec5SDimitry Andric return llvm::ConstantInt::get(Int32Ty, TypeSize, false); 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) { 109*0b57cec5SDimitry Andric const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>(); 110*0b57cec5SDimitry Andric // The type of the last (implicit) argument to be passed. 111*0b57cec5SDimitry Andric llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext()); 112*0b57cec5SDimitry Andric unsigned TypeSize = CGM.getContext() 113*0b57cec5SDimitry Andric .getTypeAlignInChars(PipeTy->getElementType()) 114*0b57cec5SDimitry Andric .getQuantity(); 115*0b57cec5SDimitry Andric return llvm::ConstantInt::get(Int32Ty, TypeSize, false); 116*0b57cec5SDimitry Andric } 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() { 119*0b57cec5SDimitry Andric assert(CGM.getLangOpts().OpenCL); 120*0b57cec5SDimitry Andric return llvm::IntegerType::getInt8PtrTy( 121*0b57cec5SDimitry Andric CGM.getLLVMContext(), 122*0b57cec5SDimitry Andric CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic)); 123*0b57cec5SDimitry Andric } 124*0b57cec5SDimitry Andric 125*0b57cec5SDimitry Andric // Get the block literal from an expression derived from the block expression. 126*0b57cec5SDimitry Andric // OpenCL v2.0 s6.12.5: 127*0b57cec5SDimitry Andric // Block variable declarations are implicitly qualified with const. Therefore 128*0b57cec5SDimitry Andric // all block variables must be initialized at declaration time and may not be 129*0b57cec5SDimitry Andric // reassigned. 130*0b57cec5SDimitry Andric static const BlockExpr *getBlockExpr(const Expr *E) { 131*0b57cec5SDimitry Andric const Expr *Prev = nullptr; // to make sure we do not stuck in infinite loop. 132*0b57cec5SDimitry Andric while(!isa<BlockExpr>(E) && E != Prev) { 133*0b57cec5SDimitry Andric Prev = E; 134*0b57cec5SDimitry Andric E = E->IgnoreCasts(); 135*0b57cec5SDimitry Andric if (auto DR = dyn_cast<DeclRefExpr>(E)) { 136*0b57cec5SDimitry Andric E = cast<VarDecl>(DR->getDecl())->getInit(); 137*0b57cec5SDimitry Andric } 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric return cast<BlockExpr>(E); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric /// Record emitted llvm invoke function and llvm block literal for the 143*0b57cec5SDimitry Andric /// corresponding block expression. 144*0b57cec5SDimitry Andric void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E, 145*0b57cec5SDimitry Andric llvm::Function *InvokeF, 146*0b57cec5SDimitry Andric llvm::Value *Block) { 147*0b57cec5SDimitry Andric assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() && 148*0b57cec5SDimitry Andric "Block expression emitted twice"); 149*0b57cec5SDimitry Andric assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function"); 150*0b57cec5SDimitry Andric assert(Block->getType()->isPointerTy() && "Invalid block literal type"); 151*0b57cec5SDimitry Andric EnqueuedBlockMap[E].InvokeFunc = InvokeF; 152*0b57cec5SDimitry Andric EnqueuedBlockMap[E].BlockArg = Block; 153*0b57cec5SDimitry Andric EnqueuedBlockMap[E].Kernel = nullptr; 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) { 157*0b57cec5SDimitry Andric return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc; 158*0b57cec5SDimitry Andric } 159*0b57cec5SDimitry Andric 160*0b57cec5SDimitry Andric CGOpenCLRuntime::EnqueuedBlockInfo 161*0b57cec5SDimitry Andric CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) { 162*0b57cec5SDimitry Andric CGF.EmitScalarExpr(E); 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric // The block literal may be assigned to a const variable. Chasing down 165*0b57cec5SDimitry Andric // to get the block literal. 166*0b57cec5SDimitry Andric const BlockExpr *Block = getBlockExpr(E); 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() && 169*0b57cec5SDimitry Andric "Block expression not emitted"); 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric // Do not emit the block wrapper again if it has been emitted. 172*0b57cec5SDimitry Andric if (EnqueuedBlockMap[Block].Kernel) { 173*0b57cec5SDimitry Andric return EnqueuedBlockMap[Block]; 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel( 177*0b57cec5SDimitry Andric CGF, EnqueuedBlockMap[Block].InvokeFunc, 178*0b57cec5SDimitry Andric EnqueuedBlockMap[Block].BlockArg->stripPointerCasts()); 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric // The common part of the post-processing of the kernel goes here. 181*0b57cec5SDimitry Andric F->addFnAttr(llvm::Attribute::NoUnwind); 182*0b57cec5SDimitry Andric F->setCallingConv( 183*0b57cec5SDimitry Andric CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel)); 184*0b57cec5SDimitry Andric EnqueuedBlockMap[Block].Kernel = F; 185*0b57cec5SDimitry Andric return EnqueuedBlockMap[Block]; 186*0b57cec5SDimitry Andric } 187