forked from OSchip/llvm-project
parent
4f42fc4e1d
commit
bd26f5ea4d
|
@ -111,6 +111,13 @@ interleaving, and unrolling to be enabled or disabled. Vector width as well
|
|||
as interleave and unrolling count can be manually specified. See language
|
||||
extensions for details.
|
||||
|
||||
Clang now supports the `#pragma unroll` directive to specify loop unrolling
|
||||
optimization hints. Placed just prior to the desired loop, `#pragma unroll`
|
||||
directs the loop unroller to attempt to fully unroll the loop. The pragma may
|
||||
also be specified with a positive integer parameter indicating the desired
|
||||
unroll count: `#pragma unroll _value_`. The unroll count parameter can be
|
||||
optionally enclosed in parentheses.
|
||||
|
||||
C Language Changes in Clang
|
||||
---------------------------
|
||||
|
||||
|
|
|
@ -1779,7 +1779,7 @@ def LoopHint : Attr {
|
|||
/// unroll: unroll loop if 'value != 0'.
|
||||
/// unroll_count: unrolls loop 'value' times.
|
||||
|
||||
let Spellings = [Pragma<"clang", "loop">];
|
||||
let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">];
|
||||
|
||||
/// State of the loop optimization specified by the spelling.
|
||||
let Args = [EnumArgument<"Option", "OptionType",
|
||||
|
@ -1809,15 +1809,47 @@ def LoopHint : Attr {
|
|||
}
|
||||
|
||||
void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {
|
||||
OS << getOptionName(option) << "(";
|
||||
unsigned SpellingIndex = getSpellingListIndex();
|
||||
if (SpellingIndex == Pragma_unroll) {
|
||||
// String "unroll" of "#pragma unroll" is already emitted as the
|
||||
// pragma name.
|
||||
if (option == UnrollCount)
|
||||
OS << getValueString();
|
||||
OS << "\n";
|
||||
return;
|
||||
}
|
||||
assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
|
||||
OS << getOptionName(option) << getValueString() << "\n";
|
||||
}
|
||||
|
||||
// Return a string containing the loop hint argument including the
|
||||
// enclosing parentheses.
|
||||
std::string getValueString() const {
|
||||
std::string ValueName;
|
||||
if (option == VectorizeWidth || option == InterleaveCount ||
|
||||
option == UnrollCount)
|
||||
OS << value;
|
||||
ValueName = std::to_string(value);
|
||||
else if (value)
|
||||
ValueName = "enable";
|
||||
else
|
||||
OS << getValueName(value);
|
||||
OS << ")\n";
|
||||
ValueName = "disable";
|
||||
|
||||
return "(" + ValueName + ")";
|
||||
}
|
||||
|
||||
// Return a string suitable for identifying this attribute in diagnostics.
|
||||
std::string getDiagnosticName() const {
|
||||
unsigned SpellingIndex = getSpellingListIndex();
|
||||
if (SpellingIndex == Pragma_unroll && option == Unroll)
|
||||
return "#pragma unroll";
|
||||
else if (SpellingIndex == Pragma_unroll && option == UnrollCount) {
|
||||
return "#pragma unroll" + getValueString();
|
||||
} else {
|
||||
assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
|
||||
return std::string(getOptionName(option)) + getValueString();
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
let Documentation = [LoopHintDocs];
|
||||
let Documentation = [LoopHintDocs, UnrollHintDocs];
|
||||
}
|
||||
|
|
|
@ -1045,3 +1045,45 @@ as interleave and unrolling count can be manually specified. See
|
|||
for details.
|
||||
}];
|
||||
}
|
||||
|
||||
def UnrollHintDocs : Documentation {
|
||||
let Category = DocCatStmt;
|
||||
let Content = [{
|
||||
Loop unrolling optimization hints can be specified with ``#pragma unroll``. The
|
||||
pragma is placed immediately before a for, while, do-while, or c++11 range-based
|
||||
for loop.
|
||||
|
||||
Specifying ``#pragma unroll`` without a parameter directs the loop unroller to
|
||||
attempt to fully unroll the loop if the trip count is known at compile time:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma unroll
|
||||
for (...) {
|
||||
...
|
||||
}
|
||||
|
||||
Specifying the optional parameter, ``#pragma unroll _value_``, directs the
|
||||
unroller to unroll the loop ``_value_`` times. The parameter may optionally be
|
||||
enclosed in parentheses:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#pragma unroll 16
|
||||
for (...) {
|
||||
...
|
||||
}
|
||||
|
||||
#pragma unroll(16)
|
||||
for (...) {
|
||||
...
|
||||
}
|
||||
|
||||
``#pragma unroll`` and ``#pragma unroll _value_`` have identical semantics to
|
||||
``#pragma clang loop unroll(enable)`` 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.
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -709,3 +709,7 @@ def BackendOptimizationFailure : DiagGroup<"pass-failed">;
|
|||
// Instrumentation based profiling warnings.
|
||||
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
|
||||
def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
|
||||
|
||||
// A warning group for warnings about code that clang accepts when
|
||||
// compiling CUDA C/C++ but which is not compatible with the CUDA spec.
|
||||
def CudaCompat : DiagGroup<"cuda-compat">;
|
||||
|
|
|
@ -813,6 +813,9 @@ def warn_pragma_expected_punc : Warning<
|
|||
"expected ')' or ',' in '#pragma %0'">, InGroup<IgnoredPragmas>;
|
||||
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">;
|
||||
// - #pragma options
|
||||
def warn_pragma_options_expected_align : Warning<
|
||||
"expected 'align' following '#pragma options' - ignored">,
|
||||
|
@ -860,8 +863,6 @@ def err_pragma_pointers_to_members_unknown_kind : Error<
|
|||
"unexpected %0, expected to see one of %select{|'best_case', 'full_generality', }1"
|
||||
"'single_inheritance', 'multiple_inheritance', or 'virtual_inheritance'">;
|
||||
// - #pragma clang optimize on/off
|
||||
def err_pragma_optimize_missing_argument : Error<
|
||||
"missing argument to '#pragma clang optimize'; expected 'on' or 'off'">;
|
||||
def err_pragma_optimize_invalid_argument : Error<
|
||||
"unexpected argument '%0' to '#pragma clang optimize'; "
|
||||
"expected 'on' or 'off'">;
|
||||
|
@ -917,8 +918,11 @@ def err_omp_expected_identifier_for_critical : Error<
|
|||
def err_pragma_loop_invalid_option : Error<
|
||||
"%select{invalid|missing}0 option%select{ %1|}0; expected vectorize, "
|
||||
"vectorize_width, interleave, interleave_count, unroll, or unroll_count">;
|
||||
def err_pragma_loop_missing_argument : Error<
|
||||
"missing argument to loop pragma %0">;
|
||||
|
||||
// Pragma unroll support.
|
||||
def warn_pragma_unroll_cuda_value_in_parens : Warning<
|
||||
"argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
|
||||
InGroup<CudaCompat>;
|
||||
} // end of Parse Issue category.
|
||||
|
||||
let CategoryName = "Modules Issue" in {
|
||||
|
|
|
@ -541,10 +541,9 @@ def err_pragma_loop_invalid_value : Error<
|
|||
def err_pragma_loop_invalid_keyword : Error<
|
||||
"invalid argument; expected 'enable' or 'disable'">;
|
||||
def err_pragma_loop_compatibility : Error<
|
||||
"%select{incompatible|duplicate}0 directives '%1(%2)' and '%3(%4)'">;
|
||||
"%select{incompatible|duplicate}0 directives '%1' and '%2'">;
|
||||
def err_pragma_loop_precedes_nonloop : Error<
|
||||
"expected a for, while, or do-while loop to follow the '#pragma clang loop' "
|
||||
"directive">;
|
||||
"expected a for, while, or do-while loop to follow '%0'">;
|
||||
|
||||
/// Objective-C parser diagnostics
|
||||
def err_duplicate_class_def : Error<
|
||||
|
|
|
@ -163,6 +163,7 @@ class Parser : public CodeCompletionHandler {
|
|||
std::unique_ptr<PragmaHandler> MSSection;
|
||||
std::unique_ptr<PragmaHandler> OptimizeHandler;
|
||||
std::unique_ptr<PragmaHandler> LoopHintHandler;
|
||||
std::unique_ptr<PragmaHandler> UnrollHintHandler;
|
||||
|
||||
std::unique_ptr<CommentHandler> CommentSemaHandler;
|
||||
|
||||
|
@ -522,7 +523,7 @@ private:
|
|||
StmtResult HandlePragmaCaptured();
|
||||
|
||||
/// \brief Handle the annotation token produced for
|
||||
/// #pragma vectorize...
|
||||
/// #pragma clang loop and #pragma unroll.
|
||||
LoopHint HandlePragmaLoopHint();
|
||||
|
||||
/// GetLookAheadToken - This peeks ahead N tokens and returns that token
|
||||
|
|
|
@ -17,13 +17,22 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Loop hint specified by a pragma loop directive.
|
||||
/// \brief Loop optimization hint for loop and unroll pragmas.
|
||||
struct LoopHint {
|
||||
// Source range of the directive.
|
||||
SourceRange Range;
|
||||
Expr *ValueExpr;
|
||||
IdentifierLoc *LoopLoc;
|
||||
IdentifierLoc *ValueLoc;
|
||||
// Identifier corresponding to the name of the pragma. "loop" for
|
||||
// "#pragma clang loop" directives and "unroll" for "#pragma unroll"
|
||||
// hints.
|
||||
IdentifierLoc *PragmaNameLoc;
|
||||
// Name of the loop hint. Examples: "unroll", "vectorize". In the
|
||||
// "#pragma unroll" case, this is identical to PragmaNameLoc.
|
||||
IdentifierLoc *OptionLoc;
|
||||
// Identifier for the hint argument. If null, then the hint has no argument
|
||||
// such as for "#pragma unroll".
|
||||
IdentifierLoc *ValueLoc;
|
||||
// Expression for the hint argument if it exists, null otherwise.
|
||||
Expr *ValueExpr;
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
@ -148,6 +148,12 @@ struct PragmaLoopHintHandler : public PragmaHandler {
|
|||
Token &FirstToken) override;
|
||||
};
|
||||
|
||||
struct PragmaUnrollHintHandler : public PragmaHandler {
|
||||
PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {}
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
|
||||
Token &FirstToken) override;
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
void Parser::initializePragmaHandlers() {
|
||||
|
@ -218,6 +224,9 @@ void Parser::initializePragmaHandlers() {
|
|||
|
||||
LoopHintHandler.reset(new PragmaLoopHintHandler());
|
||||
PP.AddPragmaHandler("clang", LoopHintHandler.get());
|
||||
|
||||
UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll"));
|
||||
PP.AddPragmaHandler(UnrollHintHandler.get());
|
||||
}
|
||||
|
||||
void Parser::resetPragmaHandlers() {
|
||||
|
@ -278,6 +287,9 @@ void Parser::resetPragmaHandlers() {
|
|||
|
||||
PP.RemovePragmaHandler("clang", LoopHintHandler.get());
|
||||
LoopHintHandler.reset();
|
||||
|
||||
PP.RemovePragmaHandler(UnrollHintHandler.get());
|
||||
UnrollHintHandler.reset();
|
||||
}
|
||||
|
||||
/// \brief Handle the annotation token produced for #pragma unused(...)
|
||||
|
@ -649,9 +661,10 @@ bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName,
|
|||
}
|
||||
|
||||
struct PragmaLoopHintInfo {
|
||||
Token Loop;
|
||||
Token Value;
|
||||
Token PragmaName;
|
||||
Token Option;
|
||||
Token Value;
|
||||
bool HasValue;
|
||||
};
|
||||
|
||||
LoopHint Parser::HandlePragmaLoopHint() {
|
||||
|
@ -660,24 +673,30 @@ LoopHint Parser::HandlePragmaLoopHint() {
|
|||
static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue());
|
||||
|
||||
LoopHint Hint;
|
||||
Hint.LoopLoc =
|
||||
IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(),
|
||||
Info->Loop.getIdentifierInfo());
|
||||
Hint.PragmaNameLoc =
|
||||
IdentifierLoc::create(Actions.Context, Info->PragmaName.getLocation(),
|
||||
Info->PragmaName.getIdentifierInfo());
|
||||
Hint.OptionLoc =
|
||||
IdentifierLoc::create(Actions.Context, Info->Option.getLocation(),
|
||||
Info->Option.getIdentifierInfo());
|
||||
Hint.ValueLoc =
|
||||
IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
|
||||
Info->Value.getIdentifierInfo());
|
||||
Hint.Range =
|
||||
SourceRange(Info->Option.getLocation(), Info->Value.getLocation());
|
||||
if (Info->HasValue) {
|
||||
Hint.Range =
|
||||
SourceRange(Info->Option.getLocation(), Info->Value.getLocation());
|
||||
Hint.ValueLoc =
|
||||
IdentifierLoc::create(Actions.Context, Info->Value.getLocation(),
|
||||
Info->Value.getIdentifierInfo());
|
||||
|
||||
// FIXME: We should allow non-type template parameters for the loop hint
|
||||
// value. See bug report #19610
|
||||
if (Info->Value.is(tok::numeric_constant))
|
||||
Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
|
||||
else
|
||||
// FIXME: We should allow non-type template parameters for the loop hint
|
||||
// value. See bug report #19610
|
||||
if (Info->Value.is(tok::numeric_constant))
|
||||
Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get();
|
||||
else
|
||||
Hint.ValueExpr = nullptr;
|
||||
} else {
|
||||
Hint.Range = SourceRange(Info->PragmaName.getLocation());
|
||||
Hint.ValueLoc = nullptr;
|
||||
Hint.ValueExpr = nullptr;
|
||||
}
|
||||
|
||||
return Hint;
|
||||
}
|
||||
|
@ -1650,7 +1669,9 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
|
|||
Token Tok;
|
||||
PP.Lex(Tok);
|
||||
if (Tok.is(tok::eod)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_missing_argument);
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
|
||||
<< "clang optimize"
|
||||
<< "'on' or 'off'";
|
||||
return;
|
||||
}
|
||||
if (Tok.isNot(tok::identifier)) {
|
||||
|
@ -1679,6 +1700,48 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
|
|||
Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation());
|
||||
}
|
||||
|
||||
/// \brief Parses loop or unroll pragma hint value and fills in Info.
|
||||
static bool ParseLoopHintValue(Preprocessor &PP, Token Tok, Token &PragmaName,
|
||||
Token &Option, bool &ValueInParens,
|
||||
PragmaLoopHintInfo &Info) {
|
||||
ValueInParens = Tok.is(tok::l_paren);
|
||||
if (ValueInParens) {
|
||||
PP.Lex(Tok);
|
||||
if (Tok.is(tok::r_paren)) {
|
||||
// Nothing between the parentheses.
|
||||
std::string PragmaString;
|
||||
if (PragmaName.getIdentifierInfo()->getName() == "loop") {
|
||||
PragmaString = "clang loop ";
|
||||
PragmaString += Option.getIdentifierInfo()->getName();
|
||||
} else {
|
||||
assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
|
||||
"Unexpected pragma name");
|
||||
PragmaString = "unroll";
|
||||
}
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument)
|
||||
<< PragmaString << "a positive integer value";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Value should be stored and parsed as a constant expression.
|
||||
Token Value = Tok;
|
||||
|
||||
if (ValueInParens) {
|
||||
PP.Lex(Tok);
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Info.PragmaName = PragmaName;
|
||||
Info.Option = Option;
|
||||
Info.Value = Value;
|
||||
Info.HasValue = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Handle the \#pragma clang loop directive.
|
||||
/// #pragma clang 'loop' loop-hints
|
||||
///
|
||||
|
@ -1720,7 +1783,8 @@ void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP,
|
|||
void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
|
||||
PragmaIntroducerKind Introducer,
|
||||
Token &Tok) {
|
||||
Token Loop = Tok;
|
||||
// Incoming token is "loop" from "#pragma clang loop".
|
||||
Token PragmaName = Tok;
|
||||
SmallVector<Token, 1> TokenList;
|
||||
|
||||
// Lex the optimization option and verify it is an identifier.
|
||||
|
@ -1736,59 +1800,40 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
|
|||
IdentifierInfo *OptionInfo = Tok.getIdentifierInfo();
|
||||
|
||||
bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName())
|
||||
.Case("vectorize", true)
|
||||
.Case("interleave", true)
|
||||
.Case("unroll", true)
|
||||
.Case("vectorize_width", true)
|
||||
.Case("interleave_count", true)
|
||||
.Case("unroll_count", true)
|
||||
.Default(false);
|
||||
.Case("vectorize", true)
|
||||
.Case("interleave", true)
|
||||
.Case("unroll", true)
|
||||
.Case("vectorize_width", true)
|
||||
.Case("interleave_count", true)
|
||||
.Case("unroll_count", true)
|
||||
.Default(false);
|
||||
if (!OptionValid) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option)
|
||||
<< /*MissingOption=*/false << OptionInfo;
|
||||
return;
|
||||
}
|
||||
|
||||
// Read '('
|
||||
PP.Lex(Tok);
|
||||
if (Tok.isNot(tok::l_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: All tokens between '(' and ')' should be stored and parsed as a
|
||||
// constant expression.
|
||||
PP.Lex(Tok);
|
||||
if (Tok.is(tok::r_paren)) {
|
||||
// Nothing between the parentheses.
|
||||
PP.Diag(Tok.getLocation(), diag::err_pragma_loop_missing_argument)
|
||||
<< OptionInfo;
|
||||
return;
|
||||
}
|
||||
Token Value = Tok;
|
||||
|
||||
// Read ')'
|
||||
PP.Lex(Tok);
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren;
|
||||
return;
|
||||
}
|
||||
|
||||
// Get next optimization option.
|
||||
PP.Lex(Tok);
|
||||
|
||||
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
|
||||
Info->Loop = Loop;
|
||||
Info->Option = Option;
|
||||
Info->Value = Value;
|
||||
PP.Lex(Tok);
|
||||
bool ValueInParens;
|
||||
if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
|
||||
return;
|
||||
|
||||
// Generate the vectorization hint token.
|
||||
if (!ValueInParens) {
|
||||
PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren;
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate the loop hint token.
|
||||
Token LoopHintTok;
|
||||
LoopHintTok.startToken();
|
||||
LoopHintTok.setKind(tok::annot_pragma_loop_hint);
|
||||
LoopHintTok.setLocation(Loop.getLocation());
|
||||
LoopHintTok.setLocation(PragmaName.getLocation());
|
||||
LoopHintTok.setAnnotationValue(static_cast<void *>(Info));
|
||||
TokenList.push_back(LoopHintTok);
|
||||
|
||||
// Get next optimization option.
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
|
@ -1804,3 +1849,62 @@ void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP,
|
|||
/*DisableMacroExpansion=*/false,
|
||||
/*OwnsTokens=*/true);
|
||||
}
|
||||
|
||||
/// \brief Handle the loop unroll optimization pragmas.
|
||||
/// #pragma unroll
|
||||
/// #pragma unroll unroll-hint-value
|
||||
/// #pragma unroll '(' unroll-hint-value ')'
|
||||
///
|
||||
/// unroll-hint-value:
|
||||
/// constant-expression
|
||||
///
|
||||
/// Loop unrolling hints are specified with '#pragma unroll'. '#pragma unroll'
|
||||
/// can take a numeric argument optionally contained in parentheses. With no
|
||||
/// argument the directive instructs llvm to try to unroll the loop
|
||||
/// completely. A positive integer argument can be specified to indicate the
|
||||
/// number of times the loop should be unrolled. To maximize compatibility with
|
||||
/// other compilers the unroll count argument can be specified with or without
|
||||
/// parentheses.
|
||||
void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP,
|
||||
PragmaIntroducerKind Introducer,
|
||||
Token &Tok) {
|
||||
// Incoming token is "unroll" of "#pragma unroll".
|
||||
Token PragmaName = Tok;
|
||||
PP.Lex(Tok);
|
||||
auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
|
||||
if (Tok.is(tok::eod)) {
|
||||
// Unroll pragma without an argument.
|
||||
Info->PragmaName = PragmaName;
|
||||
Info->Option = PragmaName;
|
||||
Info->HasValue = false;
|
||||
} else {
|
||||
// Unroll pragma with an argument: "#pragma unroll N" or
|
||||
// "#pragma unroll(N)".
|
||||
bool ValueInParens;
|
||||
if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, ValueInParens,
|
||||
*Info))
|
||||
return;
|
||||
|
||||
// In CUDA, the argument to '#pragma unroll' should not be contained in
|
||||
// parentheses.
|
||||
if (PP.getLangOpts().CUDA && ValueInParens)
|
||||
PP.Diag(Info->Value.getLocation(),
|
||||
diag::warn_pragma_unroll_cuda_value_in_parens);
|
||||
|
||||
PP.Lex(Tok);
|
||||
if (Tok.isNot(tok::eod)) {
|
||||
PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
|
||||
<< "unroll";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate the hint token.
|
||||
Token *TokenArray = new Token[1];
|
||||
TokenArray[0].startToken();
|
||||
TokenArray[0].setKind(tok::annot_pragma_loop_hint);
|
||||
TokenArray[0].setLocation(PragmaName.getLocation());
|
||||
TokenArray[0].setAnnotationValue(static_cast<void *>(Info));
|
||||
PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false,
|
||||
/*OwnsTokens=*/true);
|
||||
}
|
||||
|
|
|
@ -1833,18 +1833,16 @@ StmtResult Parser::ParsePragmaLoopHint(StmtVector &Stmts, bool OnlyStatement,
|
|||
// Create temporary attribute list.
|
||||
ParsedAttributesWithRange TempAttrs(AttrFactory);
|
||||
|
||||
// Get vectorize hints and consume annotated token.
|
||||
// Get loop hints and consume annotated token.
|
||||
while (Tok.is(tok::annot_pragma_loop_hint)) {
|
||||
LoopHint Hint = HandlePragmaLoopHint();
|
||||
ConsumeToken();
|
||||
|
||||
if (!Hint.LoopLoc || !Hint.OptionLoc || !Hint.ValueLoc)
|
||||
continue;
|
||||
|
||||
ArgsUnion ArgHints[] = {Hint.OptionLoc, Hint.ValueLoc,
|
||||
ArgsUnion ArgHints[] = {Hint.PragmaNameLoc, Hint.OptionLoc, Hint.ValueLoc,
|
||||
ArgsUnion(Hint.ValueExpr)};
|
||||
TempAttrs.addNew(Hint.LoopLoc->Ident, Hint.Range, nullptr,
|
||||
Hint.LoopLoc->Loc, ArgHints, 3, AttributeList::AS_Pragma);
|
||||
TempAttrs.addNew(Hint.PragmaNameLoc->Ident, Hint.Range, nullptr,
|
||||
Hint.PragmaNameLoc->Loc, ArgHints, 4,
|
||||
AttributeList::AS_Pragma);
|
||||
}
|
||||
|
||||
// Get the next statement.
|
||||
|
|
|
@ -45,35 +45,50 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
|
|||
|
||||
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
|
||||
SourceRange) {
|
||||
IdentifierLoc *PragmaNameLoc = A.getArgAsIdent(0);
|
||||
IdentifierLoc *OptionLoc = A.getArgAsIdent(1);
|
||||
IdentifierInfo *OptionInfo = OptionLoc->Ident;
|
||||
IdentifierLoc *ValueLoc = A.getArgAsIdent(2);
|
||||
IdentifierInfo *ValueInfo = ValueLoc ? ValueLoc->Ident : nullptr;
|
||||
Expr *ValueExpr = A.getArgAsExpr(3);
|
||||
|
||||
assert(OptionInfo && "Attribute must have valid option info.");
|
||||
|
||||
if (St->getStmtClass() != Stmt::DoStmtClass &&
|
||||
St->getStmtClass() != Stmt::ForStmtClass &&
|
||||
St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
|
||||
St->getStmtClass() != Stmt::WhileStmtClass) {
|
||||
S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop);
|
||||
const char *Pragma = PragmaNameLoc->Ident->getName() == "unroll"
|
||||
? "#pragma unroll"
|
||||
: "#pragma clang loop";
|
||||
S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IdentifierLoc *OptionLoc = A.getArgAsIdent(0);
|
||||
IdentifierInfo *OptionInfo = OptionLoc->Ident;
|
||||
IdentifierLoc *ValueLoc = A.getArgAsIdent(1);
|
||||
IdentifierInfo *ValueInfo = ValueLoc->Ident;
|
||||
Expr *ValueExpr = A.getArgAsExpr(2);
|
||||
|
||||
assert(OptionInfo && "Attribute must have valid option info.");
|
||||
|
||||
LoopHintAttr::OptionType Option =
|
||||
llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
|
||||
.Case("vectorize", LoopHintAttr::Vectorize)
|
||||
.Case("vectorize_width", LoopHintAttr::VectorizeWidth)
|
||||
.Case("interleave", LoopHintAttr::Interleave)
|
||||
.Case("interleave_count", LoopHintAttr::InterleaveCount)
|
||||
.Case("unroll", LoopHintAttr::Unroll)
|
||||
.Case("unroll_count", LoopHintAttr::UnrollCount)
|
||||
.Default(LoopHintAttr::Vectorize);
|
||||
LoopHintAttr::OptionType Option;
|
||||
LoopHintAttr::Spelling Spelling;
|
||||
if (PragmaNameLoc->Ident->getName() == "unroll") {
|
||||
Option = ValueLoc ? LoopHintAttr::UnrollCount : LoopHintAttr::Unroll;
|
||||
Spelling = LoopHintAttr::Pragma_unroll;
|
||||
} else {
|
||||
Option = llvm::StringSwitch<LoopHintAttr::OptionType>(OptionInfo->getName())
|
||||
.Case("vectorize", LoopHintAttr::Vectorize)
|
||||
.Case("vectorize_width", LoopHintAttr::VectorizeWidth)
|
||||
.Case("interleave", LoopHintAttr::Interleave)
|
||||
.Case("interleave_count", LoopHintAttr::InterleaveCount)
|
||||
.Case("unroll", LoopHintAttr::Unroll)
|
||||
.Case("unroll_count", LoopHintAttr::UnrollCount)
|
||||
.Default(LoopHintAttr::Vectorize);
|
||||
Spelling = LoopHintAttr::Pragma_clang_loop;
|
||||
}
|
||||
|
||||
int ValueInt;
|
||||
if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave ||
|
||||
Option == LoopHintAttr::Unroll) {
|
||||
if (Option == LoopHintAttr::Unroll &&
|
||||
Spelling == LoopHintAttr::Pragma_unroll) {
|
||||
ValueInt = 1;
|
||||
} else if (Option == LoopHintAttr::Vectorize ||
|
||||
Option == LoopHintAttr::Interleave ||
|
||||
Option == LoopHintAttr::Unroll) {
|
||||
if (!ValueInfo) {
|
||||
S.Diag(ValueLoc->Loc, diag::err_pragma_loop_invalid_keyword);
|
||||
return nullptr;
|
||||
|
@ -100,12 +115,12 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
|
|||
} else
|
||||
llvm_unreachable("Unknown loop hint option");
|
||||
|
||||
return LoopHintAttr::CreateImplicit(S.Context, Option, ValueInt,
|
||||
return LoopHintAttr::CreateImplicit(S.Context, Spelling, Option, ValueInt,
|
||||
A.getRange());
|
||||
}
|
||||
|
||||
static void
|
||||
CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
|
||||
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:
|
||||
|
@ -113,18 +128,9 @@ CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
|
|||
// accumulate the hints encountered while iterating through the
|
||||
// attributes to check for compatibility.
|
||||
struct {
|
||||
int EnableOptionId;
|
||||
int NumericOptionId;
|
||||
bool EnabledIsSet;
|
||||
bool ValueIsSet;
|
||||
bool Enabled;
|
||||
int Value;
|
||||
} Options[] = {{LoopHintAttr::Vectorize, LoopHintAttr::VectorizeWidth, false,
|
||||
false, false, 0},
|
||||
{LoopHintAttr::Interleave, LoopHintAttr::InterleaveCount,
|
||||
false, false, false, 0},
|
||||
{LoopHintAttr::Unroll, LoopHintAttr::UnrollCount, false, false,
|
||||
false, 0}};
|
||||
const LoopHintAttr *EnableAttr;
|
||||
const LoopHintAttr *NumericAttr;
|
||||
} HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
|
||||
|
||||
for (const auto *I : Attrs) {
|
||||
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
|
||||
|
@ -134,8 +140,6 @@ CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
|
|||
continue;
|
||||
|
||||
int Option = LH->getOption();
|
||||
int ValueInt = LH->getValue();
|
||||
|
||||
int Category;
|
||||
switch (Option) {
|
||||
case LoopHintAttr::Vectorize:
|
||||
|
@ -152,44 +156,34 @@ CheckForIncompatibleAttributes(Sema &S, SmallVectorImpl<const Attr *> &Attrs) {
|
|||
break;
|
||||
};
|
||||
|
||||
auto &CategoryState = Options[Category];
|
||||
SourceLocation ValueLoc = LH->getRange().getEnd();
|
||||
auto &CategoryState = HintAttrs[Category];
|
||||
SourceLocation OptionLoc = LH->getRange().getBegin();
|
||||
const LoopHintAttr *PrevAttr;
|
||||
if (Option == LoopHintAttr::Vectorize ||
|
||||
Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
|
||||
// Enable|disable hint. For example, vectorize(enable).
|
||||
if (CategoryState.EnabledIsSet) {
|
||||
// Cannot specify enable/disable state twice.
|
||||
S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
|
||||
<< /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
|
||||
<< LoopHintAttr::getValueName(CategoryState.Enabled)
|
||||
<< LoopHintAttr::getOptionName(Option)
|
||||
<< LoopHintAttr::getValueName(ValueInt);
|
||||
}
|
||||
CategoryState.EnabledIsSet = true;
|
||||
CategoryState.Enabled = ValueInt;
|
||||
PrevAttr = CategoryState.EnableAttr;
|
||||
CategoryState.EnableAttr = LH;
|
||||
} else {
|
||||
// Numeric hint. For example, unroll_count(8).
|
||||
if (CategoryState.ValueIsSet) {
|
||||
// Cannot specify numeric hint twice.
|
||||
S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
|
||||
<< /*Duplicate=*/true << LoopHintAttr::getOptionName(Option)
|
||||
<< CategoryState.Value << LoopHintAttr::getOptionName(Option)
|
||||
<< ValueInt;
|
||||
}
|
||||
CategoryState.ValueIsSet = true;
|
||||
CategoryState.Value = ValueInt;
|
||||
// Numeric hint. For example, vectorize_width(8).
|
||||
PrevAttr = CategoryState.NumericAttr;
|
||||
CategoryState.NumericAttr = LH;
|
||||
}
|
||||
|
||||
if (CategoryState.EnabledIsSet && !CategoryState.Enabled &&
|
||||
CategoryState.ValueIsSet) {
|
||||
if (PrevAttr)
|
||||
// Cannot specify same type of attribute twice.
|
||||
S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
|
||||
<< /*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.
|
||||
S.Diag(ValueLoc, diag::err_pragma_loop_compatibility)
|
||||
S.Diag(OptionLoc, diag::err_pragma_loop_compatibility)
|
||||
<< /*Duplicate=*/false
|
||||
<< LoopHintAttr::getOptionName(CategoryState.EnableOptionId)
|
||||
<< LoopHintAttr::getValueName(CategoryState.Enabled)
|
||||
<< LoopHintAttr::getOptionName(CategoryState.NumericOptionId)
|
||||
<< CategoryState.Value;
|
||||
<< CategoryState.EnableAttr->getDiagnosticName()
|
||||
<< CategoryState.NumericAttr->getDiagnosticName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
// Verify while loop is recognized after unroll pragma.
|
||||
void while_test(int *List, int Length) {
|
||||
// CHECK: define {{.*}} @_Z10while_test
|
||||
int i = 0;
|
||||
|
||||
#pragma unroll
|
||||
while (i < Length) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_1:.*]]
|
||||
List[i] = i * 2;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify do loop is recognized after multi-option pragma clang loop directive.
|
||||
void do_test(int *List, int Length) {
|
||||
int i = 0;
|
||||
|
||||
#pragma unroll 16
|
||||
do {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_2:.*]]
|
||||
List[i] = i * 2;
|
||||
i++;
|
||||
} while (i < Length);
|
||||
}
|
||||
|
||||
// Verify for loop is recognized after unroll pragma.
|
||||
void for_test(int *List, int Length) {
|
||||
#pragma unroll 8
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_3:.*]]
|
||||
List[i] = i * 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify c++11 for range loop is recognized after unroll pragma.
|
||||
void for_range_test() {
|
||||
double List[100];
|
||||
|
||||
#pragma unroll(4)
|
||||
for (int i : List) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_4:.*]]
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
#define UNROLLCOUNT 8
|
||||
|
||||
// Verify defines are correctly resolved in unroll pragmas.
|
||||
void for_define_test(int *List, int Length, int Value) {
|
||||
#pragma unroll(UNROLLCOUNT)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_5:.*]]
|
||||
List[i] = i * Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify metadata is generated when template is used.
|
||||
template <typename A>
|
||||
void for_template_test(A *List, int Length, A Value) {
|
||||
#pragma unroll 8
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_6:.*]]
|
||||
List[i] = i * Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify define is resolved correctly when template is used.
|
||||
template <typename A>
|
||||
void for_template_define_test(A *List, int Length, A Value) {
|
||||
#pragma unroll(UNROLLCOUNT)
|
||||
for (int i = 0; i < Length; i++) {
|
||||
// CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
|
||||
List[i] = i * Value;
|
||||
}
|
||||
}
|
||||
|
||||
#undef UNROLLCOUNT
|
||||
|
||||
// Use templates defined above. Test verifies metadata is generated correctly.
|
||||
void template_test(double *List, int Length) {
|
||||
double Value = 10;
|
||||
|
||||
for_template_test<double>(List, Length, Value);
|
||||
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_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:.*]]}
|
||||
// CHECK: ![[UNROLL_8]] = metadata !{metadata !"llvm.loop.unroll.count", i32 8}
|
||||
// CHECK: ![[LOOP_4]] = metadata !{metadata ![[LOOP_4]], metadata ![[UNROLL_4:.*]]}
|
||||
// CHECK: ![[UNROLL_4]] = metadata !{metadata !"llvm.loop.unroll.count", i32 4}
|
||||
// CHECK: ![[LOOP_5]] = metadata !{metadata ![[LOOP_5]], metadata ![[UNROLL_8:.*]]}
|
||||
// CHECK: ![[LOOP_6]] = metadata !{metadata ![[LOOP_6]], metadata ![[UNROLL_8:.*]]}
|
||||
// CHECK: ![[LOOP_7]] = metadata !{metadata ![[LOOP_7]], metadata ![[UNROLL_8:.*]]}
|
|
@ -13,6 +13,8 @@
|
|||
// CHECK: #pragma clang loop unroll(enable)
|
||||
// CHECK: #pragma clang loop interleave(enable)
|
||||
// CHECK: #pragma clang loop vectorize(disable)
|
||||
// CHECK: #pragma unroll
|
||||
// CHECK: #pragma unroll (32)
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
@ -51,6 +53,24 @@ public:
|
|||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void run4(int *List, int Length) {
|
||||
int i = 0;
|
||||
#pragma unroll
|
||||
while (i - 3 < Length) {
|
||||
List[i] = i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
inline void run5(int *List, int Length) {
|
||||
int i = 0;
|
||||
#pragma unroll 32
|
||||
while (i - 3 < Length) {
|
||||
List[i] = i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
@ -63,6 +83,8 @@ void test() {
|
|||
pt.run1(List, 100);
|
||||
pt.run2(List, 100);
|
||||
pt.run3(List, 100);
|
||||
pt.run4(List, 100);
|
||||
pt.run5(List, 100);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,9 +55,9 @@ void test(int *List, int Length) {
|
|||
/* expected-error {{expected ')'}} */ #pragma clang loop interleave_count(4
|
||||
/* expected-error {{expected ')'}} */ #pragma clang loop unroll_count(4
|
||||
|
||||
/* expected-error {{missing argument to loop pragma 'vectorize'}} */ #pragma clang loop vectorize()
|
||||
/* expected-error {{missing argument to loop pragma 'interleave_count'}} */ #pragma clang loop interleave_count()
|
||||
/* expected-error {{missing argument to loop pragma 'unroll'}} */ #pragma clang loop unroll()
|
||||
/* 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 option}} */ #pragma clang loop
|
||||
/* expected-error {{invalid option 'badkeyword'}} */ #pragma clang loop badkeyword
|
||||
|
@ -110,7 +110,7 @@ void test(int *List, int Length) {
|
|||
}
|
||||
|
||||
#pragma clang loop vectorize(enable)
|
||||
/* expected-error {{expected a for, while, or do-while loop to follow the '#pragma clang loop' directive}} */ int j = Length;
|
||||
/* expected-error {{expected a for, while, or do-while loop to follow '#pragma clang loop'}} */ int j = Length;
|
||||
List[0] = List[1];
|
||||
|
||||
while (j-1 < Length) {
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||
|
||||
// Note that this puts the expected lines before the directives to work around
|
||||
// limitations in the -verify mode.
|
||||
|
||||
void test(int *List, int Length) {
|
||||
int i = 0;
|
||||
|
||||
#pragma unroll
|
||||
while (i + 1 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma unroll 4
|
||||
while (i - 1 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma unroll(8)
|
||||
while (i - 2 < 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-warning {{extra tokens at end of '#pragma unroll'}} */ #pragma unroll 1 2
|
||||
while (i-6 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(()
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll -
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(0)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 0
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll(3000000000)
|
||||
/* expected-error {{invalid argument; expected a positive integer value}} */ #pragma unroll 3000000000
|
||||
while (i-8 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma unroll
|
||||
/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll'}} */ int j = Length;
|
||||
#pragma unroll 4
|
||||
/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll'}} */ int k = Length;
|
||||
|
||||
/* expected-error {{incompatible directives 'unroll(disable)' and '#pragma unroll(4)'}} */ #pragma unroll 4
|
||||
#pragma clang loop unroll(disable)
|
||||
while (i-10 < 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)
|
||||
while (i-15 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
/* expected-error {{duplicate directives '#pragma unroll(4)' and '#pragma unroll(4)'}} */ #pragma unroll 4
|
||||
#pragma unroll(4)
|
||||
while (i-16 < Length) {
|
||||
List[i] = i;
|
||||
}
|
||||
|
||||
#pragma unroll
|
||||
/* expected-error {{expected statement}} */ }
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: %clang_cc1 -Wno-cuda-compat -Werror %s
|
||||
// RUN: %clang_cc1 -Wcuda-compat -verify %s
|
||||
// RUN: %clang_cc1 -x c++ -Wcuda-compat -Werror %s
|
||||
|
||||
// Note that this puts the expected lines before the directives to work around
|
||||
// limitations in the -verify mode.
|
||||
|
||||
void test(int *List, int Length) {
|
||||
/* expected-warning {{argument to '#pragma unroll' should not be in parentheses in CUDA C/C++}} */#pragma unroll(4)
|
||||
for (int i = 0; i < Length; ++i) {
|
||||
List[i] = i;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue