UnsignedArgument<"ZDim">];
}
+def WorkGroupSizeHint : InheritableAttr {
+ let Spellings = [GNU<"work_group_size_hint">];
+ let Args = [UnsignedArgument<"XDim">,
+ UnsignedArgument<"YDim">,
+ UnsignedArgument<"ZDim">];
+}
+
def InitPriority : InheritableAttr {
let Spellings = [GNU<"init_priority">];
let Args = [UnsignedArgument<"Priority">];
def err_invalid_conversion_between_ext_vectors : Error<
"invalid conversion between ext-vector type %0 and %1">;
+def warn_duplicate_attribute : Warning<
+ "attribute %0 is already applied with different parameters">;
+
// Type
def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">;
def warn_receiver_forward_class : Warning<
Builder.CreateCall(MCountFn);
}
+void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
+ llvm::Function *Fn)
+{
+ if (!FD->hasAttr<OpenCLKernelAttr>())
+ return;
+
+ llvm::LLVMContext &Context = getLLVMContext();
+
+ llvm::SmallVector <llvm::Value*, 5> kernelMDArgs;
+ kernelMDArgs.push_back(Fn);
+
+ if (FD->hasAttr<WorkGroupSizeHintAttr>()) {
+ llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
+ attrMDArgs.push_back(llvm::MDString::get(Context, "work_group_size_hint"));
+ WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>();
+ llvm::Type *iTy = llvm::IntegerType::get(Context, 32);
+ attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
+ llvm::APInt(32, (uint64_t)attr->getXDim())));
+ attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
+ llvm::APInt(32, (uint64_t)attr->getYDim())));
+ attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
+ llvm::APInt(32, (uint64_t)attr->getZDim())));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
+ }
+
+ if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) {
+ llvm::SmallVector <llvm::Value*, 5> attrMDArgs;
+ attrMDArgs.push_back(llvm::MDString::get(Context, "reqd_work_group_size"));
+ ReqdWorkGroupSizeAttr *attr = FD->getAttr<ReqdWorkGroupSizeAttr>();
+ llvm::Type *iTy = llvm::IntegerType::get(Context, 32);
+ attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
+ llvm::APInt(32, (uint64_t)attr->getXDim())));
+ attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
+ llvm::APInt(32, (uint64_t)attr->getYDim())));
+ attrMDArgs.push_back(llvm::ConstantInt::get(iTy,
+ llvm::APInt(32, (uint64_t)attr->getZDim())));
+ kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs));
+ }
+
+ llvm::MDNode *kernelMDNode = llvm::MDNode::get(Context, kernelMDArgs);
+ llvm::NamedMDNode *OpenCLKernelMetadata =
+ CGM.getModule().getOrInsertNamedMetadata("opencl.kernels");
+ OpenCLKernelMetadata->addOperand(kernelMDNode);
+}
+
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
if (getContext().getLangOpts().OpenCL) {
// Add metadata for a kernel function.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
- if (FD->hasAttr<OpenCLKernelAttr>()) {
- llvm::LLVMContext &Context = getLLVMContext();
- llvm::NamedMDNode *OpenCLMetadata =
- CGM.getModule().getOrInsertNamedMetadata("opencl.kernels");
-
- llvm::Value *Op = Fn;
- OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Op));
- }
+ EmitOpenCLKernelMetadata(FD, Fn);
}
llvm::BasicBlock *EntryBB = createBasicBlock("entry", CurFn);
llvm::BasicBlock *TerminateHandler;
llvm::BasicBlock *TrapBB;
+ /// Add a kernel metadata node to the named metadata node 'opencl.kernels'.
+ /// In the kernel metadata node, reference the kernel function and metadata
+ /// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2):
+ /// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string
+ /// "work_group_size_hint", and three 32-bit integers X, Y and Z.
+ /// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string
+ /// "reqd_work_group_size", and three 32-bit integers X, Y and Z.
+ void EmitOpenCLKernelMetadata(const FunctionDecl *FD,
+ llvm::Function *Fn);
+
public:
CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext=false);
~CodeGenFunction();
D->addAttr(::new (S.Context) WeakImportAttr(Attr.getRange(), S.Context));
}
-static void handleReqdWorkGroupSize(Sema &S, Decl *D,
- const AttributeList &Attr) {
+// Handles reqd_work_group_size and work_group_size_hint.
+static void handleWorkGroupSize(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ assert(Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
+ || Attr.getKind() == AttributeList::AT_WorkGroupSizeHint);
+
// Attribute has 3 arguments.
- if (!checkAttributeNumArgs(S, Attr, 3))
- return;
+ if (!checkAttributeNumArgs(S, Attr, 3)) return;
unsigned WGSize[3];
for (unsigned i = 0; i < 3; ++i) {
if (E->isTypeDependent() || E->isValueDependent() ||
!E->isIntegerConstantExpr(ArgNum, S.Context)) {
S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
- << "reqd_work_group_size" << E->getSourceRange();
+ << Attr.getName()->getName() << E->getSourceRange();
return;
}
WGSize[i] = (unsigned) ArgNum.getZExtValue();
}
- D->addAttr(::new (S.Context) ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
- WGSize[0], WGSize[1],
- WGSize[2]));
+
+ if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize
+ && D->hasAttr<ReqdWorkGroupSizeAttr>()) {
+ ReqdWorkGroupSizeAttr *A = D->getAttr<ReqdWorkGroupSizeAttr>();
+ if (!(A->getXDim() == WGSize[0] &&
+ A->getYDim() == WGSize[1] &&
+ A->getZDim() == WGSize[2])) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+ Attr.getName();
+ }
+ }
+
+ if (Attr.getKind() == AttributeList::AT_WorkGroupSizeHint
+ && D->hasAttr<WorkGroupSizeHintAttr>()) {
+ WorkGroupSizeHintAttr *A = D->getAttr<WorkGroupSizeHintAttr>();
+ if (!(A->getXDim() == WGSize[0] &&
+ A->getYDim() == WGSize[1] &&
+ A->getZDim() == WGSize[2])) {
+ S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) <<
+ Attr.getName();
+ }
+ }
+
+ if (Attr.getKind() == AttributeList::AT_ReqdWorkGroupSize)
+ D->addAttr(::new (S.Context)
+ ReqdWorkGroupSizeAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2]));
+ else
+ D->addAttr(::new (S.Context)
+ WorkGroupSizeHintAttr(Attr.getRange(), S.Context,
+ WGSize[0], WGSize[1], WGSize[2]));
}
SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range,
case AttributeList::AT_CFReturnsRetained:
handleNSReturnsRetainedAttr(S, D, Attr); break;
+ case AttributeList::AT_WorkGroupSizeHint:
case AttributeList::AT_ReqdWorkGroupSize:
- handleReqdWorkGroupSize(S, D, Attr); break;
+ handleWorkGroupSize(S, D, Attr); break;
case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr); break;
--- /dev/null
+// RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+kernel __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {}
+
+kernel __attribute__((work_group_size_hint(8,16,32))) void kernel2(float4 a) {}
+
+// CHECK: opencl.kernels = !{[[MDNODE0:![0-9]+]], [[MDNODE3:![0-9]+]]}
+
+// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE2:![0-9]+]]}
+// CHECK: [[MDNODE2]] = metadata !{metadata !"reqd_work_group_size", i32 1, i32 2, i32 4}
+// CHECK: [[MDNODE3]] = metadata !{void (<4 x float>)* @kernel2, metadata [[MDNODE5:![0-9]+]]}
+// CHECK: [[MDNODE5]] = metadata !{metadata !"work_group_size_hint", i32 8, i32 16, i32 32}