In unroll pragma syntax and loop hint metadata, change "enable" forms to a new form using the string "full".

llvm-svn: 213771
This commit is contained in:
Mark Heffernan 2014-07-23 17:31:31 +00:00
parent 4c7ceab219
commit 450c23843e
13 changed files with 91 additions and 72 deletions

View File

@ -1843,7 +1843,7 @@ iterations. Full unrolling is only possible if the loop trip count is known at
compile time. Partial unrolling replicates the loop body within the loop and
reduces the trip count.
If ``unroll(enable)`` is specified the unroller will attempt to fully unroll the
If ``unroll(full)`` is specified the unroller will attempt to fully unroll the
loop if the trip count is known at compile time. If the loop count is not known
or the fully unrolled code size is greater than the limit specified by the
`-pragma-unroll-threshold` command line option the loop will be partially
@ -1851,7 +1851,7 @@ unrolled subject to the same limit.
.. code-block:: c++
#pragma clang loop unroll(enable)
#pragma clang loop unroll(full)
for(...) {
...
}

View File

@ -1788,7 +1788,7 @@ def LoopHint : Attr {
/// vectorize_width: vectorize loop operations with width 'value'.
/// interleave: interleave multiple loop iterations if 'value != 0'.
/// interleave_count: interleaves 'value' loop interations.
/// unroll: unroll loop if 'value != 0'.
/// unroll: fully unroll loop if 'value != 0'.
/// unroll_count: unrolls loop 'value' times.
let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];
@ -1842,6 +1842,10 @@ def LoopHint : Attr {
if (option == VectorizeWidth || option == InterleaveCount ||
option == UnrollCount)
OS << value;
else if (option == Unroll && value)
// Unroll loop hint does not use the keyword "enable". Instead, a nonzero value
// indicates full unrolling which uses the keyword "full".
OS << "full";
else if (value)
OS << "enable";
else

View File

@ -1097,7 +1097,7 @@ enclosed in parentheses:
}
``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
``#pragma clang loop unroll(enable)`` and ``#pragma clang loop
``#pragma clang loop unroll(full)`` and ``#pragma clang loop
unroll_count(_value_)`` respectively. See `language extensions
<http://clang.llvm.org/docs/LanguageExtensions.html#extensions-for-loop-hint-optimizations>`_
for further details including limitations of the unroll hints.

View File

@ -818,7 +818,7 @@ def warn_pragma_expected_non_wide_string : Warning<
"expected non-wide string literal in '#pragma %0'">, InGroup<IgnoredPragmas>;
// - Generic errors
def err_pragma_missing_argument : Error<
"missing argument to '#pragma %0'; expected %1">;
"missing argument to '#pragma %0'%select{|; expected %2}1">;
// - #pragma options
def warn_pragma_options_expected_align : Warning<
"expected 'align' following '#pragma options' - ignored">,

View File

@ -539,7 +539,7 @@ def note_surrounding_namespace_starts_here : Note<
def err_pragma_loop_invalid_value : Error<
"invalid argument; expected a positive integer value">;
def err_pragma_loop_invalid_keyword : Error<
"invalid argument; expected 'enable' or 'disable'">;
"invalid argument; expected '%0' or 'disable'">;
def err_pragma_loop_compatibility : Error<
"%select{incompatible|duplicate}0 directives '%1' and '%2'">;
def err_pragma_loop_precedes_nonloop : Error<

View File

@ -601,13 +601,14 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
MetadataName = "llvm.loop.interleave.count";
break;
case LoopHintAttr::Unroll:
MetadataName = "llvm.loop.unroll.enable";
// With the unroll loop hint, a non-zero value indicates full unrolling.
MetadataName =
ValueInt == 0 ? "llvm.loop.unroll.disable" : "llvm.loop.unroll.full";
break;
case LoopHintAttr::UnrollCount:
MetadataName = "llvm.loop.unroll.count";
break;
}
llvm::Value *Value;
llvm::MDString *Name;
switch (Option) {
@ -625,22 +626,20 @@ void CodeGenFunction::EmitCondBrHints(llvm::LLVMContext &Context,
// Fallthrough.
case LoopHintAttr::VectorizeWidth:
case LoopHintAttr::InterleaveCount:
case LoopHintAttr::UnrollCount:
Name = llvm::MDString::get(Context, MetadataName);
Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
break;
case LoopHintAttr::Unroll:
Name = llvm::MDString::get(Context, MetadataName);
Value = (ValueInt == 0) ? Builder.getFalse() : Builder.getTrue();
break;
case LoopHintAttr::UnrollCount:
Name = llvm::MDString::get(Context, MetadataName);
Value = llvm::ConstantInt::get(Int32Ty, ValueInt);
Value = nullptr;
break;
}
SmallVector<llvm::Value *, 2> OpValues;
OpValues.push_back(Name);
OpValues.push_back(Value);
if (Value)
OpValues.push_back(Value);
// Set or overwrite metadata indicated by Name.
Metadata.push_back(llvm::MDNode::get(Context, OpValues));

View File

@ -1719,8 +1719,7 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
PP.Lex(Tok);
if (Tok.is(tok::eod)) {
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
<< "clang optimize"
<< "'on' or 'off'";
<< "clang optimize" << /*Expected=*/true << "'on' or 'off'";
return;
}
if (Tok.isNot(tok::identifier)) {
@ -1767,8 +1766,12 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
"Unexpected pragma name");
PragmaString = "unroll";
}
// Don't try to emit what the pragma is expecting with the diagnostic
// because the logic is non-trivial and we give expected values in sema
// diagnostics if an invalid argument is given. Here, just note that the
// pragma is missing an argument.
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
<< PragmaString << "a positive integer value";
<< PragmaString << /*Expected=*/false;
return true;
}
}
@ -1800,7 +1803,7 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
/// loop-hint:
/// 'vectorize' '(' loop-hint-keyword ')'
/// 'interleave' '(' loop-hint-keyword ')'
/// 'unroll' '(' loop-hint-keyword ')'
/// 'unroll' '(' unroll-hint-keyword ')'
/// 'vectorize_width' '(' loop-hint-value ')'
/// 'interleave_count' '(' loop-hint-value ')'
/// 'unroll_count' '(' loop-hint-value ')'
@ -1809,6 +1812,10 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
/// 'enable'
/// 'disable'
///
/// unroll-hint-keyword:
/// 'full'
/// 'disable'
///
/// loop-hint-value:
/// constant-expression
///
@ -1823,12 +1830,10 @@ static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
/// only works on inner loops.
///
/// The unroll and unroll_count directives control the concatenation
/// unroller. Specifying unroll(enable) instructs llvm to try to
/// unroller. Specifying unroll(full) instructs llvm to try to
/// unroll the loop completely, and unroll(disable) disables unrolling
/// for the loop. Specifying unroll_count(_value_) instructs llvm to
/// try to unroll the loop the number of times indicated by the value.
/// If unroll(enable) and unroll_count are both specified only
/// unroll_count takes effect.
void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &Tok) {

View File

@ -89,16 +89,22 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
} else if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave ||
Option == LoopHintAttr::Unroll) {
// Unrolling uses the keyword "full" rather than "enable" to indicate full
// unrolling.
const char *TrueKeyword =
Option == LoopHintAttr::Unroll ? "full" : "enable";
if (!ValueInfo) {
S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
<< TrueKeyword;
return nullptr;
}
if (ValueInfo->isStr("disable"))
ValueInt = 0;
else if (ValueInfo->isStr("enable"))
else if (ValueInfo->getName() == TrueKeyword)
ValueInt = 1;
else {
S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword)
<< TrueKeyword;
return nullptr;
}
} else if (Option == LoopHintAttr::VectorizeWidth ||
@ -121,12 +127,14 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
static void CheckForIncompatibleAttributes(
Sema &S, const SmallVectorImpl<const Attr *> &Attrs) {
// There are 3 categories of loop hints: vectorize, interleave, and
// unroll. Each comes in two variants: an enable/disable form and a
// form which takes a numeric argument. For example:
// unroll(enable|disable) and unroll_count(N). The following array
// accumulate the hints encountered while iterating through the
// attributes to check for compatibility.
// There are 3 categories of loop hints attributes: vectorize, interleave, and
// unroll. Each comes in two variants: a boolean form and a numeric form. The
// boolean hints selectively enables/disables the transformation for the loop
// (for unroll, a nonzero value indicates full unrolling rather than enabling
// the transformation). The numeric hint provides an integer hint (for
// example, unroll count) to the transformer. The following array accumulates
// the hints encountered while iterating through the attributes to check for
// compatibility.
struct {
const LoopHintAttr *EnableAttr;
const LoopHintAttr *NumericAttr;
@ -141,18 +149,19 @@ static void CheckForIncompatibleAttributes(
int Option = LH->getOption();
int Category;
enum { Vectorize, Interleave, Unroll };
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::VectorizeWidth:
Category = 0;
Category = Vectorize;
break;
case LoopHintAttr::Interleave:
case LoopHintAttr::InterleaveCount:
Category = 1;
Category = Interleave;
break;
case LoopHintAttr::Unroll:
case LoopHintAttr::UnrollCount:
Category = 2;
Category = Unroll;
break;
};
@ -176,10 +185,11 @@ static void CheckForIncompatibleAttributes(
<< /*Duplicate=*/true << PrevAttr->getDiagnosticName()
<< LH->getDiagnosticName();
if (CategoryState.EnableAttr && !CategoryState.EnableAttr->getValue() &&
CategoryState.NumericAttr) {
// Disable hints are not compatible with numeric hints of the
// same category.
if (CategoryState.EnableAttr && CategoryState.NumericAttr &&
(Category == Unroll || !CategoryState.EnableAttr->getValue())) {
// Disable hints are not compatible with numeric hints of the same
// category. As a special case, numeric unroll hints are also not
// compatible with "enable" form of the unroll pragma, unroll(full).
S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
<< /*Duplicate=*/false
<< CategoryState.EnableAttr->getDiagnosticName()

View File

@ -8,7 +8,7 @@ void while_test(int *List, int Length) {
#pragma clang loop vectorize(enable)
#pragma clang loop interleave_count(4)
#pragma clang loop vectorize_width(4)
#pragma clang loop unroll(enable)
#pragma clang loop unroll(full)
while (i < Length) {
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_1:.*]]
List[i] = i * 2;
@ -121,7 +121,7 @@ void template_test(double *List, int Length) {
// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
// CHECK: ![[INTERLEAVE_2]] = metadata !{metadata !"llvm.loop.interleave.count", i32 2}
// CHECK: ![[WIDTH_2]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 2}
// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLLENABLE_0:.*]], metadata ![[WIDTH_1:.*]]}
// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLL_DISABLE:.*]], metadata ![[WIDTH_1:.*]]}
// CHECK: ![[WIDTH_1]] = metadata !{metadata !"llvm.loop.vectorize.width", i32 1}
// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_2:.*]], metadata ![[WIDTH_2:.*]]}
// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]], metadata ![[INTERLEAVE_8:.*]], metadata ![[WIDTH_8:.*]]}

View File

@ -86,8 +86,8 @@ void template_test(double *List, int Length) {
for_template_define_test<double>(List, Length, Value);
}
// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLLENABLE_1:.*]]}
// CHECK: ![[UNROLLENABLE_1]] = metadata !{metadata !"llvm.loop.unroll.enable", i1 true}
// CHECK: ![[LOOP_1]] = metadata !{metadata ![[LOOP_1]], metadata ![[UNROLL_FULL:.*]]}
// CHECK: ![[UNROLL_FULL]] = metadata !{metadata !"llvm.loop.unroll.full"}
// CHECK: ![[LOOP_2]] = metadata !{metadata ![[LOOP_2:.*]], metadata ![[UNROLL_16:.*]]}
// CHECK: ![[UNROLL_16]] = metadata !{metadata !"llvm.loop.unroll.count", i32 16}
// CHECK: ![[LOOP_3]] = metadata !{metadata ![[LOOP_3]], metadata ![[UNROLL_8:.*]]}

View File

@ -10,7 +10,7 @@
// CHECK: #pragma clang loop unroll(disable)
// CHECK: #pragma clang loop interleave(disable)
// CHECK: #pragma clang loop vectorize(enable)
// CHECK: #pragma clang loop unroll(enable)
// CHECK: #pragma clang loop unroll(full)
// CHECK: #pragma clang loop interleave(enable)
// CHECK: #pragma clang loop vectorize(disable)
// CHECK: #pragma unroll
@ -47,7 +47,7 @@ public:
int i = 0;
#pragma clang loop vectorize(disable)
#pragma clang loop interleave(enable)
#pragma clang loop unroll(enable)
#pragma clang loop unroll(full)
while (i - 3 < Length) {
List[i] = i;
i++;

View File

@ -8,7 +8,7 @@ void test(int *List, int Length) {
#pragma clang loop vectorize(enable)
#pragma clang loop interleave(enable)
#pragma clang loop unroll(enable)
#pragma clang loop unroll(full)
while (i + 1 < Length) {
List[i] = i;
}
@ -49,15 +49,15 @@ void test(int *List, int Length) {
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize(enable
/* expected-error {{expected ')'}} */ #pragma clang loop interleave(enable
/* expected-error {{expected ')'}} */ #pragma clang loop unroll(enable
/* expected-error {{expected ')'}} */ #pragma clang loop unroll(full
/* expected-error {{expected ')'}} */ #pragma clang loop vectorize_width(4
/* expected-error {{expected ')'}} */ #pragma clang loop interleave_count(4
/* expected-error {{expected ')'}} */ #pragma clang loop unroll_count(4
/* expected-error {{missing argument to '#pragma clang loop vectorize'; expected a positive integer value}} */ #pragma clang loop vectorize()
/* expected-error {{missing argument to '#pragma clang loop interleave_count'; expected a positive integer value}} */ #pragma clang loop interleave_count()
/* expected-error {{missing argument to '#pragma clang loop unroll'; expected a positive integer value}} */ #pragma clang loop unroll()
/* expected-error {{missing argument to '#pragma clang loop vectorize'}} */ #pragma clang loop vectorize()
/* expected-error {{missing argument to '#pragma clang loop interleave_count'}} */ #pragma clang loop interleave_count()
/* expected-error {{missing argument to '#pragma clang loop unroll'}} */ #pragma clang loop unroll()
/* expected-error {{missing option}} */ #pragma clang loop
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword
@ -92,7 +92,7 @@ void test(int *List, int Length) {
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(badidentifier)
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(badidentifier)
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll(badidentifier)
/* expected-error {{invalid argument; expected 'full' or 'disable'}} */ #pragma clang loop unroll(badidentifier)
while (i-7 < Length) {
List[i] = i;
}
@ -101,7 +101,7 @@ void test(int *List, int Length) {
// constants crash FE.
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop vectorize(()
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop interleave(*)
/* expected-error {{invalid argument; expected 'enable' or 'disable'}} */ #pragma clang loop unroll(=)
/* expected-error {{invalid argument; expected 'full' or 'disable'}} */ #pragma clang loop unroll(=)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop vectorize_width(^)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop interleave_count(/)
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma clang loop unroll_count(==)
@ -136,7 +136,7 @@ void test(int *List, int Length) {
#pragma clang loop vectorize(disable)
/* expected-error {{duplicate directives 'interleave(disable)' and 'interleave(enable)'}} */ #pragma clang loop interleave(enable)
#pragma clang loop interleave(disable)
/* expected-error {{duplicate directives 'unroll(disable)' and 'unroll(enable)'}} */ #pragma clang loop unroll(enable)
/* expected-error {{duplicate directives 'unroll(disable)' and 'unroll(full)'}} */ #pragma clang loop unroll(full)
#pragma clang loop unroll(disable)
while (i-9 < Length) {
List[i] = i;
@ -162,5 +162,12 @@ void test(int *List, int Length) {
List[i] = i;
}
/* expected-error {{incompatible directives 'unroll(full)' and 'unroll_count(4)'}} */ #pragma clang loop unroll(full)
#pragma clang loop unroll_count(4)
while (i-11 < Length) {
List[i] = i;
}
#pragma clang loop interleave(enable)
/* expected-error {{expected statement}} */ }

View File

@ -21,26 +21,8 @@ void test(int *List, int Length) {
List[i] = i;
}
#pragma unroll
#pragma unroll(8)
while (i - 3 < Length) {
List[i] = i;
}
#pragma clang loop unroll(enable)
#pragma unroll(8)
while (i - 4 < Length) {
List[i] = i;
}
#pragma unroll
#pragma clang loop unroll_count(4)
while (i - 5 < Length) {
List[i] = i;
}
/* expected-error {{expected ')'}} */ #pragma unroll(4
/* expected-error {{missing argument to '#pragma unroll'; expected a positive integer value}} */ #pragma unroll()
/* expected-error {{missing argument to '#pragma unroll'}} */ #pragma unroll()
/* expected-warning {{extra tokens at end of '#pragma unroll'}} */ #pragma unroll 1 2
while (i-6 < Length) {
List[i] = i;
@ -67,14 +49,26 @@ void test(int *List, int Length) {
List[i] = i;
}
/* expected-error {{incompatible directives 'unroll(full)' and '#pragma unroll(4)'}} */ #pragma unroll(4)
#pragma clang loop unroll(full)
while (i-11 < Length) {
List[i] = i;
}
/* expected-error {{incompatible directives '#pragma unroll' and '#pragma unroll(4)'}} */ #pragma unroll(4)
#pragma unroll
while (i-11 < Length) {
List[i] = i;
}
/* expected-error {{duplicate directives '#pragma unroll' and '#pragma unroll'}} */ #pragma unroll
#pragma unroll
while (i-14 < Length) {
List[i] = i;
}
/* expected-error {{duplicate directives 'unroll(enable)' and '#pragma unroll'}} */ #pragma unroll
#pragma clang loop unroll(enable)
/* expected-error {{duplicate directives 'unroll(full)' and '#pragma unroll'}} */ #pragma unroll
#pragma clang loop unroll(full)
while (i-15 < Length) {
List[i] = i;
}