1//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This provides an abstract class for OpenCL code generation. Concrete
10// subclasses of this implement code generation for specific OpenCL
11// runtime libraries.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CGOpenCLRuntime.h"
16#include "CodeGenFunction.h"
17#include "TargetInfo.h"
18#include "clang/CodeGen/ConstantInitBuilder.h"
19#include "llvm/IR/DerivedTypes.h"
20#include "llvm/IR/GlobalValue.h"
21#include <assert.h>
22
23using namespace clang;
24using namespace CodeGen;
25
26CGOpenCLRuntime::~CGOpenCLRuntime() {}
27
28void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
29 const VarDecl &D) {
30 return CGF.EmitStaticVarDecl(D, Linkage: llvm::GlobalValue::InternalLinkage);
31}
32
33llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
34 assert(T->isOpenCLSpecificType() && "Not an OpenCL specific type!");
35
36 // Check if the target has a specific translation for this type first.
37 if (llvm::Type *TransTy = CGM.getTargetCodeGenInfo().getOpenCLType(CGM, T))
38 return TransTy;
39
40 if (T->isSamplerT())
41 return getSamplerType(T);
42
43 return getPointerType(T);
44}
45
46llvm::PointerType *CGOpenCLRuntime::getPointerType(const Type *T) {
47 uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
48 AS: CGM.getContext().getOpenCLTypeAddrSpace(T));
49 return llvm::PointerType::get(C&: CGM.getLLVMContext(), AddressSpace: AddrSpc);
50}
51
52llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
53 if (llvm::Type *PipeTy = CGM.getTargetCodeGenInfo().getOpenCLType(CGM, T))
54 return PipeTy;
55
56 if (!PipeTy)
57 PipeTy = getPointerType(T);
58 return PipeTy;
59}
60
61llvm::Type *CGOpenCLRuntime::getSamplerType(const Type *T) {
62 if (SamplerTy)
63 return SamplerTy;
64
65 if (llvm::Type *TransTy = CGM.getTargetCodeGenInfo().getOpenCLType(
66 CGM, T: CGM.getContext().OCLSamplerTy.getTypePtr()))
67 SamplerTy = TransTy;
68 else
69 SamplerTy = getPointerType(T);
70 return SamplerTy;
71}
72
73llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
74 const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
75 // The type of the last (implicit) argument to be passed.
76 llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(C&: CGM.getLLVMContext());
77 unsigned TypeSize = CGM.getContext()
78 .getTypeSizeInChars(T: PipeTy->getElementType())
79 .getQuantity();
80 return llvm::ConstantInt::get(Ty: Int32Ty, V: TypeSize, IsSigned: false);
81}
82
83llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
84 const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>();
85 // The type of the last (implicit) argument to be passed.
86 llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(C&: CGM.getLLVMContext());
87 unsigned TypeSize = CGM.getContext()
88 .getTypeAlignInChars(T: PipeTy->getElementType())
89 .getQuantity();
90 return llvm::ConstantInt::get(Ty: Int32Ty, V: TypeSize, IsSigned: false);
91}
92
93llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
94 assert(CGM.getLangOpts().OpenCL);
95 return llvm::PointerType::get(
96 C&: CGM.getLLVMContext(),
97 AddressSpace: CGM.getContext().getTargetAddressSpace(AS: LangAS::opencl_generic));
98}
99
100// Get the block literal from an expression derived from the block expression.
101// OpenCL v2.0 s6.12.5:
102// Block variable declarations are implicitly qualified with const. Therefore
103// all block variables must be initialized at declaration time and may not be
104// reassigned.
105static const BlockExpr *getBlockExpr(const Expr *E) {
106 const Expr *Prev = nullptr; // to make sure we do not stuck in infinite loop.
107 while(!isa<BlockExpr>(Val: E) && E != Prev) {
108 Prev = E;
109 E = E->IgnoreCasts();
110 if (auto DR = dyn_cast<DeclRefExpr>(Val: E)) {
111 E = cast<VarDecl>(Val: DR->getDecl())->getInit();
112 }
113 }
114 return cast<BlockExpr>(Val: E);
115}
116
117/// Record emitted llvm invoke function and llvm block literal for the
118/// corresponding block expression.
119void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
120 llvm::Function *InvokeF,
121 llvm::Value *Block, llvm::Type *BlockTy) {
122 assert(!EnqueuedBlockMap.contains(E) && "Block expression emitted twice");
123 assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
124 assert(Block->getType()->isPointerTy() && "Invalid block literal type");
125 EnqueuedBlockInfo &BlockInfo = EnqueuedBlockMap[E];
126 BlockInfo.InvokeFunc = InvokeF;
127 BlockInfo.BlockArg = Block;
128 BlockInfo.BlockTy = BlockTy;
129 BlockInfo.KernelHandle = nullptr;
130}
131
132llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) {
133 return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc;
134}
135
136CGOpenCLRuntime::EnqueuedBlockInfo
137CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
138 CGF.EmitScalarExpr(E);
139
140 // The block literal may be assigned to a const variable. Chasing down
141 // to get the block literal.
142 const BlockExpr *Block = getBlockExpr(E);
143
144 auto It = EnqueuedBlockMap.find(Val: Block);
145 assert(It != EnqueuedBlockMap.end() && "Block expression not emitted");
146 EnqueuedBlockInfo &BlockInfo = It->second;
147
148 // Do not emit the block wrapper again if it has been emitted.
149 if (BlockInfo.KernelHandle) {
150 return BlockInfo;
151 }
152
153 auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
154 CGF, BlockInvokeFunc: BlockInfo.InvokeFunc, BlockTy: BlockInfo.BlockTy);
155
156 // The common part of the post-processing of the kernel goes here.
157 BlockInfo.KernelHandle = F;
158 return BlockInfo;
159}
160