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