r213574 - Add support for '#pragma unroll'.

Mark Heffernan meheff at google.com
Mon Jul 21 11:08:35 PDT 2014


Author: meheff
Date: Mon Jul 21 13:08:34 2014
New Revision: 213574

URL: http://llvm.org/viewvc/llvm-project?rev=213574&view=rev
Log:
Add support for '#pragma unroll'.

Added:
    cfe/trunk/test/CodeGen/pragma-unroll.cpp
    cfe/trunk/test/Parser/pragma-unroll.cpp
    cfe/trunk/test/Parser/warn-cuda-compat.cu
Modified:
    cfe/trunk/docs/ReleaseNotes.rst
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/AttrDocs.td
    cfe/trunk/include/clang/Basic/DiagnosticGroups.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/LoopHint.h
    cfe/trunk/lib/Parse/ParsePragma.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Sema/SemaStmtAttr.cpp
    cfe/trunk/test/PCH/pragma-loop.cpp
    cfe/trunk/test/Parser/pragma-loop.cpp

Modified: cfe/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/ReleaseNotes.rst?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/docs/ReleaseNotes.rst (original)
+++ cfe/trunk/docs/ReleaseNotes.rst Mon Jul 21 13:08:34 2014
@@ -111,6 +111,13 @@ interleaving, and unrolling to be enable
 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
 ---------------------------
 

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Mon Jul 21 13:08:34 2014
@@ -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];
 }

Modified: cfe/trunk/include/clang/Basic/AttrDocs.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/AttrDocs.td (original)
+++ cfe/trunk/include/clang/Basic/AttrDocs.td Mon Jul 21 13:08:34 2014
@@ -1045,3 +1045,45 @@ as interleave and unrolling count can be
 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.
+  }];
+}
+

Modified: cfe/trunk/include/clang/Basic/DiagnosticGroups.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticGroups.td?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticGroups.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticGroups.td Mon Jul 21 13:08:34 2014
@@ -709,3 +709,7 @@ def BackendOptimizationFailure : DiagGro
 // 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">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jul 21 13:08:34 2014
@@ -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_unkno
   "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_crit
 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 {

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 21 13:08:34 2014
@@ -541,10 +541,9 @@ def err_pragma_loop_invalid_value : Erro
 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<

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul 21 13:08:34 2014
@@ -163,6 +163,7 @@ class Parser : public CodeCompletionHand
   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

Modified: cfe/trunk/include/clang/Sema/LoopHint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/LoopHint.h?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/LoopHint.h (original)
+++ cfe/trunk/include/clang/Sema/LoopHint.h Mon Jul 21 13:08:34 2014
@@ -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

Modified: cfe/trunk/lib/Parse/ParsePragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParsePragma.cpp?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParsePragma.cpp (original)
+++ cfe/trunk/lib/Parse/ParsePragma.cpp Mon Jul 21 13:08:34 2014
@@ -148,6 +148,12 @@ struct PragmaLoopHintHandler : public Pr
                     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(Strin
 }
 
 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());
-
-  // 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
+  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
+      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
   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
   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
 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
     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 '('
+    auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo;
     PP.Lex(Tok);
-    if (Tok.isNot(tok::l_paren)) {
-      PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren;
+    bool ValueInParens;
+    if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info))
       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;
+    if (!ValueInParens) {
+      PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren;
       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;
-
-    // Generate the vectorization hint token.
+    // 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
                       /*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);
+}

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Mon Jul 21 13:08:34 2014
@@ -1833,18 +1833,16 @@ StmtResult Parser::ParsePragmaLoopHint(S
   // 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.

Modified: cfe/trunk/lib/Sema/SemaStmtAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAttr.cpp?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp Mon Jul 21 13:08:34 2014
@@ -45,35 +45,50 @@ static Attr *handleFallThroughAttr(Sema
 
 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,
   } 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,
   // 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,
       continue;
 
     int Option = LH->getOption();
-    int ValueInt = LH->getValue();
-
     int Category;
     switch (Option) {
     case LoopHintAttr::Vectorize:
@@ -152,44 +156,34 @@ CheckForIncompatibleAttributes(Sema &S,
       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();
     }
   }
 }

Added: cfe/trunk/test/CodeGen/pragma-unroll.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/pragma-unroll.cpp?rev=213574&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/pragma-unroll.cpp (added)
+++ cfe/trunk/test/CodeGen/pragma-unroll.cpp Mon Jul 21 13:08:34 2014
@@ -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:.*]]}

Modified: cfe/trunk/test/PCH/pragma-loop.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/pragma-loop.cpp?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/test/PCH/pragma-loop.cpp (original)
+++ cfe/trunk/test/PCH/pragma-loop.cpp Mon Jul 21 13:08:34 2014
@@ -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

Modified: cfe/trunk/test/Parser/pragma-loop.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-loop.cpp?rev=213574&r1=213573&r2=213574&view=diff
==============================================================================
--- cfe/trunk/test/Parser/pragma-loop.cpp (original)
+++ cfe/trunk/test/Parser/pragma-loop.cpp Mon Jul 21 13:08:34 2014
@@ -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) {

Added: cfe/trunk/test/Parser/pragma-unroll.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-unroll.cpp?rev=213574&view=auto
==============================================================================
--- cfe/trunk/test/Parser/pragma-unroll.cpp (added)
+++ cfe/trunk/test/Parser/pragma-unroll.cpp Mon Jul 21 13:08:34 2014
@@ -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}} */ }

Added: cfe/trunk/test/Parser/warn-cuda-compat.cu
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/warn-cuda-compat.cu?rev=213574&view=auto
==============================================================================
--- cfe/trunk/test/Parser/warn-cuda-compat.cu (added)
+++ cfe/trunk/test/Parser/warn-cuda-compat.cu Mon Jul 21 13:08:34 2014
@@ -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;
+  }
+}





More information about the cfe-commits mailing list