r360342 - [OpenCL] Make global ctor init function a kernel
Anastasia Stulova via cfe-commits
cfe-commits at lists.llvm.org
Thu May 9 06:55:44 PDT 2019
Author: stulova
Date: Thu May 9 06:55:44 2019
New Revision: 360342
URL: http://llvm.org/viewvc/llvm-project?rev=360342&view=rev
Log:
[OpenCL] Make global ctor init function a kernel
We need to be able to enqueue internal function that initializes
global constructors on the host side. Therefore it has to be
converted to a kernel.
This change factors out common logic for adding kernel metadata
and moves it from CodeGenFunction to CodeGenModule in order to
make it accessible for the extra use case.
Differential revision: https://reviews.llvm.org/D61488
Added:
cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl
Modified:
cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.cpp
cfe/trunk/lib/CodeGen/CodeGenModule.h
Modified: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDeclCXX.cpp?rev=360342&r1=360341&r2=360342&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp Thu May 9 06:55:44 2019
@@ -580,6 +580,19 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, CXXGlobalInits);
AddGlobalCtor(Fn);
+ // In OpenCL global init functions must be converted to kernels in order to
+ // be able to launch them from the host.
+ // FIXME: Some more work might be needed to handle destructors correctly.
+ // Current initialization function makes use of function pointers callbacks.
+ // We can't support function pointers especially between host and device.
+ // However it seems global destruction has little meaning without any
+ // dynamic resource allocation on the device and program scope variables are
+ // destroyed by the runtime when program is released.
+ if (getLangOpts().OpenCL) {
+ GenOpenCLArgMetadata(Fn);
+ Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL);
+ }
+
CXXGlobalInits.clear();
}
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=360342&r1=360341&r2=360342&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu May 9 06:55:44 2019
@@ -536,205 +536,6 @@ CodeGenFunction::DecodeAddrUsedInPrologu
"decoded_addr");
}
-static void removeImageAccessQualifier(std::string& TyName) {
- std::string ReadOnlyQual("__read_only");
- std::string::size_type ReadOnlyPos = TyName.find(ReadOnlyQual);
- if (ReadOnlyPos != std::string::npos)
- // "+ 1" for the space after access qualifier.
- TyName.erase(ReadOnlyPos, ReadOnlyQual.size() + 1);
- else {
- std::string WriteOnlyQual("__write_only");
- std::string::size_type WriteOnlyPos = TyName.find(WriteOnlyQual);
- if (WriteOnlyPos != std::string::npos)
- TyName.erase(WriteOnlyPos, WriteOnlyQual.size() + 1);
- else {
- std::string ReadWriteQual("__read_write");
- std::string::size_type ReadWritePos = TyName.find(ReadWriteQual);
- if (ReadWritePos != std::string::npos)
- TyName.erase(ReadWritePos, ReadWriteQual.size() + 1);
- }
- }
-}
-
-// Returns the address space id that should be produced to the
-// kernel_arg_addr_space metadata. This is always fixed to the ids
-// as specified in the SPIR 2.0 specification in order to differentiate
-// for example in clGetKernelArgInfo() implementation between the address
-// spaces with targets without unique mapping to the OpenCL address spaces
-// (basically all single AS CPUs).
-static unsigned ArgInfoAddressSpace(LangAS AS) {
- switch (AS) {
- case LangAS::opencl_global: return 1;
- case LangAS::opencl_constant: return 2;
- case LangAS::opencl_local: return 3;
- case LangAS::opencl_generic: return 4; // Not in SPIR 2.0 specs.
- default:
- return 0; // Assume private.
- }
-}
-
-// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
-// information in the program executable. The argument information stored
-// includes the argument name, its type, the address and access qualifiers used.
-static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn,
- CodeGenModule &CGM, llvm::LLVMContext &Context,
- CGBuilderTy &Builder, ASTContext &ASTCtx) {
- // Create MDNodes that represent the kernel arg metadata.
- // Each MDNode is a list in the form of "key", N number of values which is
- // the same number of values as their are kernel arguments.
-
- const PrintingPolicy &Policy = ASTCtx.getPrintingPolicy();
-
- // MDNode for the kernel argument address space qualifiers.
- SmallVector<llvm::Metadata *, 8> addressQuals;
-
- // MDNode for the kernel argument access qualifiers (images only).
- SmallVector<llvm::Metadata *, 8> accessQuals;
-
- // MDNode for the kernel argument type names.
- SmallVector<llvm::Metadata *, 8> argTypeNames;
-
- // MDNode for the kernel argument base type names.
- SmallVector<llvm::Metadata *, 8> argBaseTypeNames;
-
- // MDNode for the kernel argument type qualifiers.
- SmallVector<llvm::Metadata *, 8> argTypeQuals;
-
- // MDNode for the kernel argument names.
- SmallVector<llvm::Metadata *, 8> argNames;
-
- for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
- const ParmVarDecl *parm = FD->getParamDecl(i);
- QualType ty = parm->getType();
- std::string typeQuals;
-
- if (ty->isPointerType()) {
- QualType pointeeTy = ty->getPointeeType();
-
- // Get address qualifier.
- addressQuals.push_back(llvm::ConstantAsMetadata::get(Builder.getInt32(
- ArgInfoAddressSpace(pointeeTy.getAddressSpace()))));
-
- // Get argument type name.
- std::string typeName =
- pointeeTy.getUnqualifiedType().getAsString(Policy) + "*";
-
- // Turn "unsigned type" to "utype"
- std::string::size_type pos = typeName.find("unsigned");
- if (pointeeTy.isCanonical() && pos != std::string::npos)
- typeName.erase(pos+1, 8);
-
- argTypeNames.push_back(llvm::MDString::get(Context, typeName));
-
- std::string baseTypeName =
- pointeeTy.getUnqualifiedType().getCanonicalType().getAsString(
- Policy) +
- "*";
-
- // Turn "unsigned type" to "utype"
- pos = baseTypeName.find("unsigned");
- if (pos != std::string::npos)
- baseTypeName.erase(pos+1, 8);
-
- argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
-
- // Get argument type qualifiers:
- if (ty.isRestrictQualified())
- typeQuals = "restrict";
- if (pointeeTy.isConstQualified() ||
- (pointeeTy.getAddressSpace() == LangAS::opencl_constant))
- typeQuals += typeQuals.empty() ? "const" : " const";
- if (pointeeTy.isVolatileQualified())
- typeQuals += typeQuals.empty() ? "volatile" : " volatile";
- } else {
- uint32_t AddrSpc = 0;
- bool isPipe = ty->isPipeType();
- if (ty->isImageType() || isPipe)
- AddrSpc = ArgInfoAddressSpace(LangAS::opencl_global);
-
- addressQuals.push_back(
- llvm::ConstantAsMetadata::get(Builder.getInt32(AddrSpc)));
-
- // Get argument type name.
- std::string typeName;
- if (isPipe)
- typeName = ty.getCanonicalType()->getAs<PipeType>()->getElementType()
- .getAsString(Policy);
- else
- typeName = ty.getUnqualifiedType().getAsString(Policy);
-
- // Turn "unsigned type" to "utype"
- std::string::size_type pos = typeName.find("unsigned");
- if (ty.isCanonical() && pos != std::string::npos)
- typeName.erase(pos+1, 8);
-
- std::string baseTypeName;
- if (isPipe)
- baseTypeName = ty.getCanonicalType()->getAs<PipeType>()
- ->getElementType().getCanonicalType()
- .getAsString(Policy);
- else
- baseTypeName =
- ty.getUnqualifiedType().getCanonicalType().getAsString(Policy);
-
- // Remove access qualifiers on images
- // (as they are inseparable from type in clang implementation,
- // but OpenCL spec provides a special query to get access qualifier
- // via clGetKernelArgInfo with CL_KERNEL_ARG_ACCESS_QUALIFIER):
- if (ty->isImageType()) {
- removeImageAccessQualifier(typeName);
- removeImageAccessQualifier(baseTypeName);
- }
-
- argTypeNames.push_back(llvm::MDString::get(Context, typeName));
-
- // Turn "unsigned type" to "utype"
- pos = baseTypeName.find("unsigned");
- if (pos != std::string::npos)
- baseTypeName.erase(pos+1, 8);
-
- argBaseTypeNames.push_back(llvm::MDString::get(Context, baseTypeName));
-
- if (isPipe)
- typeQuals = "pipe";
- }
-
- argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals));
-
- // Get image and pipe access qualifier:
- if (ty->isImageType()|| ty->isPipeType()) {
- const Decl *PDecl = parm;
- if (auto *TD = dyn_cast<TypedefType>(ty))
- PDecl = TD->getDecl();
- const OpenCLAccessAttr *A = PDecl->getAttr<OpenCLAccessAttr>();
- if (A && A->isWriteOnly())
- accessQuals.push_back(llvm::MDString::get(Context, "write_only"));
- else if (A && A->isReadWrite())
- accessQuals.push_back(llvm::MDString::get(Context, "read_write"));
- else
- accessQuals.push_back(llvm::MDString::get(Context, "read_only"));
- } else
- accessQuals.push_back(llvm::MDString::get(Context, "none"));
-
- // Get argument name.
- argNames.push_back(llvm::MDString::get(Context, parm->getName()));
- }
-
- Fn->setMetadata("kernel_arg_addr_space",
- llvm::MDNode::get(Context, addressQuals));
- Fn->setMetadata("kernel_arg_access_qual",
- llvm::MDNode::get(Context, accessQuals));
- Fn->setMetadata("kernel_arg_type",
- llvm::MDNode::get(Context, argTypeNames));
- Fn->setMetadata("kernel_arg_base_type",
- llvm::MDNode::get(Context, argBaseTypeNames));
- Fn->setMetadata("kernel_arg_type_qual",
- llvm::MDNode::get(Context, argTypeQuals));
- if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata)
- Fn->setMetadata("kernel_arg_name",
- llvm::MDNode::get(Context, argNames));
-}
-
void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
llvm::Function *Fn)
{
@@ -743,7 +544,7 @@ void CodeGenFunction::EmitOpenCLKernelMe
llvm::LLVMContext &Context = getLLVMContext();
- GenOpenCLArgMetadata(FD, Fn, CGM, Context, Builder, getContext());
+ CGM.GenOpenCLArgMetadata(Fn, FD, this);
if (const VecTypeHintAttr *A = FD->getAttr<VecTypeHintAttr>()) {
QualType HintQTy = A->getTypeHint();
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=360342&r1=360341&r2=360342&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu May 9 06:55:44 2019
@@ -1193,6 +1193,212 @@ void CodeGenModule::SetLLVMFunctionAttri
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
+static void removeImageAccessQualifier(std::string& TyName) {
+ std::string ReadOnlyQual("__read_only");
+ std::string::size_type ReadOnlyPos = TyName.find(ReadOnlyQual);
+ if (ReadOnlyPos != std::string::npos)
+ // "+ 1" for the space after access qualifier.
+ TyName.erase(ReadOnlyPos, ReadOnlyQual.size() + 1);
+ else {
+ std::string WriteOnlyQual("__write_only");
+ std::string::size_type WriteOnlyPos = TyName.find(WriteOnlyQual);
+ if (WriteOnlyPos != std::string::npos)
+ TyName.erase(WriteOnlyPos, WriteOnlyQual.size() + 1);
+ else {
+ std::string ReadWriteQual("__read_write");
+ std::string::size_type ReadWritePos = TyName.find(ReadWriteQual);
+ if (ReadWritePos != std::string::npos)
+ TyName.erase(ReadWritePos, ReadWriteQual.size() + 1);
+ }
+ }
+}
+
+// Returns the address space id that should be produced to the
+// kernel_arg_addr_space metadata. This is always fixed to the ids
+// as specified in the SPIR 2.0 specification in order to differentiate
+// for example in clGetKernelArgInfo() implementation between the address
+// spaces with targets without unique mapping to the OpenCL address spaces
+// (basically all single AS CPUs).
+static unsigned ArgInfoAddressSpace(LangAS AS) {
+ switch (AS) {
+ case LangAS::opencl_global: return 1;
+ case LangAS::opencl_constant: return 2;
+ case LangAS::opencl_local: return 3;
+ case LangAS::opencl_generic: return 4; // Not in SPIR 2.0 specs.
+ default:
+ return 0; // Assume private.
+ }
+}
+
+void CodeGenModule::GenOpenCLArgMetadata(llvm::Function *Fn,
+ const FunctionDecl *FD,
+ CodeGenFunction *CGF) {
+ assert(((FD && CGF) || (!FD && !CGF)) &&
+ "Incorrect use - FD and CGF should either be both null or not!");
+ // Create MDNodes that represent the kernel arg metadata.
+ // Each MDNode is a list in the form of "key", N number of values which is
+ // the same number of values as their are kernel arguments.
+
+ const PrintingPolicy &Policy = Context.getPrintingPolicy();
+
+ // MDNode for the kernel argument address space qualifiers.
+ SmallVector<llvm::Metadata *, 8> addressQuals;
+
+ // MDNode for the kernel argument access qualifiers (images only).
+ SmallVector<llvm::Metadata *, 8> accessQuals;
+
+ // MDNode for the kernel argument type names.
+ SmallVector<llvm::Metadata *, 8> argTypeNames;
+
+ // MDNode for the kernel argument base type names.
+ SmallVector<llvm::Metadata *, 8> argBaseTypeNames;
+
+ // MDNode for the kernel argument type qualifiers.
+ SmallVector<llvm::Metadata *, 8> argTypeQuals;
+
+ // MDNode for the kernel argument names.
+ SmallVector<llvm::Metadata *, 8> argNames;
+
+ if (FD && CGF)
+ for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) {
+ const ParmVarDecl *parm = FD->getParamDecl(i);
+ QualType ty = parm->getType();
+ std::string typeQuals;
+
+ if (ty->isPointerType()) {
+ QualType pointeeTy = ty->getPointeeType();
+
+ // Get address qualifier.
+ addressQuals.push_back(
+ llvm::ConstantAsMetadata::get(CGF->Builder.getInt32(
+ ArgInfoAddressSpace(pointeeTy.getAddressSpace()))));
+
+ // Get argument type name.
+ std::string typeName =
+ pointeeTy.getUnqualifiedType().getAsString(Policy) + "*";
+
+ // Turn "unsigned type" to "utype"
+ std::string::size_type pos = typeName.find("unsigned");
+ if (pointeeTy.isCanonical() && pos != std::string::npos)
+ typeName.erase(pos + 1, 8);
+
+ argTypeNames.push_back(llvm::MDString::get(VMContext, typeName));
+
+ std::string baseTypeName =
+ pointeeTy.getUnqualifiedType().getCanonicalType().getAsString(
+ Policy) +
+ "*";
+
+ // Turn "unsigned type" to "utype"
+ pos = baseTypeName.find("unsigned");
+ if (pos != std::string::npos)
+ baseTypeName.erase(pos + 1, 8);
+
+ argBaseTypeNames.push_back(
+ llvm::MDString::get(VMContext, baseTypeName));
+
+ // Get argument type qualifiers:
+ if (ty.isRestrictQualified())
+ typeQuals = "restrict";
+ if (pointeeTy.isConstQualified() ||
+ (pointeeTy.getAddressSpace() == LangAS::opencl_constant))
+ typeQuals += typeQuals.empty() ? "const" : " const";
+ if (pointeeTy.isVolatileQualified())
+ typeQuals += typeQuals.empty() ? "volatile" : " volatile";
+ } else {
+ uint32_t AddrSpc = 0;
+ bool isPipe = ty->isPipeType();
+ if (ty->isImageType() || isPipe)
+ AddrSpc = ArgInfoAddressSpace(LangAS::opencl_global);
+
+ addressQuals.push_back(
+ llvm::ConstantAsMetadata::get(CGF->Builder.getInt32(AddrSpc)));
+
+ // Get argument type name.
+ std::string typeName;
+ if (isPipe)
+ typeName = ty.getCanonicalType()
+ ->getAs<PipeType>()
+ ->getElementType()
+ .getAsString(Policy);
+ else
+ typeName = ty.getUnqualifiedType().getAsString(Policy);
+
+ // Turn "unsigned type" to "utype"
+ std::string::size_type pos = typeName.find("unsigned");
+ if (ty.isCanonical() && pos != std::string::npos)
+ typeName.erase(pos + 1, 8);
+
+ std::string baseTypeName;
+ if (isPipe)
+ baseTypeName = ty.getCanonicalType()
+ ->getAs<PipeType>()
+ ->getElementType()
+ .getCanonicalType()
+ .getAsString(Policy);
+ else
+ baseTypeName =
+ ty.getUnqualifiedType().getCanonicalType().getAsString(Policy);
+
+ // Remove access qualifiers on images
+ // (as they are inseparable from type in clang implementation,
+ // but OpenCL spec provides a special query to get access qualifier
+ // via clGetKernelArgInfo with CL_KERNEL_ARG_ACCESS_QUALIFIER):
+ if (ty->isImageType()) {
+ removeImageAccessQualifier(typeName);
+ removeImageAccessQualifier(baseTypeName);
+ }
+
+ argTypeNames.push_back(llvm::MDString::get(VMContext, typeName));
+
+ // Turn "unsigned type" to "utype"
+ pos = baseTypeName.find("unsigned");
+ if (pos != std::string::npos)
+ baseTypeName.erase(pos + 1, 8);
+
+ argBaseTypeNames.push_back(
+ llvm::MDString::get(VMContext, baseTypeName));
+
+ if (isPipe)
+ typeQuals = "pipe";
+ }
+
+ argTypeQuals.push_back(llvm::MDString::get(VMContext, typeQuals));
+
+ // Get image and pipe access qualifier:
+ if (ty->isImageType() || ty->isPipeType()) {
+ const Decl *PDecl = parm;
+ if (auto *TD = dyn_cast<TypedefType>(ty))
+ PDecl = TD->getDecl();
+ const OpenCLAccessAttr *A = PDecl->getAttr<OpenCLAccessAttr>();
+ if (A && A->isWriteOnly())
+ accessQuals.push_back(llvm::MDString::get(VMContext, "write_only"));
+ else if (A && A->isReadWrite())
+ accessQuals.push_back(llvm::MDString::get(VMContext, "read_write"));
+ else
+ accessQuals.push_back(llvm::MDString::get(VMContext, "read_only"));
+ } else
+ accessQuals.push_back(llvm::MDString::get(VMContext, "none"));
+
+ // Get argument name.
+ argNames.push_back(llvm::MDString::get(VMContext, parm->getName()));
+ }
+
+ Fn->setMetadata("kernel_arg_addr_space",
+ llvm::MDNode::get(VMContext, addressQuals));
+ Fn->setMetadata("kernel_arg_access_qual",
+ llvm::MDNode::get(VMContext, accessQuals));
+ Fn->setMetadata("kernel_arg_type",
+ llvm::MDNode::get(VMContext, argTypeNames));
+ Fn->setMetadata("kernel_arg_base_type",
+ llvm::MDNode::get(VMContext, argBaseTypeNames));
+ Fn->setMetadata("kernel_arg_type_qual",
+ llvm::MDNode::get(VMContext, argTypeQuals));
+ if (getCodeGenOpts().EmitOpenCLArgMetadata)
+ Fn->setMetadata("kernel_arg_name",
+ llvm::MDNode::get(VMContext, argNames));
+}
+
/// Determines whether the language options require us to model
/// unwind exceptions. We treat -fexceptions as mandating this
/// except under the fragile ObjC ABI with only ObjC exceptions
Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=360342&r1=360341&r2=360342&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu May 9 06:55:44 2019
@@ -1315,6 +1315,19 @@ public:
llvm::Value *
createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF);
+ /// OpenCL v1.2 s5.6.4.6 allows the compiler to store kernel argument
+ /// information in the program executable. The argument information stored
+ /// includes the argument name, its type, the address and access qualifiers
+ /// used. This helper can be used to generate metadata for source code kernel
+ /// function as well as generated implicitly kernels. If a kernel is generated
+ /// implicitly null value has to be passed to the last two parameters,
+ /// otherwise all parameters must have valid non-null values.
+ /// \param FN is a pointer to IR function being generated.
+ /// \param FD is a pointer to function declaration if any.
+ /// \param CGF is a pointer to CodeGenFunction that generates this function.
+ void GenOpenCLArgMetadata(llvm::Function *Fn, const FunctionDecl *FD=nullptr,
+ CodeGenFunction *CGF=nullptr);
+
/// Get target specific null pointer.
/// \param T is the LLVM type of the null pointer.
/// \param QT is the clang QualType of the null pointer.
Added: cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl?rev=360342&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl (added)
+++ cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl Thu May 9 06:55:44 2019
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -triple spir -cl-std=c++ -emit-llvm -O0 -o - | FileCheck %s
+
+struct S {
+ S() {}
+};
+
+S s;
+
+//CHECK: define internal spir_kernel void @_GLOBAL__sub_I_{{.*}}!kernel_arg_addr_space [[ARGMD:![0-9]+]] !kernel_arg_access_qual [[ARGMD]] !kernel_arg_type [[ARGMD]] !kernel_arg_base_type [[ARGMD]] !kernel_arg_type_qual [[ARGMD]]
+// Check that parameters are empty.
+//CHECK: [[ARGMD]] = !{}
More information about the cfe-commits
mailing list