forked from OSchip/llvm-project
[OpenCL] Generate metadata for opencl_unroll_hint attribute
Add support for opencl_unroll_hint attribute from OpenCL v2.0 s6.11.5. Reusing most of metadata generation from CGLoopInfo helper class. The code is based on Khronos OpenCL compiler: https://github.com/KhronosGroup/SPIR/tree/spirv-1.0 Patch by Liu Yaxun (Sam)! Differential Revision: http://reviews.llvm.org/D16686 llvm-svn: 261350
This commit is contained in:
parent
7e4ba3dc02
commit
6bdbcbb3d9
|
@ -656,6 +656,12 @@ def OpenCLKernel : InheritableAttr {
|
|||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def OpenCLUnrollHint : InheritableAttr {
|
||||
let Spellings = [GNU<"opencl_unroll_hint">];
|
||||
let Args = [UnsignedArgument<"UnrollHint">];
|
||||
let Documentation = [OpenCLUnrollHintDocs];
|
||||
}
|
||||
|
||||
// This attribute is both a type attribute, and a declaration attribute (for
|
||||
// parameter variables).
|
||||
def OpenCLImageAccess : Attr {
|
||||
|
|
|
@ -1567,6 +1567,19 @@ for further details including limitations of the unroll hints.
|
|||
}];
|
||||
}
|
||||
|
||||
def OpenCLUnrollHintDocs : Documentation {
|
||||
let Category = DocCatStmt;
|
||||
let Heading = "__attribute__((opencl_unroll_hint))";
|
||||
let Content = [{
|
||||
The opencl_unroll_hint attribute qualifier can be used to specify that a loop
|
||||
(for, while and do loops) can be unrolled. This attribute qualifier can be
|
||||
used to specify full unrolling or partial unrolling by a specified amount.
|
||||
This is a compiler hint and the compiler may ignore this directive. See
|
||||
`OpenCL v2.0 <https://www.khronos.org/registry/cl/specs/opencl-2.0.pdf>`_
|
||||
s6.11.5 for details.
|
||||
}];
|
||||
}
|
||||
|
||||
def DocOpenCLAddressSpaces : DocumentationCategory<"OpenCL Address Spaces"> {
|
||||
let Content = [{
|
||||
The address space qualifier may be used to specify the region of memory that is
|
||||
|
|
|
@ -902,6 +902,9 @@ def err_pragma_optimize_invalid_argument : Error<
|
|||
def err_pragma_optimize_extra_argument : Error<
|
||||
"unexpected extra argument '%0' to '#pragma clang optimize'">;
|
||||
|
||||
def err_opencl_unroll_hint_on_non_loop : Error<
|
||||
"OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements">;
|
||||
|
||||
// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1])
|
||||
def warn_pragma_expected_colon : Warning<
|
||||
"missing ':' after %0 - ignoring">, InGroup<IgnoredPragmas>;
|
||||
|
|
|
@ -2123,6 +2123,10 @@ def err_attribute_too_few_arguments : Error<
|
|||
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">;
|
||||
def err_attribute_requires_positive_integer : Error<
|
||||
"%0 attribute requires a positive integral compile time constant expression">;
|
||||
def err_attribute_requires_opencl_version : Error<
|
||||
"%0 attribute requires OpenCL version %1 or above">;
|
||||
def warn_unsupported_target_attribute
|
||||
: Warning<"Ignoring unsupported '%0' in the target attribute string">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
|
|
|
@ -2198,8 +2198,19 @@ private:
|
|||
SourceLocation SkipExtendedMicrosoftTypeAttributes();
|
||||
void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs);
|
||||
void ParseBorlandTypeAttributes(ParsedAttributes &attrs);
|
||||
void ParseOpenCLAttributes(ParsedAttributes &attrs);
|
||||
void ParseOpenCLKernelAttributes(ParsedAttributes &attrs);
|
||||
void ParseOpenCLQualifiers(ParsedAttributes &Attrs);
|
||||
/// \brief Parses opencl_unroll_hint attribute if language is OpenCL v2.0
|
||||
/// or higher.
|
||||
/// \return false if error happens.
|
||||
bool MaybeParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
|
||||
if (getLangOpts().OpenCL)
|
||||
return ParseOpenCLUnrollHintAttribute(Attrs);
|
||||
return true;
|
||||
}
|
||||
/// \brief Parses opencl_unroll_hint attribute.
|
||||
/// \return false if error happens.
|
||||
bool ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs);
|
||||
void ParseNullabilityTypeSpecifiers(ParsedAttributes &attrs);
|
||||
|
||||
VersionTuple ParseVersionTuple(SourceRange &Range);
|
||||
|
|
|
@ -115,20 +115,41 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
|
|||
// Identify loop hint attributes from Attrs.
|
||||
for (const auto *Attr : Attrs) {
|
||||
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(Attr);
|
||||
const OpenCLUnrollHintAttr *OpenCLHint =
|
||||
dyn_cast<OpenCLUnrollHintAttr>(Attr);
|
||||
|
||||
// Skip non loop hint attributes
|
||||
if (!LH)
|
||||
if (!LH && !OpenCLHint) {
|
||||
continue;
|
||||
|
||||
auto *ValueExpr = LH->getValue();
|
||||
unsigned ValueInt = 1;
|
||||
if (ValueExpr) {
|
||||
llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
|
||||
ValueInt = ValueAPS.getSExtValue();
|
||||
}
|
||||
|
||||
LoopHintAttr::OptionType Option = LH->getOption();
|
||||
LoopHintAttr::LoopHintState State = LH->getState();
|
||||
LoopHintAttr::OptionType Option = LoopHintAttr::Unroll;
|
||||
LoopHintAttr::LoopHintState State = LoopHintAttr::Disable;
|
||||
unsigned ValueInt = 1;
|
||||
// Translate opencl_unroll_hint attribute argument to
|
||||
// equivalent LoopHintAttr enums.
|
||||
// OpenCL v2.0 s6.11.5:
|
||||
// 0 - full unroll (no argument).
|
||||
// 1 - disable unroll.
|
||||
// other positive integer n - unroll by n.
|
||||
if (OpenCLHint) {
|
||||
ValueInt = OpenCLHint->getUnrollHint();
|
||||
if (ValueInt == 0) {
|
||||
State = LoopHintAttr::Full;
|
||||
} else if (ValueInt != 1) {
|
||||
Option = LoopHintAttr::UnrollCount;
|
||||
State = LoopHintAttr::Numeric;
|
||||
}
|
||||
} else if (LH) {
|
||||
auto *ValueExpr = LH->getValue();
|
||||
if (ValueExpr) {
|
||||
llvm::APSInt ValueAPS = ValueExpr->EvaluateKnownConstInt(Ctx);
|
||||
ValueInt = ValueAPS.getSExtValue();
|
||||
}
|
||||
|
||||
Option = LH->getOption();
|
||||
State = LH->getState();
|
||||
}
|
||||
switch (State) {
|
||||
case LoopHintAttr::Disable:
|
||||
switch (Option) {
|
||||
|
|
|
@ -670,7 +670,7 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) {
|
|||
}
|
||||
}
|
||||
|
||||
void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) {
|
||||
void Parser::ParseOpenCLKernelAttributes(ParsedAttributes &attrs) {
|
||||
// Treat these like attributes
|
||||
while (Tok.is(tok::kw___kernel)) {
|
||||
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
|
||||
|
@ -3098,7 +3098,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
|||
|
||||
// OpenCL single token adornments.
|
||||
case tok::kw___kernel:
|
||||
ParseOpenCLAttributes(DS.getAttributes());
|
||||
ParseOpenCLKernelAttributes(DS.getAttributes());
|
||||
continue;
|
||||
|
||||
// Nullability type specifiers.
|
||||
|
|
|
@ -107,6 +107,8 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts,
|
|||
|
||||
ParsedAttributesWithRange Attrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(Attrs, nullptr, /*MightBeObjCMessageSend*/ true);
|
||||
if (!MaybeParseOpenCLUnrollHintAttribute(Attrs))
|
||||
return StmtError();
|
||||
|
||||
StmtResult Res = ParseStatementOrDeclarationAfterAttributes(
|
||||
Stmts, Allowed, TrailingElseLoc, Attrs);
|
||||
|
@ -2208,3 +2210,19 @@ void Parser::ParseMicrosoftIfExistsStatement(StmtVector &Stmts) {
|
|||
}
|
||||
Braces.consumeClose();
|
||||
}
|
||||
|
||||
bool Parser::ParseOpenCLUnrollHintAttribute(ParsedAttributes &Attrs) {
|
||||
MaybeParseGNUAttributes(Attrs);
|
||||
|
||||
if (Attrs.empty())
|
||||
return true;
|
||||
|
||||
if (Attrs.getList()->getKind() != AttributeList::AT_OpenCLUnrollHint)
|
||||
return true;
|
||||
|
||||
if (!(Tok.is(tok::kw_for) || Tok.is(tok::kw_while) || Tok.is(tok::kw_do))) {
|
||||
Diag(Tok, diag::err_opencl_unroll_hint_on_non_loop);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -203,6 +203,52 @@ CheckForIncompatibleAttributes(Sema &S,
|
|||
}
|
||||
}
|
||||
|
||||
static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A,
|
||||
SourceRange Range) {
|
||||
// OpenCL v2.0 s6.11.5 - opencl_unroll_hint can have 0 arguments (compiler
|
||||
// determines unrolling factor) or 1 argument (the unroll factor provided
|
||||
// by the user).
|
||||
|
||||
if (S.getLangOpts().OpenCLVersion < 200) {
|
||||
S.Diag(A.getLoc(), diag::err_attribute_requires_opencl_version)
|
||||
<< A.getName() << "2.0";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned NumArgs = A.getNumArgs();
|
||||
|
||||
if (NumArgs > 1) {
|
||||
S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName()
|
||||
<< 1;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned UnrollFactor = 0;
|
||||
|
||||
if (NumArgs == 1) {
|
||||
Expr *E = A.getArgAsExpr(0);
|
||||
llvm::APSInt ArgVal(32);
|
||||
|
||||
if (!E->isIntegerConstantExpr(ArgVal, S.Context)) {
|
||||
S.Diag(A.getLoc(), diag::err_attribute_argument_type)
|
||||
<< A.getName() << AANT_ArgumentIntegerConstant << E->getSourceRange();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Val = ArgVal.getSExtValue();
|
||||
|
||||
if (Val <= 0) {
|
||||
S.Diag(A.getRange().getBegin(),
|
||||
diag::err_attribute_requires_positive_integer)
|
||||
<< A.getName();
|
||||
return nullptr;
|
||||
}
|
||||
UnrollFactor = Val;
|
||||
}
|
||||
|
||||
return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
|
||||
}
|
||||
|
||||
static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
|
||||
SourceRange Range) {
|
||||
switch (A.getKind()) {
|
||||
|
@ -215,6 +261,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
|
|||
return handleFallThroughAttr(S, St, A, Range);
|
||||
case AttributeList::AT_LoopHint:
|
||||
return handleLoopHintAttr(S, St, A, Range);
|
||||
case AttributeList::AT_OpenCLUnrollHint:
|
||||
return handleOpenCLUnrollHint(S, St, A, Range);
|
||||
default:
|
||||
// if we're here, then we parsed a known attribute, but didn't recognize
|
||||
// it as a statement attribute => it is declaration attribute
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
// RUN: %clang_cc1 -emit-llvm -O0 -cl-std=CL2.0 -o - %s | FileCheck %s
|
||||
|
||||
/*** for ***/
|
||||
void for_count()
|
||||
{
|
||||
// CHECK-LABEL: for_count
|
||||
__attribute__((opencl_unroll_hint(8)))
|
||||
for( int i = 0; i < 1000; ++i);
|
||||
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_COUNT:.*]]
|
||||
}
|
||||
|
||||
void for_disable()
|
||||
{
|
||||
// CHECK-LABEL: for_disable
|
||||
__attribute__((opencl_unroll_hint(1)))
|
||||
for( int i = 0; i < 1000; ++i);
|
||||
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_DISABLE:.*]]
|
||||
}
|
||||
|
||||
void for_full()
|
||||
{
|
||||
// CHECK-LABEL: for_full
|
||||
__attribute__((opencl_unroll_hint))
|
||||
for( int i = 0; i < 1000; ++i);
|
||||
// CHECK: br label %{{.*}}, !llvm.loop ![[FOR_FULL:.*]]
|
||||
}
|
||||
|
||||
/*** while ***/
|
||||
void while_count()
|
||||
{
|
||||
// CHECK-LABEL: while_count
|
||||
int i = 1000;
|
||||
__attribute__((opencl_unroll_hint(8)))
|
||||
while(i-->0);
|
||||
// CHECK: br label %{{.*}}, !llvm.loop ![[WHILE_COUNT:.*]]
|
||||
}
|
||||
|
||||
void while_disable()
|
||||
{
|
||||
// CHECK-LABEL: while_disable
|
||||
int i = 1000;
|
||||
__attribute__((opencl_unroll_hint(1)))
|
||||
while(i-->0);
|
||||
// CHECK: br label %{{.*}}, !llvm.loop ![[WHILE_DISABLE:.*]]
|
||||
}
|
||||
|
||||
void while_full()
|
||||
{
|
||||
// CHECK-LABEL: while_full
|
||||
int i = 1000;
|
||||
__attribute__((opencl_unroll_hint))
|
||||
while(i-->0);
|
||||
// CHECK: br label %{{.*}}, !llvm.loop ![[WHILE_FULL:.*]]
|
||||
}
|
||||
|
||||
/*** do ***/
|
||||
void do_count()
|
||||
{
|
||||
// CHECK-LABEL: do_count
|
||||
int i = 1000;
|
||||
__attribute__((opencl_unroll_hint(8)))
|
||||
do {} while(i--> 0);
|
||||
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[DO_COUNT:.*]]
|
||||
}
|
||||
|
||||
void do_disable()
|
||||
{
|
||||
// CHECK-LABEL: do_disable
|
||||
int i = 1000;
|
||||
__attribute__((opencl_unroll_hint(1)))
|
||||
do {} while(i--> 0);
|
||||
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[DO_DISABLE:.*]]
|
||||
}
|
||||
|
||||
void do_full()
|
||||
{
|
||||
// CHECK-LABEL: do_full
|
||||
int i = 1000;
|
||||
__attribute__((opencl_unroll_hint))
|
||||
do {} while(i--> 0);
|
||||
// CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !llvm.loop ![[DO_FULL:.*]]
|
||||
}
|
||||
|
||||
|
||||
// CHECK: ![[FOR_COUNT]] = distinct !{![[FOR_COUNT]], ![[COUNT:.*]]}
|
||||
// CHECK: ![[COUNT]] = !{!"llvm.loop.unroll.count", i32 8}
|
||||
// CHECK: ![[FOR_DISABLE]] = distinct !{![[FOR_DISABLE]], ![[DISABLE:.*]]}
|
||||
// CHECK: ![[DISABLE]] = !{!"llvm.loop.unroll.disable"}
|
||||
// CHECK: ![[FOR_FULL]] = distinct !{![[FOR_FULL]], ![[FULL:.*]]}
|
||||
// CHECK: ![[FULL]] = !{!"llvm.loop.unroll.full"}
|
||||
// CHECK: ![[WHILE_COUNT]] = distinct !{![[WHILE_COUNT]], ![[COUNT]]}
|
||||
// CHECK: ![[WHILE_DISABLE]] = distinct !{![[WHILE_DISABLE]], ![[DISABLE]]}
|
||||
// CHECK: ![[WHILE_FULL]] = distinct !{![[WHILE_FULL]], ![[FULL]]}
|
||||
// CHECK: ![[DO_COUNT]] = distinct !{![[DO_COUNT]], ![[COUNT]]}
|
||||
// CHECK: ![[DO_DISABLE]] = distinct !{![[DO_DISABLE]], ![[DISABLE]]}
|
||||
// CHECK: ![[DO_FULL]] = distinct !{![[DO_FULL]], ![[FULL]]}
|
|
@ -0,0 +1,8 @@
|
|||
//RUN: %clang_cc1 -O0 -cl-std=CL2.0 -fsyntax-only -verify %s
|
||||
|
||||
kernel void B (global int *x) {
|
||||
__attribute__((opencl_unroll_hint(42)))
|
||||
if (x[0]) // expected-error {{OpenCL only supports 'opencl_unroll_hint' attribute on for, while, and do statements}}
|
||||
x[0] = 15;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
//RUN: %clang_cc1 -O0 -fsyntax-only -verify %s
|
||||
//RUN: %clang_cc1 -O0 -cl-std=CL2.0 -fsyntax-only -verify -DCL20 %s
|
||||
|
||||
kernel void D (global int *x) {
|
||||
int i = 10;
|
||||
#ifndef CL20
|
||||
// expected-error@+2 {{'opencl_unroll_hint' attribute requires OpenCL version 2.0 or above}}
|
||||
#endif
|
||||
__attribute__((opencl_unroll_hint))
|
||||
do {
|
||||
} while(i--);
|
||||
}
|
||||
|
||||
#ifdef CL20
|
||||
kernel void C (global int *x) {
|
||||
int I = 3;
|
||||
__attribute__((opencl_unroll_hint(I))) // expected-error {{'opencl_unroll_hint' attribute requires an integer constant}}
|
||||
while (I--);
|
||||
}
|
||||
|
||||
kernel void E() {
|
||||
__attribute__((opencl_unroll_hint(2,4))) // expected-error {{'opencl_unroll_hint' attribute takes no more than 1 argument}}
|
||||
for(int i=0; i<100; i++);
|
||||
}
|
||||
|
||||
kernel void F() {
|
||||
__attribute__((opencl_unroll_hint(-1))) // expected-error {{'opencl_unroll_hint' attribute requires a positive integral compile time constant expression}}
|
||||
for(int i=0; i<100; i++);
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue