Index: cfe/trunk/lib/CodeGen/CGDeclCXX.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGDeclCXX.cpp +++ cfe/trunk/lib/CodeGen/CGDeclCXX.cpp @@ -580,6 +580,19 @@ 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(); } Index: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp @@ -536,205 +536,6 @@ "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 addressQuals; - - // MDNode for the kernel argument access qualifiers (images only). - SmallVector accessQuals; - - // MDNode for the kernel argument type names. - SmallVector argTypeNames; - - // MDNode for the kernel argument base type names. - SmallVector argBaseTypeNames; - - // MDNode for the kernel argument type qualifiers. - SmallVector argTypeQuals; - - // MDNode for the kernel argument names. - SmallVector 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()->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() - ->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(ty)) - PDecl = TD->getDecl(); - const OpenCLAccessAttr *A = PDecl->getAttr(); - 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 @@ llvm::LLVMContext &Context = getLLVMContext(); - GenOpenCLArgMetadata(FD, Fn, CGM, Context, Builder, getContext()); + CGM.GenOpenCLArgMetadata(Fn, FD, this); if (const VecTypeHintAttr *A = FD->getAttr()) { QualType HintQTy = A->getTypeHint(); Index: cfe/trunk/lib/CodeGen/CodeGenModule.h =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h +++ cfe/trunk/lib/CodeGen/CodeGenModule.h @@ -1315,6 +1315,19 @@ 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. Index: cfe/trunk/lib/CodeGen/CodeGenModule.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp @@ -1193,6 +1193,212 @@ F->setCallingConv(static_cast(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 addressQuals; + + // MDNode for the kernel argument access qualifiers (images only). + SmallVector accessQuals; + + // MDNode for the kernel argument type names. + SmallVector argTypeNames; + + // MDNode for the kernel argument base type names. + SmallVector argBaseTypeNames; + + // MDNode for the kernel argument type qualifiers. + SmallVector argTypeQuals; + + // MDNode for the kernel argument names. + SmallVector 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() + ->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() + ->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(ty)) + PDecl = TD->getDecl(); + const OpenCLAccessAttr *A = PDecl->getAttr(); + 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 Index: cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl =================================================================== --- cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl +++ cfe/trunk/test/CodeGenOpenCLCXX/global_init.cl @@ -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]] = !{}