Files
clang-p2996/clang/lib/CodeGen/CGOpenCLRuntime.cpp
Yaxun Liu cb35e9fa94 [OpenCL] Remove block invoke function from emitted block literal struct
OpenCL runtime tracks the invoke function emitted for
any block expression. Due to restrictions on blocks in
OpenCL (v2.0 s6.12.5), it is always possible to know the
block invoke function when emitting call of block expression
or __enqueue_kernel builtin functions. Since __enqueu_kernel
already has an argument for the invoke function, it is redundant
to have invoke function member in the llvm block literal structure.

This patch removes invoke function from the llvm block literal
structure. It also removes the bitcast of block invoke function
to the generic block literal type which is useless for OpenCL.

This will save some space for the kernel argument, and also
eliminate some store instructions.

Differential Revision: https://reviews.llvm.org/D43783

llvm-svn: 326937
2018-03-07 19:32:58 +00:00

176 lines
6.5 KiB
C++

//===----- CGOpenCLRuntime.cpp - Interface to OpenCL Runtimes -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This provides an abstract class for OpenCL code generation. Concrete
// subclasses of this implement code generation for specific OpenCL
// runtime libraries.
//
//===----------------------------------------------------------------------===//
#include "CGOpenCLRuntime.h"
#include "CodeGenFunction.h"
#include "TargetInfo.h"
#include "clang/CodeGen/ConstantInitBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalValue.h"
#include <assert.h>
using namespace clang;
using namespace CodeGen;
CGOpenCLRuntime::~CGOpenCLRuntime() {}
void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
const VarDecl &D) {
return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
}
llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
assert(T->isOpenCLSpecificType() &&
"Not an OpenCL specific type!");
llvm::LLVMContext& Ctx = CGM.getLLVMContext();
uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
CGM.getContext().getOpenCLTypeAddrSpace(T));
switch (cast<BuiltinType>(T)->getKind()) {
default:
llvm_unreachable("Unexpected opencl builtin type!");
return nullptr;
#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id: \
return llvm::PointerType::get( \
llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \
AddrSpc);
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
return getSamplerType(T);
case BuiltinType::OCLEvent:
return llvm::PointerType::get(
llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc);
case BuiltinType::OCLClkEvent:
return llvm::PointerType::get(
llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc);
case BuiltinType::OCLQueue:
return llvm::PointerType::get(
llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc);
case BuiltinType::OCLReserveID:
return llvm::PointerType::get(
llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc);
}
}
llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
if (!PipeTy){
uint32_t PipeAddrSpc = CGM.getContext().getTargetAddressSpace(
CGM.getContext().getOpenCLTypeAddrSpace(T));
PipeTy = llvm::PointerType::get(llvm::StructType::create(
CGM.getLLVMContext(), "opencl.pipe_t"), PipeAddrSpc);
}
return PipeTy;
}
llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
if (!SamplerTy)
SamplerTy = llvm::PointerType::get(llvm::StructType::create(
CGM.getLLVMContext(), "opencl.sampler_t"),
CGM.getContext().getTargetAddressSpace(
CGM.getContext().getOpenCLTypeAddrSpace(T)));
return SamplerTy;
}
llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) {
const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
// The type of the last (implicit) argument to be passed.
llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
unsigned TypeSize = CGM.getContext()
.getTypeSizeInChars(PipeTy->getElementType())
.getQuantity();
return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
}
llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
// The type of the last (implicit) argument to be passed.
llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
unsigned TypeSize = CGM.getContext()
.getTypeAlignInChars(PipeTy->getElementType())
.getQuantity();
return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
}
llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
assert(CGM.getLangOpts().OpenCL);
return llvm::IntegerType::getInt8PtrTy(
CGM.getLLVMContext(),
CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
}
// Get the block literal from an expression derived from the block expression.
// OpenCL v2.0 s6.12.5:
// Block variable declarations are implicitly qualified with const. Therefore
// all block variables must be initialized at declaration time and may not be
// reassigned.
static const BlockExpr *getBlockExpr(const Expr *E) {
if (auto Cast = dyn_cast<CastExpr>(E)) {
E = Cast->getSubExpr();
}
if (auto DR = dyn_cast<DeclRefExpr>(E)) {
E = cast<VarDecl>(DR->getDecl())->getInit();
}
E = E->IgnoreImplicit();
if (auto Cast = dyn_cast<CastExpr>(E)) {
E = Cast->getSubExpr();
}
return cast<BlockExpr>(E);
}
/// Record emitted llvm invoke function and llvm block literal for the
/// corresponding block expression.
void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
llvm::Function *InvokeF,
llvm::Value *Block) {
assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() &&
"Block expression emitted twice");
assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
assert(Block->getType()->isPointerTy() && "Invalid block literal type");
EnqueuedBlockMap[E].InvokeFunc = InvokeF;
EnqueuedBlockMap[E].BlockArg = Block;
EnqueuedBlockMap[E].Kernel = nullptr;
}
llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) {
return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc;
}
CGOpenCLRuntime::EnqueuedBlockInfo
CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
CGF.EmitScalarExpr(E);
const BlockExpr *Block = getBlockExpr(E);
assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() &&
"Block expression not emitted");
// Do not emit the block wrapper again if it has been emitted.
if (EnqueuedBlockMap[Block].Kernel) {
return EnqueuedBlockMap[Block];
}
auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
CGF, EnqueuedBlockMap[Block].InvokeFunc,
EnqueuedBlockMap[Block].BlockArg->stripPointerCasts());
// The common part of the post-processing of the kernel goes here.
F->addFnAttr(llvm::Attribute::NoUnwind);
F->setCallingConv(
CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
EnqueuedBlockMap[Block].Kernel = F;
return EnqueuedBlockMap[Block];
}