#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!");
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 getPointerType(T, "opencl." #ImgType "_" #Suffix "_t");
#include "clang/Basic/OpenCLImageTypes.def"
case BuiltinType::OCLSampler:
return getSamplerType(T);
case BuiltinType::OCLEvent:
return getPointerType(T, "opencl.event_t");
case BuiltinType::OCLClkEvent:
return getPointerType(T, "opencl.clk_event_t");
case BuiltinType::OCLQueue:
return getPointerType(T, "opencl.queue_t");
case BuiltinType::OCLReserveID:
return getPointerType(T, "opencl.reserve_id_t");
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id: \
return getPointerType(T, "opencl." #ExtType);
#include "clang/Basic/OpenCLExtensionTypes.def"
}
}
llvm::PointerType *CGOpenCLRuntime::getPointerType(const Type *T,
StringRef Name) {
auto I = CachedTys.find(Name);
if (I != CachedTys.end())
return I->second;
llvm::LLVMContext &Ctx = CGM.getLLVMContext();
uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
CGM.getContext().getOpenCLTypeAddrSpace(T));
auto *PTy =
llvm::PointerType::get(llvm::StructType::create(Ctx, Name), AddrSpc);
CachedTys[Name] = PTy;
return PTy;
}
llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
if (T->isReadOnly())
return getPipeType(T, "opencl.pipe_ro_t", PipeROTy);
else
return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy);
}
llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name,
llvm::Type *&PipeTy) {
if (!PipeTy)
PipeTy = llvm::PointerType::get(llvm::StructType::create(
CGM.getLLVMContext(), Name),
CGM.getContext().getTargetAddressSpace(
CGM.getContext().getOpenCLTypeAddrSpace(T)));
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()->castAs<PipeType>();
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()->castAs<PipeType>();
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));
}
static const BlockExpr *getBlockExpr(const Expr *E) {
const Expr *Prev = nullptr; while(!isa<BlockExpr>(E) && E != Prev) {
Prev = E;
E = E->IgnoreCasts();
if (auto DR = dyn_cast<DeclRefExpr>(E)) {
E = cast<VarDecl>(DR->getDecl())->getInit();
}
}
return cast<BlockExpr>(E);
}
void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
llvm::Function *InvokeF,
llvm::Value *Block, llvm::Type *BlockTy) {
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].BlockTy = BlockTy;
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");
if (EnqueuedBlockMap[Block].Kernel) {
return EnqueuedBlockMap[Block];
}
auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
CGF, EnqueuedBlockMap[Block].InvokeFunc, EnqueuedBlockMap[Block].BlockTy);
F->addFnAttr(llvm::Attribute::NoUnwind);
F->setCallingConv(
CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
EnqueuedBlockMap[Block].Kernel = F;
return EnqueuedBlockMap[Block];
}