diff options
-rw-r--r-- | clang/include/clang/Basic/Attr.td | 3 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | clang/include/clang/Sema/AttributeList.h | 52 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 17 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 3 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 47 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 33 | ||||
-rw-r--r-- | clang/test/CodeGenOpenCL/kernel-attributes.cl | 12 |
8 files changed, 156 insertions, 15 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3d4c3e026e2..53f83e1acf3 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -720,8 +720,9 @@ def VectorSize : Attr { let ASTNode = 0; } -def VecTypeHint : IgnoredAttr { +def VecTypeHint : InheritableAttr { let Spellings = [GNU<"vec_type_hint">]; + let Args = [TypeArgument<"TypeHint">, SourceLocArgument<"TypeLoc">]; } def Visibility : InheritableAttr { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 44dec5a2c81..21618920470 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1644,6 +1644,8 @@ def err_attribute_too_few_arguments : Error< "attribute takes at least %0 argument%s0">; def err_attribute_missing_parameter_name : Error< "attribute requires unquoted parameter">; +def err_attribute_requires_type_parameter : Error< + "%0 attribute requires type parameter">; def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; def err_attribute_bad_neon_vector_size : Error< "Neon vector size must be 64 or 128 bits">; @@ -1672,6 +1674,8 @@ def err_attribute_argument_outof_range : Error< def err_init_priority_object_attr : Error< "can only use 'init_priority' attribute on file-scope definitions " "of objects of class type">; +def err_attribute_argument_vec_type_hint : Error< + "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">; def err_attribute_argument_n_not_int : Error< "'%0' attribute requires parameter %1 to be an integer constant">; def err_attribute_argument_n_not_string : Error< diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index a8d3eb4fb75..0f0d2185b0c 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -144,6 +144,14 @@ private: return *reinterpret_cast<const TypeTagForDatatypeData *>(this + 1); } + ParsedType &getTypeBuffer() { + return *reinterpret_cast<ParsedType *>(this + 1); + } + + const ParsedType &getTypeBuffer() const { + return *reinterpret_cast<const ParsedType *>(this + 1); + } + AttributeList(const AttributeList &) LLVM_DELETED_FUNCTION; void operator=(const AttributeList &) LLVM_DELETED_FUNCTION; void operator delete(void *) LLVM_DELETED_FUNCTION; @@ -208,6 +216,20 @@ private: AttrKind = getKind(getName(), getScopeName(), syntaxUsed); } + /// Constructor for attributes with a single type argument. + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + ParsedType typeArg, Syntax syntaxUsed) + : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), + AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), + EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed), Invalid(false), + UsedAsTypeAttr(false), IsAvailability(false), + IsTypeTagForDatatype(false), NextInPosition(0), NextInPool(0) { + new (&getTypeBuffer()) ParsedType(typeArg); + AttrKind = getKind(getName(), getScopeName(), syntaxUsed); + } + friend class AttributePool; friend class AttributeFactory; @@ -352,6 +374,11 @@ public: return getTypeTagForDatatypeDataSlot().MustBeNull; } + const ParsedType &getTypeArg() const { + assert(getKind() == AT_VecTypeHint && "Not a type attribute"); + return getTypeBuffer(); + } + /// \brief Get an index into the attribute spelling list /// defined in Attr.td. This index is used by an attribute /// to pretty print itself. @@ -509,6 +536,18 @@ public: matchingCType, layoutCompatible, mustBeNull, syntax)); } + + AttributeList *createTypeAttribute( + IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + ParsedType typeArg, AttributeList::Syntax syntaxUsed) { + void *memory = allocate(sizeof(AttributeList) + sizeof(void *)); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + parmName, parmLoc, + typeArg, syntaxUsed)); + } }; /// addAttributeLists - Add two AttributeLists together @@ -651,6 +690,19 @@ public: return attr; } + /// Add an attribute with a single type argument. + AttributeList * + addNewTypeAttr(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + ParsedType typeArg, AttributeList::Syntax syntaxUsed) { + AttributeList *attr = + pool.createTypeAttribute(attrName, attrRange, scopeName, scopeLoc, + parmName, parmLoc, typeArg, syntaxUsed); + add(attr); + return attr; + } + AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name, SourceLocation loc, int arg) { AttributeList *attr = diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 5e8bce974ba..bd4c98e35b1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -323,6 +323,23 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD, if (CGM.getCodeGenOpts().EmitOpenCLArgMetadata) GenOpenCLArgMetadata(FD, Fn, CGM, Context, kernelMDArgs); + if (FD->hasAttr<VecTypeHintAttr>()) { + VecTypeHintAttr *attr = FD->getAttr<VecTypeHintAttr>(); + QualType hintQTy = attr->getTypeHint(); + const ExtVectorType *hintEltQTy = hintQTy->getAs<ExtVectorType>(); + bool isSignedInteger = + hintQTy->isSignedIntegerType() || + (hintEltQTy && hintEltQTy->getElementType()->isSignedIntegerType()); + llvm::Value *attrMDArgs[] = { + llvm::MDString::get(Context, "vec_type_hint"), + llvm::UndefValue::get(CGM.getTypes().ConvertType(attr->getTypeHint())), + llvm::ConstantInt::get( + llvm::IntegerType::get(Context, 32), + llvm::APInt(32, (uint64_t)(isSignedInteger ? 1 : 0))) + }; + kernelMDArgs.push_back(llvm::MDNode::get(Context, attrMDArgs)); + } + if (FD->hasAttr<WorkGroupSizeHintAttr>()) { WorkGroupSizeHintAttr *attr = FD->getAttr<WorkGroupSizeHintAttr>(); llvm::Value *attrMDArgs[] = { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 2be8dcc4a65..0155f033e6f 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -1214,6 +1214,9 @@ private: /// 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 vec_type_hint(<type>) qualifier contains string + /// "vec_type_hint", an undefined value of the <type> data type, + /// and a Boolean that is true if the <type> is integer and signed. /// - 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 diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 6ab1540134a..bf5c078b714 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -214,6 +214,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, SourceLocation ParmLoc; bool BuiltinType = false; + TypeResult T; + SourceRange TypeRange; + bool TypeParsed = false; + switch (Tok.getKind()) { case tok::kw_char: case tok::kw_wchar_t: @@ -232,12 +236,17 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, case tok::kw_void: case tok::kw_typeof: // __attribute__(( vec_type_hint(char) )) - // FIXME: Don't just discard the builtin type token. - ConsumeToken(); BuiltinType = true; + T = ParseTypeName(&TypeRange); + TypeParsed = true; break; case tok::identifier: + if (AttrName->isStr("vec_type_hint")) { + T = ParseTypeName(&TypeRange); + TypeParsed = true; + break; + } ParmName = Tok.getIdentifierInfo(); ParmLoc = ConsumeToken(); break; @@ -247,8 +256,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, } ExprVector ArgExprs; + bool isInvalid = false; + bool isParmType = false; - if (!BuiltinType && + if (!BuiltinType && !AttrName->isStr("vec_type_hint") && (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { // Eat the comma. if (ParmLoc.isValid()) @@ -283,17 +294,33 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, Diag(Tok, diag::err_iboutletcollection_with_protocol); SkipUntil(tok::r_paren, false, true); // skip until ')' } + } else if (AttrName->isStr("vec_type_hint")) { + if (T.get() && !T.isInvalid()) + isParmType = true; + else { + if (Tok.is(tok::identifier)) + ConsumeToken(); + if (TypeParsed) + isInvalid = true; + } } SourceLocation RParen = Tok.getLocation(); - if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen) && + !isInvalid) { SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; - AttributeList *attr = - Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), - ScopeName, ScopeLoc, ParmName, ParmLoc, - ArgExprs.data(), ArgExprs.size(), Syntax); - if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection) - Diag(Tok, diag::err_iboutletcollection_builtintype); + if (isParmType) { + QualType ParmType = Sema::GetTypeFromParser(T.get()); + Attrs.addNewTypeAttr(AttrName, SourceRange(AttrLoc, RParen), ScopeName, + ScopeLoc, ParmName, ParmLoc, T.get(), Syntax); + } else { + AttributeList *attr = Attrs.addNew( + AttrName, SourceRange(AttrLoc, RParen), ScopeName, ScopeLoc, ParmName, + ParmLoc, ArgExprs.data(), ArgExprs.size(), Syntax); + if (BuiltinType && + attr->getKind() == AttributeList::AT_IBOutletCollection) + Diag(Tok, diag::err_iboutletcollection_builtintype); + } } } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 2778d6e6484..c9ccf80191e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -2769,6 +2769,36 @@ static void handleWorkGroupSize(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleVecTypeHint(Sema &S, Decl *D, const AttributeList &Attr) { + assert(Attr.getKind() == AttributeList::AT_VecTypeHint); + + // Attribute has 1 argument. + if (!checkAttributeNumArgs(S, Attr, 1)) + return; + + QualType ParmType = S.GetTypeFromParser(Attr.getTypeArg()); + + if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() && + (ParmType->isBooleanType() || + !ParmType->isIntegralType(S.getASTContext()))) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_vec_type_hint) + << ParmType; + return; + } + + if (Attr.getKind() == AttributeList::AT_VecTypeHint && + D->hasAttr<VecTypeHintAttr>()) { + VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>(); + if (A->getTypeHint() != ParmType) { + S.Diag(Attr.getLoc(), diag::warn_duplicate_attribute) << Attr.getName(); + return; + } + } + + D->addAttr(::new (S.Context) VecTypeHintAttr(Attr.getLoc(), S.Context, + ParmType, Attr.getLoc())); +} + SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex) { @@ -4750,6 +4780,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ReqdWorkGroupSize: handleWorkGroupSize(S, D, Attr); break; + case AttributeList::AT_VecTypeHint: + handleVecTypeHint(S, D, Attr); break; + case AttributeList::AT_InitPriority: handleInitPriorityAttr(S, D, Attr); break; diff --git a/clang/test/CodeGenOpenCL/kernel-attributes.cl b/clang/test/CodeGenOpenCL/kernel-attributes.cl index de16a414531..1166f9384fa 100644 --- a/clang/test/CodeGenOpenCL/kernel-attributes.cl +++ b/clang/test/CodeGenOpenCL/kernel-attributes.cl @@ -1,12 +1,16 @@ // RUN: %clang_cc1 -emit-llvm -O0 -o - %s | FileCheck %s -kernel __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {} +typedef unsigned int uint4 __attribute__((ext_vector_type(4))); -kernel __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {} +kernel __attribute__((vec_type_hint(int))) __attribute__((reqd_work_group_size(1,2,4))) void kernel1(int a) {} + +kernel __attribute__((vec_type_hint(uint4))) __attribute__((work_group_size_hint(8,16,32))) void kernel2(int a) {} // CHECK: opencl.kernels = !{[[MDNODE0:![0-9]+]], [[MDNODE3:![0-9]+]]} -// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE2:![0-9]+]]} +// CHECK: [[MDNODE0]] = metadata !{void (i32)* @kernel1, metadata [[MDNODE1:![0-9]+]], metadata [[MDNODE2:![0-9]+]]} +// CHECK: [[MDNODE1]] = metadata !{metadata !"vec_type_hint", i32 undef, i32 1} // CHECK: [[MDNODE2]] = metadata !{metadata !"reqd_work_group_size", i32 1, i32 2, i32 4} -// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE5:![0-9]+]]} +// CHECK: [[MDNODE3]] = metadata !{void (i32)* @kernel2, metadata [[MDNODE4:![0-9]+]], metadata [[MDNODE5:![0-9]+]]} +// CHECK: [[MDNODE4]] = metadata !{metadata !"vec_type_hint", <4 x i32> undef, i32 0} // CHECK: [[MDNODE5]] = metadata !{metadata !"work_group_size_hint", i32 8, i32 16, i32 32} |