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