CGOpenCLRuntime.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. #include "CGOpenCLRuntime.h"
  15. #include "CodeGenFunction.h"
  16. #include "TargetInfo.h"
  17. #include "clang/CodeGen/ConstantInitBuilder.h"
  18. #include "llvm/IR/DerivedTypes.h"
  19. #include "llvm/IR/GlobalValue.h"
  20. #include <assert.h>
  21. using namespace clang;
  22. using namespace CodeGen;
  23. CGOpenCLRuntime::~CGOpenCLRuntime() {}
  24. void CGOpenCLRuntime::EmitWorkGroupLocalVarDecl(CodeGenFunction &CGF,
  25. const VarDecl &D) {
  26. return CGF.EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage);
  27. }
  28. llvm::Type *CGOpenCLRuntime::convertOpenCLSpecificType(const Type *T) {
  29. assert(T->isOpenCLSpecificType() &&
  30. "Not an OpenCL specific type!");
  31. llvm::LLVMContext& Ctx = CGM.getLLVMContext();
  32. uint32_t AddrSpc = CGM.getContext().getTargetAddressSpace(
  33. CGM.getContext().getOpenCLTypeAddrSpace(T));
  34. switch (cast<BuiltinType>(T)->getKind()) {
  35. default:
  36. llvm_unreachable("Unexpected opencl builtin type!");
  37. return nullptr;
  38. #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
  39. case BuiltinType::Id: \
  40. return llvm::PointerType::get( \
  41. llvm::StructType::create(Ctx, "opencl." #ImgType "_" #Suffix "_t"), \
  42. AddrSpc);
  43. #include "clang/Basic/OpenCLImageTypes.def"
  44. case BuiltinType::OCLSampler:
  45. return getSamplerType(T);
  46. case BuiltinType::OCLEvent:
  47. return llvm::PointerType::get(
  48. llvm::StructType::create(Ctx, "opencl.event_t"), AddrSpc);
  49. case BuiltinType::OCLClkEvent:
  50. return llvm::PointerType::get(
  51. llvm::StructType::create(Ctx, "opencl.clk_event_t"), AddrSpc);
  52. case BuiltinType::OCLQueue:
  53. return llvm::PointerType::get(
  54. llvm::StructType::create(Ctx, "opencl.queue_t"), AddrSpc);
  55. case BuiltinType::OCLReserveID:
  56. return llvm::PointerType::get(
  57. llvm::StructType::create(Ctx, "opencl.reserve_id_t"), AddrSpc);
  58. #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
  59. case BuiltinType::Id: \
  60. return llvm::PointerType::get( \
  61. llvm::StructType::create(Ctx, "opencl." #ExtType), AddrSpc);
  62. #include "clang/Basic/OpenCLExtensionTypes.def"
  63. }
  64. }
  65. llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T) {
  66. if (T->isReadOnly())
  67. return getPipeType(T, "opencl.pipe_ro_t", PipeROTy);
  68. else
  69. return getPipeType(T, "opencl.pipe_wo_t", PipeWOTy);
  70. }
  71. llvm::Type *CGOpenCLRuntime::getPipeType(const PipeType *T, StringRef Name,
  72. llvm::Type *&PipeTy) {
  73. if (!PipeTy)
  74. PipeTy = llvm::PointerType::get(llvm::StructType::create(
  75. CGM.getLLVMContext(), Name),
  76. CGM.getContext().getTargetAddressSpace(
  77. CGM.getContext().getOpenCLTypeAddrSpace(T)));
  78. return PipeTy;
  79. }
  80. llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) {
  81. if (!SamplerTy)
  82. SamplerTy = llvm::PointerType::get(llvm::StructType::create(
  83. CGM.getLLVMContext(), "opencl.sampler_t"),
  84. CGM.getContext().getTargetAddressSpace(
  85. CGM.getContext().getOpenCLTypeAddrSpace(T)));
  86. return SamplerTy;
  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. llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) {
  98. const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>();
  99. // The type of the last (implicit) argument to be passed.
  100. llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext());
  101. unsigned TypeSize = CGM.getContext()
  102. .getTypeAlignInChars(PipeTy->getElementType())
  103. .getQuantity();
  104. return llvm::ConstantInt::get(Int32Ty, TypeSize, false);
  105. }
  106. llvm::PointerType *CGOpenCLRuntime::getGenericVoidPointerType() {
  107. assert(CGM.getLangOpts().OpenCL);
  108. return llvm::IntegerType::getInt8PtrTy(
  109. CGM.getLLVMContext(),
  110. CGM.getContext().getTargetAddressSpace(LangAS::opencl_generic));
  111. }
  112. // Get the block literal from an expression derived from the block expression.
  113. // OpenCL v2.0 s6.12.5:
  114. // Block variable declarations are implicitly qualified with const. Therefore
  115. // all block variables must be initialized at declaration time and may not be
  116. // reassigned.
  117. static const BlockExpr *getBlockExpr(const Expr *E) {
  118. const Expr *Prev = nullptr; // to make sure we do not stuck in infinite loop.
  119. while(!isa<BlockExpr>(E) && E != Prev) {
  120. Prev = E;
  121. E = E->IgnoreCasts();
  122. if (auto DR = dyn_cast<DeclRefExpr>(E)) {
  123. E = cast<VarDecl>(DR->getDecl())->getInit();
  124. }
  125. }
  126. return cast<BlockExpr>(E);
  127. }
  128. /// Record emitted llvm invoke function and llvm block literal for the
  129. /// corresponding block expression.
  130. void CGOpenCLRuntime::recordBlockInfo(const BlockExpr *E,
  131. llvm::Function *InvokeF,
  132. llvm::Value *Block) {
  133. assert(EnqueuedBlockMap.find(E) == EnqueuedBlockMap.end() &&
  134. "Block expression emitted twice");
  135. assert(isa<llvm::Function>(InvokeF) && "Invalid invoke function");
  136. assert(Block->getType()->isPointerTy() && "Invalid block literal type");
  137. EnqueuedBlockMap[E].InvokeFunc = InvokeF;
  138. EnqueuedBlockMap[E].BlockArg = Block;
  139. EnqueuedBlockMap[E].Kernel = nullptr;
  140. }
  141. llvm::Function *CGOpenCLRuntime::getInvokeFunction(const Expr *E) {
  142. return EnqueuedBlockMap[getBlockExpr(E)].InvokeFunc;
  143. }
  144. CGOpenCLRuntime::EnqueuedBlockInfo
  145. CGOpenCLRuntime::emitOpenCLEnqueuedBlock(CodeGenFunction &CGF, const Expr *E) {
  146. CGF.EmitScalarExpr(E);
  147. // The block literal may be assigned to a const variable. Chasing down
  148. // to get the block literal.
  149. const BlockExpr *Block = getBlockExpr(E);
  150. assert(EnqueuedBlockMap.find(Block) != EnqueuedBlockMap.end() &&
  151. "Block expression not emitted");
  152. // Do not emit the block wrapper again if it has been emitted.
  153. if (EnqueuedBlockMap[Block].Kernel) {
  154. return EnqueuedBlockMap[Block];
  155. }
  156. auto *F = CGF.getTargetHooks().createEnqueuedBlockKernel(
  157. CGF, EnqueuedBlockMap[Block].InvokeFunc,
  158. EnqueuedBlockMap[Block].BlockArg->stripPointerCasts());
  159. // The common part of the post-processing of the kernel goes here.
  160. F->addFnAttr(llvm::Attribute::NoUnwind);
  161. F->setCallingConv(
  162. CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel));
  163. EnqueuedBlockMap[Block].Kernel = F;
  164. return EnqueuedBlockMap[Block];
  165. }