diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 88cf0f9644..47905bf8b1 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -333,7 +333,6 @@ def OpenCLKernel : Attr { def OpenCLImageAccess : Attr { let Spellings = [GNU<"opencl_image_access">]; let Args = [IntArgument<"Access">]; - let ASTNode = 0; } def Deprecated : InheritableAttr { diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 04de55d517..a43148cce7 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/Basic/OpenCL.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/IR/DataLayout.h" @@ -285,27 +286,117 @@ void CodeGenFunction::EmitMCountInstrumentation() { // 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. -// FIXME: Add type, address, and access qualifiers. static void GenOpenCLArgMetadata(const FunctionDecl *FD, llvm::Function *Fn, CodeGenModule &CGM,llvm::LLVMContext &Context, - SmallVector &kernelMDArgs) { - - // Create MDNodes that represents the kernel arg metadata. + SmallVector &kernelMDArgs, + 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. + // MDNode for the kernel argument address space qualifiers. + SmallVector addressQuals; + addressQuals.push_back(llvm::MDString::get(Context, "kernel_arg_addr_space")); + + // MDNode for the kernel argument access qualifiers (images only). + SmallVector accessQuals; + accessQuals.push_back(llvm::MDString::get(Context, "kernel_arg_access_qual")); + + // MDNode for the kernel argument type names. + SmallVector argTypeNames; + argTypeNames.push_back(llvm::MDString::get(Context, "kernel_arg_type")); + + // MDNode for the kernel argument type qualifiers. + SmallVector argTypeQuals; + argTypeQuals.push_back(llvm::MDString::get(Context, "kernel_arg_type_qual")); + // MDNode for the kernel argument names. SmallVector argNames; argNames.push_back(llvm::MDString::get(Context, "kernel_arg_name")); 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(Builder.getInt32(ASTCtx.getTargetAddressSpace( + pointeeTy.getAddressSpace()))); + + // Get argument type name. + std::string typeName = pointeeTy.getUnqualifiedType().getAsString() + "*"; + + // Turn "unsigned type" to "utype" + std::string::size_type pos = typeName.find("unsigned"); + if(pos != std::string::npos) { + typeName = typeName.substr(0, pos+1) + + typeName.substr(pos+9, typeName.size()); + } + + argTypeNames.push_back(llvm::MDString::get(Context, typeName)); + + // Get argument type qualifiers: + if (ty.isRestrictQualified()) + typeQuals = "restrict"; + if (pointeeTy.isConstQualified() || + (pointeeTy.getAddressSpace() == LangAS::opencl_constant)) + if (typeQuals != "") + typeQuals += " const"; + else + typeQuals += "const"; + if (pointeeTy.isVolatileQualified()) + if (typeQuals != "") + typeQuals += " volatile"; + else + typeQuals += "volatile"; + } else { + addressQuals.push_back(Builder.getInt32(0)); + + // Get argument type name. + std::string typeName = ty.getUnqualifiedType().getAsString(); + + // Turn "unsigned type" to "utype" + std::string::size_type pos = typeName.find("unsigned"); + if(pos != std::string::npos) { + typeName = typeName.substr(0, pos+1) + + typeName.substr(pos+9, typeName.size()); + } + + argTypeNames.push_back(llvm::MDString::get(Context, typeName)); + + // Get argument type qualifiers: + if (ty.isConstQualified()) + typeQuals = "const"; + if (ty.isVolatileQualified()) + if (typeQuals != "") + typeQuals += " volatile"; + else + typeQuals += "volatile"; + } + + argTypeQuals.push_back(llvm::MDString::get(Context, typeQuals)); + + // Get image access qualifier: + if (ty->isImageType()) { + if (parm->hasAttr() && + parm->getAttr()->getAccess() == CLIA_write_only) + accessQuals.push_back(llvm::MDString::get(Context, "write_only")); + 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())); - } - // Add MDNode to the list of all metadata. + + kernelMDArgs.push_back(llvm::MDNode::get(Context, addressQuals)); + kernelMDArgs.push_back(llvm::MDNode::get(Context, accessQuals)); + kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeNames)); + kernelMDArgs.push_back(llvm::MDNode::get(Context, argTypeQuals)); kernelMDArgs.push_back(llvm::MDNode::get(Context, argNames)); } @@ -321,7 +412,8 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, kernelMDArgs.push_back(Fn); if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata) - GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs); + GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs, + Builder, getContext()); if (FD->hasAttr()) { VecTypeHintAttr *attr = FD->getAttr(); diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index c6e28c3e61..77c7dc59c8 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -3997,6 +3997,22 @@ static void handleOpenCLKernelAttr(Sema &S, Decl *D, const AttributeList &Attr){ D->addAttr(::new (S.Context) OpenCLKernelAttr(Attr.getRange(), S.Context)); } +static void handleOpenCLImageAccessAttr(Sema &S, Decl *D, const AttributeList &Attr){ + assert(!Attr.isInvalid()); + + Expr *E = Attr.getArg(0); + llvm::APSInt ArgNum(32); + if (E->isTypeDependent() || E->isValueDependent() || + !E->isIntegerConstantExpr(ArgNum, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << Attr.getName()->getName() << E->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) OpenCLImageAccessAttr( + Attr.getRange(), S.Context, ArgNum.getZExtValue())); +} + bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD) { if (attr.isInvalid()) @@ -4687,7 +4703,6 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_IBOutletCollection: handleIBOutletCollection(S, D, Attr); break; case AttributeList::AT_AddressSpace: - case AttributeList::AT_OpenCLImageAccess: case AttributeList::AT_ObjCGC: case AttributeList::AT_VectorSize: case AttributeList::AT_NeonVectorType: @@ -4866,6 +4881,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_OpenCLKernel: handleOpenCLKernelAttr(S, D, Attr); break; + case AttributeList::AT_OpenCLImageAccess: + handleOpenCLImageAccessAttr(S, D, Attr); + break; // Microsoft attributes: case AttributeList::AT_MsStruct: diff --git a/test/CodeGenOpenCL/kernel-arg-info.cl b/test/CodeGenOpenCL/kernel-arg-info.cl index 7e35a33564..c7e20491a9 100644 --- a/test/CodeGenOpenCL/kernel-arg-info.cl +++ b/test/CodeGenOpenCL/kernel-arg-info.cl @@ -1,7 +1,20 @@ -// RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -cl-kernel-arg-info -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s -kernel void foo(global int *X, int Y, int anotherArg) { +kernel void foo(__global int * restrict X, const int Y, + volatile int anotherArg, __constant float * restrict Z) { *X = Y + anotherArg; } -// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X", metadata !"Y", metadata !"anotherArg"} +// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 1, i32 0, i32 0, i32 2} +// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"none", metadata !"none", metadata !"none", metadata !"none"} +// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"int*", metadata !"int", metadata !"int", metadata !"float*"} +// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"restrict", metadata !"const", metadata !"volatile", metadata !"restrict const"} +// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"X", metadata !"Y", metadata !"anotherArg", metadata !"Z"} + +kernel void foo2(read_only image1d_t img1, image2d_t img2, write_only image2d_array_t img3) { +} +// CHECK: metadata !{metadata !"kernel_arg_addr_space", i32 0, i32 0, i32 0} +// CHECK: metadata !{metadata !"kernel_arg_access_qual", metadata !"read_only", metadata !"read_only", metadata !"write_only"} +// CHECK: metadata !{metadata !"kernel_arg_type", metadata !"image1d_t", metadata !"image2d_t", metadata !"image2d_array_t"} +// CHECK: metadata !{metadata !"kernel_arg_type_qual", metadata !"", metadata !"", metadata !""} +// CHECK: metadata !{metadata !"kernel_arg_name", metadata !"img1", metadata !"img2", metadata !"img3"}