r338566 - [UnrollAndJam] Add unroll_and_jam pragma handling

David Green via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 1 07:36:12 PDT 2018


Author: dmgreen
Date: Wed Aug  1 07:36:12 2018
New Revision: 338566

URL: http://llvm.org/viewvc/llvm-project?rev=338566&view=rev
Log:
[UnrollAndJam] Add unroll_and_jam pragma handling

This adds support for the unroll_and_jam pragma, to go with the recently
added unroll and jam pass. The name of the pragma is the same as is used
in the Intel compiler, and most of the code works the same as for unroll.

#pragma clang loop unroll_and_jam has been separated into a different
patch. This part adds #pragma unroll_and_jam with an optional count, and
#pragma no_unroll_and_jam to disable the transform.

Differential Revision: https://reviews.llvm.org/D47267


Added:
    cfe/trunk/test/CodeGenCXX/pragma-unroll-and-jam.cpp
    cfe/trunk/test/Parser/pragma-unroll-and-jam.cpp
Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/CodeGen/CGLoopInfo.cpp
    cfe/trunk/lib/CodeGen/CGLoopInfo.h
    cfe/trunk/lib/Parse/ParsePragma.cpp
    cfe/trunk/lib/Sema/SemaStmtAttr.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=338566&r1=338565&r2=338566&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Wed Aug  1 07:36:12 2018
@@ -2748,6 +2748,8 @@ def LoopHint : Attr {
   /// interleave_count: interleaves 'Value' loop iterations.
   /// unroll: fully unroll loop if State == Enable.
   /// unroll_count: unrolls loop 'Value' times.
+  /// unroll_and_jam: attempt to unroll and jam loop if State == Enable.
+  /// unroll_and_jam_count: unroll and jams loop 'Value' times.
   /// distribute: attempt to distribute loop if State == Enable
 
   /// #pragma unroll <argument> directive
@@ -2756,14 +2758,17 @@ def LoopHint : Attr {
   /// expression: unrolls loop 'Value' times.
 
   let Spellings = [Pragma<"clang", "loop">, Pragma<"", "unroll">,
-                   Pragma<"", "nounroll">];
+                   Pragma<"", "nounroll">, Pragma<"", "unroll_and_jam">,
+                   Pragma<"", "nounroll_and_jam">];
 
   /// State of the loop optimization specified by the spelling.
   let Args = [EnumArgument<"Option", "OptionType",
                           ["vectorize", "vectorize_width", "interleave", "interleave_count",
-                           "unroll", "unroll_count", "distribute"],
+                           "unroll", "unroll_count", "unroll_and_jam", "unroll_and_jam_count",
+                           "distribute"],
                           ["Vectorize", "VectorizeWidth", "Interleave", "InterleaveCount",
-                           "Unroll", "UnrollCount", "Distribute"]>,
+                           "Unroll", "UnrollCount", "UnrollAndJam", "UnrollAndJamCount",
+                           "Distribute"]>,
               EnumArgument<"State", "LoopHintState",
                            ["enable", "disable", "numeric", "assume_safety", "full"],
                            ["Enable", "Disable", "Numeric", "AssumeSafety", "Full"]>,
@@ -2778,6 +2783,8 @@ def LoopHint : Attr {
     case InterleaveCount: return "interleave_count";
     case Unroll: return "unroll";
     case UnrollCount: return "unroll_count";
+    case UnrollAndJam: return "unroll_and_jam";
+    case UnrollAndJamCount: return "unroll_and_jam_count";
     case Distribute: return "distribute";
     }
     llvm_unreachable("Unhandled LoopHint option.");
@@ -2787,9 +2794,9 @@ def LoopHint : Attr {
     unsigned SpellingIndex = getSpellingListIndex();
     // For "#pragma unroll" and "#pragma nounroll" the string "unroll" or
     // "nounroll" is already emitted as the pragma name.
-    if (SpellingIndex == Pragma_nounroll)
+    if (SpellingIndex == Pragma_nounroll || SpellingIndex == Pragma_nounroll_and_jam)
       return;
-    else if (SpellingIndex == Pragma_unroll) {
+    else if (SpellingIndex == Pragma_unroll || SpellingIndex == Pragma_unroll_and_jam) {
       OS << ' ' << getValueString(Policy);
       return;
     }
@@ -2825,6 +2832,11 @@ def LoopHint : Attr {
       return "#pragma nounroll";
     else if (SpellingIndex == Pragma_unroll)
       return "#pragma unroll" + (option == UnrollCount ? getValueString(Policy) : "");
+    else if (SpellingIndex == Pragma_nounroll_and_jam)
+      return "#pragma nounroll_and_jam";
+    else if (SpellingIndex == Pragma_unroll_and_jam)
+      return "#pragma unroll_and_jam" +
+        (option == UnrollAndJamCount ? getValueString(Policy) : "");
 
     assert(SpellingIndex == Pragma_clang_loop && "Unexpected spelling");
     return getOptionName(option) + getValueString(Policy);

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=338566&r1=338565&r2=338566&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Aug  1 07:36:12 2018
@@ -185,6 +185,8 @@ class Parser : public CodeCompletionHand
   std::unique_ptr<PragmaHandler> LoopHintHandler;
   std::unique_ptr<PragmaHandler> UnrollHintHandler;
   std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
+  std::unique_ptr<PragmaHandler> UnrollAndJamHintHandler;
+  std::unique_ptr<PragmaHandler> NoUnrollAndJamHintHandler;
   std::unique_ptr<PragmaHandler> FPHandler;
   std::unique_ptr<PragmaHandler> STDCFENVHandler;
   std::unique_ptr<PragmaHandler> STDCCXLIMITHandler;

Modified: cfe/trunk/lib/CodeGen/CGLoopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGLoopInfo.cpp?rev=338566&r1=338565&r2=338566&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGLoopInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGLoopInfo.cpp Wed Aug  1 07:36:12 2018
@@ -25,10 +25,12 @@ static MDNode *createMetadata(LLVMContex
 
   if (!Attrs.IsParallel && Attrs.VectorizeWidth == 0 &&
       Attrs.InterleaveCount == 0 && Attrs.UnrollCount == 0 &&
+      Attrs.UnrollAndJamCount == 0 &&
       Attrs.VectorizeEnable == LoopAttributes::Unspecified &&
       Attrs.UnrollEnable == LoopAttributes::Unspecified &&
-      Attrs.DistributeEnable == LoopAttributes::Unspecified &&
-      !StartLoc && !EndLoc)
+      Attrs.UnrollAndJamEnable == LoopAttributes::Unspecified &&
+      Attrs.DistributeEnable == LoopAttributes::Unspecified && !StartLoc &&
+      !EndLoc)
     return nullptr;
 
   SmallVector<Metadata *, 4> Args;
@@ -61,7 +63,7 @@ static MDNode *createMetadata(LLVMContex
     Args.push_back(MDNode::get(Ctx, Vals));
   }
 
-  // Setting interleave.count
+  // Setting unroll.count
   if (Attrs.UnrollCount > 0) {
     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll.count"),
                         ConstantAsMetadata::get(ConstantInt::get(
@@ -69,6 +71,14 @@ static MDNode *createMetadata(LLVMContex
     Args.push_back(MDNode::get(Ctx, Vals));
   }
 
+  // Setting unroll_and_jam.count
+  if (Attrs.UnrollAndJamCount > 0) {
+    Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.unroll_and_jam.count"),
+                        ConstantAsMetadata::get(ConstantInt::get(
+                            Type::getInt32Ty(Ctx), Attrs.UnrollAndJamCount))};
+    Args.push_back(MDNode::get(Ctx, Vals));
+  }
+
   // Setting vectorize.enable
   if (Attrs.VectorizeEnable != LoopAttributes::Unspecified) {
     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.vectorize.enable"),
@@ -91,6 +101,19 @@ static MDNode *createMetadata(LLVMContex
     Args.push_back(MDNode::get(Ctx, Vals));
   }
 
+  // Setting unroll_and_jam.full or unroll_and_jam.disable
+  if (Attrs.UnrollAndJamEnable != LoopAttributes::Unspecified) {
+    std::string Name;
+    if (Attrs.UnrollAndJamEnable == LoopAttributes::Enable)
+      Name = "llvm.loop.unroll_and_jam.enable";
+    else if (Attrs.UnrollAndJamEnable == LoopAttributes::Full)
+      Name = "llvm.loop.unroll_and_jam.full";
+    else
+      Name = "llvm.loop.unroll_and_jam.disable";
+    Metadata *Vals[] = {MDString::get(Ctx, Name)};
+    Args.push_back(MDNode::get(Ctx, Vals));
+  }
+
   if (Attrs.DistributeEnable != LoopAttributes::Unspecified) {
     Metadata *Vals[] = {MDString::get(Ctx, "llvm.loop.distribute.enable"),
                         ConstantAsMetadata::get(ConstantInt::get(
@@ -107,8 +130,9 @@ static MDNode *createMetadata(LLVMContex
 
 LoopAttributes::LoopAttributes(bool IsParallel)
     : IsParallel(IsParallel), VectorizeEnable(LoopAttributes::Unspecified),
-      UnrollEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
-      InterleaveCount(0), UnrollCount(0),
+      UnrollEnable(LoopAttributes::Unspecified),
+      UnrollAndJamEnable(LoopAttributes::Unspecified), VectorizeWidth(0),
+      InterleaveCount(0), UnrollCount(0), UnrollAndJamCount(0),
       DistributeEnable(LoopAttributes::Unspecified) {}
 
 void LoopAttributes::clear() {
@@ -116,8 +140,10 @@ void LoopAttributes::clear() {
   VectorizeWidth = 0;
   InterleaveCount = 0;
   UnrollCount = 0;
+  UnrollAndJamCount = 0;
   VectorizeEnable = LoopAttributes::Unspecified;
   UnrollEnable = LoopAttributes::Unspecified;
+  UnrollAndJamEnable = LoopAttributes::Unspecified;
   DistributeEnable = LoopAttributes::Unspecified;
 }
 
@@ -191,10 +217,14 @@ void LoopInfoStack::push(BasicBlock *Hea
       case LoopHintAttr::Unroll:
         setUnrollState(LoopAttributes::Disable);
         break;
+      case LoopHintAttr::UnrollAndJam:
+        setUnrollAndJamState(LoopAttributes::Disable);
+        break;
       case LoopHintAttr::Distribute:
         setDistributeState(false);
         break;
       case LoopHintAttr::UnrollCount:
+      case LoopHintAttr::UnrollAndJamCount:
       case LoopHintAttr::VectorizeWidth:
       case LoopHintAttr::InterleaveCount:
         llvm_unreachable("Options cannot be disabled.");
@@ -210,10 +240,14 @@ void LoopInfoStack::push(BasicBlock *Hea
       case LoopHintAttr::Unroll:
         setUnrollState(LoopAttributes::Enable);
         break;
+      case LoopHintAttr::UnrollAndJam:
+        setUnrollAndJamState(LoopAttributes::Enable);
+        break;
       case LoopHintAttr::Distribute:
         setDistributeState(true);
         break;
       case LoopHintAttr::UnrollCount:
+      case LoopHintAttr::UnrollAndJamCount:
       case LoopHintAttr::VectorizeWidth:
       case LoopHintAttr::InterleaveCount:
         llvm_unreachable("Options cannot enabled.");
@@ -229,7 +263,9 @@ void LoopInfoStack::push(BasicBlock *Hea
         setVectorizeEnable(true);
         break;
       case LoopHintAttr::Unroll:
+      case LoopHintAttr::UnrollAndJam:
       case LoopHintAttr::UnrollCount:
+      case LoopHintAttr::UnrollAndJamCount:
       case LoopHintAttr::VectorizeWidth:
       case LoopHintAttr::InterleaveCount:
       case LoopHintAttr::Distribute:
@@ -242,9 +278,13 @@ void LoopInfoStack::push(BasicBlock *Hea
       case LoopHintAttr::Unroll:
         setUnrollState(LoopAttributes::Full);
         break;
+      case LoopHintAttr::UnrollAndJam:
+        setUnrollAndJamState(LoopAttributes::Full);
+        break;
       case LoopHintAttr::Vectorize:
       case LoopHintAttr::Interleave:
       case LoopHintAttr::UnrollCount:
+      case LoopHintAttr::UnrollAndJamCount:
       case LoopHintAttr::VectorizeWidth:
       case LoopHintAttr::InterleaveCount:
       case LoopHintAttr::Distribute:
@@ -263,7 +303,11 @@ void LoopInfoStack::push(BasicBlock *Hea
       case LoopHintAttr::UnrollCount:
         setUnrollCount(ValueInt);
         break;
+      case LoopHintAttr::UnrollAndJamCount:
+        setUnrollAndJamCount(ValueInt);
+        break;
       case LoopHintAttr::Unroll:
+      case LoopHintAttr::UnrollAndJam:
       case LoopHintAttr::Vectorize:
       case LoopHintAttr::Interleave:
       case LoopHintAttr::Distribute:

Modified: cfe/trunk/lib/CodeGen/CGLoopInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGLoopInfo.h?rev=338566&r1=338565&r2=338566&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGLoopInfo.h (original)
+++ cfe/trunk/lib/CodeGen/CGLoopInfo.h Wed Aug  1 07:36:12 2018
@@ -49,6 +49,9 @@ struct LoopAttributes {
   /// Value for llvm.loop.unroll.* metadata (enable, disable, or full).
   LVEnableState UnrollEnable;
 
+  /// Value for llvm.loop.unroll_and_jam.* metadata (enable, disable, or full).
+  LVEnableState UnrollAndJamEnable;
+
   /// Value for llvm.loop.vectorize.width metadata.
   unsigned VectorizeWidth;
 
@@ -58,6 +61,9 @@ struct LoopAttributes {
   /// llvm.unroll.
   unsigned UnrollCount;
 
+  /// llvm.unroll.
+  unsigned UnrollAndJamCount;
+
   /// Value for llvm.loop.distribute.enable metadata.
   LVEnableState DistributeEnable;
 };
@@ -143,6 +149,11 @@ public:
     StagedAttrs.UnrollEnable = State;
   }
 
+  /// Set the next pushed loop unroll_and_jam state.
+  void setUnrollAndJamState(const LoopAttributes::LVEnableState &State) {
+    StagedAttrs.UnrollAndJamEnable = State;
+  }
+
   /// Set the vectorize width for the next loop pushed.
   void setVectorizeWidth(unsigned W) { StagedAttrs.VectorizeWidth = W; }
 
@@ -152,6 +163,9 @@ public:
   /// Set the unroll count for the next loop pushed.
   void setUnrollCount(unsigned C) { StagedAttrs.UnrollCount = C; }
 
+  /// \brief Set the unroll count for the next loop pushed.
+  void setUnrollAndJamCount(unsigned C) { StagedAttrs.UnrollAndJamCount = C; }
+
 private:
   /// Returns true if there is LoopInfo on the stack.
   bool hasInfo() const { return !Active.empty(); }

Modified: cfe/trunk/lib/Parse/ParsePragma.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParsePragma.cpp?rev=338566&r1=338565&r2=338566&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParsePragma.cpp (original)
+++ cfe/trunk/lib/Parse/ParsePragma.cpp Wed Aug  1 07:36:12 2018
@@ -352,6 +352,13 @@ void Parser::initializePragmaHandlers()
   NoUnrollHintHandler.reset(new PragmaUnrollHintHandler("nounroll"));
   PP.AddPragmaHandler(NoUnrollHintHandler.get());
 
+  UnrollAndJamHintHandler.reset(new PragmaUnrollHintHandler("unroll_and_jam"));
+  PP.AddPragmaHandler(UnrollAndJamHintHandler.get());
+
+  NoUnrollAndJamHintHandler.reset(
+      new PragmaUnrollHintHandler("nounroll_and_jam"));
+  PP.AddPragmaHandler(NoUnrollAndJamHintHandler.get());
+
   FPHandler.reset(new PragmaFPHandler());
   PP.AddPragmaHandler("clang", FPHandler.get());
 
@@ -451,6 +458,12 @@ void Parser::resetPragmaHandlers() {
   PP.RemovePragmaHandler(NoUnrollHintHandler.get());
   NoUnrollHintHandler.reset();
 
+  PP.RemovePragmaHandler(UnrollAndJamHintHandler.get());
+  UnrollAndJamHintHandler.reset();
+
+  PP.RemovePragmaHandler(NoUnrollAndJamHintHandler.get());
+  NoUnrollAndJamHintHandler.reset();
+
   PP.RemovePragmaHandler("clang", FPHandler.get());
   FPHandler.reset();
 
@@ -955,6 +968,8 @@ static std::string PragmaLoopHintString(
   if (PragmaName.getIdentifierInfo()->getName() == "loop") {
     PragmaString = "clang loop ";
     PragmaString += Option.getIdentifierInfo()->getName();
+  } else if (PragmaName.getIdentifierInfo()->getName() == "unroll_and_jam") {
+    PragmaString = "unroll_and_jam";
   } else {
     assert(PragmaName.getIdentifierInfo()->getName() == "unroll" &&
            "Unexpected pragma name");
@@ -986,7 +1001,10 @@ bool Parser::HandlePragmaLoopHint(LoopHi
   // without an argument.
   bool PragmaUnroll = PragmaNameInfo->getName() == "unroll";
   bool PragmaNoUnroll = PragmaNameInfo->getName() == "nounroll";
-  if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll)) {
+  bool PragmaUnrollAndJam = PragmaNameInfo->getName() == "unroll_and_jam";
+  bool PragmaNoUnrollAndJam = PragmaNameInfo->getName() == "nounroll_and_jam";
+  if (Toks.empty() && (PragmaUnroll || PragmaNoUnroll || PragmaUnrollAndJam ||
+                       PragmaNoUnrollAndJam)) {
     ConsumeAnnotationToken();
     Hint.Range = Info->PragmaName.getLocation();
     return true;
@@ -999,24 +1017,28 @@ bool Parser::HandlePragmaLoopHint(LoopHi
 
   // If no option is specified the argument is assumed to be a constant expr.
   bool OptionUnroll = false;
+  bool OptionUnrollAndJam = false;
   bool OptionDistribute = false;
   bool StateOption = false;
   if (OptionInfo) { // Pragma Unroll does not specify an option.
     OptionUnroll = OptionInfo->isStr("unroll");
+    OptionUnrollAndJam = OptionInfo->isStr("unroll_and_jam");
     OptionDistribute = OptionInfo->isStr("distribute");
     StateOption = llvm::StringSwitch<bool>(OptionInfo->getName())
                       .Case("vectorize", true)
                       .Case("interleave", true)
                       .Default(false) ||
-                  OptionUnroll || OptionDistribute;
+                  OptionUnroll || OptionUnrollAndJam || OptionDistribute;
   }
 
-  bool AssumeSafetyArg = !OptionUnroll && !OptionDistribute;
+  bool AssumeSafetyArg =
+      !OptionUnroll && !OptionUnrollAndJam && !OptionDistribute;
   // Verify loop hint has an argument.
   if (Toks[0].is(tok::eof)) {
     ConsumeAnnotationToken();
     Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument)
-        << /*StateArgument=*/StateOption << /*FullKeyword=*/OptionUnroll
+        << /*StateArgument=*/StateOption
+        << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam)
         << /*AssumeSafetyKeyword=*/AssumeSafetyArg;
     return false;
   }
@@ -1027,15 +1049,15 @@ bool Parser::HandlePragmaLoopHint(LoopHi
     SourceLocation StateLoc = Toks[0].getLocation();
     IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo();
 
-    bool Valid = StateInfo &&
-                 llvm::StringSwitch<bool>(StateInfo->getName())
-                     .Cases("enable", "disable", true)
-                     .Case("full", OptionUnroll)
-                     .Case("assume_safety", AssumeSafetyArg)
-                     .Default(false);
+    bool Valid =
+        StateInfo && llvm::StringSwitch<bool>(StateInfo->getName())
+                         .Cases("enable", "disable", true)
+                         .Case("full", OptionUnroll || OptionUnrollAndJam)
+                         .Case("assume_safety", AssumeSafetyArg)
+                         .Default(false);
     if (!Valid) {
       Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword)
-          << /*FullKeyword=*/OptionUnroll
+          << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam)
           << /*AssumeSafetyKeyword=*/AssumeSafetyArg;
       return false;
     }
@@ -2844,6 +2866,10 @@ void PragmaLoopHintHandler::HandlePragma
 ///  #pragma unroll unroll-hint-value
 ///  #pragma unroll '(' unroll-hint-value ')'
 ///  #pragma nounroll
+///  #pragma unroll_and_jam
+///  #pragma unroll_and_jam unroll-hint-value
+///  #pragma unroll_and_jam '(' unroll-hint-value ')'
+///  #pragma nounroll_and_jam
 ///
 ///  unroll-hint-value:
 ///    constant-expression
@@ -2868,9 +2894,10 @@ void PragmaUnrollHintHandler::HandlePrag
     // nounroll or unroll pragma without an argument.
     Info->PragmaName = PragmaName;
     Info->Option.startToken();
-  } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll") {
+  } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll" ||
+             PragmaName.getIdentifierInfo()->getName() == "nounroll_and_jam") {
     PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
-        << "nounroll";
+        << PragmaName.getIdentifierInfo()->getName();
     return;
   } else {
     // Unroll pragma with an argument: "#pragma unroll N" or

Modified: cfe/trunk/lib/Sema/SemaStmtAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmtAttr.cpp?rev=338566&r1=338565&r2=338566&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmtAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmtAttr.cpp Wed Aug  1 07:36:12 2018
@@ -87,6 +87,9 @@ static Attr *handleLoopHintAttr(Sema &S,
 
   bool PragmaUnroll = PragmaNameLoc->Ident->getName() == "unroll";
   bool PragmaNoUnroll = PragmaNameLoc->Ident->getName() == "nounroll";
+  bool PragmaUnrollAndJam = PragmaNameLoc->Ident->getName() == "unroll_and_jam";
+  bool PragmaNoUnrollAndJam =
+      PragmaNameLoc->Ident->getName() == "nounroll_and_jam";
   if (St->getStmtClass() != Stmt::DoStmtClass &&
       St->getStmtClass() != Stmt::ForStmtClass &&
       St->getStmtClass() != Stmt::CXXForRangeStmtClass &&
@@ -95,6 +98,8 @@ static Attr *handleLoopHintAttr(Sema &S,
         llvm::StringSwitch<const char *>(PragmaNameLoc->Ident->getName())
             .Case("unroll", "#pragma unroll")
             .Case("nounroll", "#pragma nounroll")
+            .Case("unroll_and_jam", "#pragma unroll_and_jam")
+            .Case("nounroll_and_jam", "#pragma nounroll_and_jam")
             .Default("#pragma clang loop");
     S.Diag(St->getLocStart(), diag::err_pragma_loop_precedes_nonloop) << Pragma;
     return nullptr;
@@ -118,6 +123,20 @@ static Attr *handleLoopHintAttr(Sema &S,
       Option = LoopHintAttr::Unroll;
       State = LoopHintAttr::Enable;
     }
+  } else if (PragmaNoUnrollAndJam) {
+    // #pragma nounroll_and_jam
+    Option = LoopHintAttr::UnrollAndJam;
+    State = LoopHintAttr::Disable;
+  } else if (PragmaUnrollAndJam) {
+    if (ValueExpr) {
+      // #pragma unroll_and_jam N
+      Option = LoopHintAttr::UnrollAndJamCount;
+      State = LoopHintAttr::Numeric;
+    } else {
+      // #pragma unroll_and_jam
+      Option = LoopHintAttr::UnrollAndJam;
+      State = LoopHintAttr::Enable;
+    }
   } else {
     // #pragma clang loop ...
     assert(OptionLoc && OptionLoc->Ident &&
@@ -165,20 +184,22 @@ static Attr *handleLoopHintAttr(Sema &S,
 static void
 CheckForIncompatibleAttributes(Sema &S,
                                const SmallVectorImpl<const Attr *> &Attrs) {
-  // There are 4 categories of loop hints attributes: vectorize, interleave,
-  // unroll and distribute. Except for distribute they come in two variants: a
-  // state form and a numeric form.  The state form selectively
-  // defaults/enables/disables the transformation for the loop (for unroll,
-  // default indicates full unrolling rather than enabling the transformation).
-  // The numeric form form 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.
+  // There are 5 categories of loop hints attributes: vectorize, interleave,
+  // unroll, unroll_and_jam and distribute. Except for distribute they come
+  // in two variants: a state form and a numeric form.  The state form
+  // selectively defaults/enables/disables the transformation for the loop
+  // (for unroll, default indicates full unrolling rather than enabling the
+  // transformation). The numeric form form 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 *StateAttr;
     const LoopHintAttr *NumericAttr;
   } HintAttrs[] = {{nullptr, nullptr},
                    {nullptr, nullptr},
                    {nullptr, nullptr},
+                   {nullptr, nullptr},
                    {nullptr, nullptr}};
 
   for (const auto *I : Attrs) {
@@ -189,7 +210,7 @@ CheckForIncompatibleAttributes(Sema &S,
       continue;
 
     LoopHintAttr::OptionType Option = LH->getOption();
-    enum { Vectorize, Interleave, Unroll, Distribute } Category;
+    enum { Vectorize, Interleave, Unroll, UnrollAndJam, Distribute } Category;
     switch (Option) {
     case LoopHintAttr::Vectorize:
     case LoopHintAttr::VectorizeWidth:
@@ -203,16 +224,22 @@ CheckForIncompatibleAttributes(Sema &S,
     case LoopHintAttr::UnrollCount:
       Category = Unroll;
       break;
+    case LoopHintAttr::UnrollAndJam:
+    case LoopHintAttr::UnrollAndJamCount:
+      Category = UnrollAndJam;
+      break;
     case LoopHintAttr::Distribute:
       // Perform the check for duplicated 'distribute' hints.
       Category = Distribute;
       break;
     };
 
+    assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0]));
     auto &CategoryState = HintAttrs[Category];
     const LoopHintAttr *PrevAttr;
     if (Option == LoopHintAttr::Vectorize ||
         Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
+        Option == LoopHintAttr::UnrollAndJam ||
         Option == LoopHintAttr::Distribute) {
       // Enable|Disable|AssumeSafety hint.  For example, vectorize(enable).
       PrevAttr = CategoryState.StateAttr;
@@ -232,7 +259,7 @@ CheckForIncompatibleAttributes(Sema &S,
           << LH->getDiagnosticName(Policy);
 
     if (CategoryState.StateAttr && CategoryState.NumericAttr &&
-        (Category == Unroll ||
+        (Category == Unroll || Category == UnrollAndJam ||
          CategoryState.StateAttr->getState() == LoopHintAttr::Disable)) {
       // Disable hints are not compatible with numeric hints of the same
       // category.  As a special case, numeric unroll hints are also not

Added: cfe/trunk/test/CodeGenCXX/pragma-unroll-and-jam.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/pragma-unroll-and-jam.cpp?rev=338566&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/pragma-unroll-and-jam.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/pragma-unroll-and-jam.cpp Wed Aug  1 07:36:12 2018
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 -triple arm-none-eabi -std=c++11 -emit-llvm -o - %s | FileCheck %s
+
+void unroll_and_jam(int *List, int Length, int Value) {
+  // CHECK-LABEL: define {{.*}} @_Z14unroll_and_jam
+#pragma unroll_and_jam
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_1:.*]]
+      List[i * Length + j] = Value;
+    }
+  }
+}
+
+void unroll_and_jam_count(int *List, int Length, int Value) {
+  // CHECK-LABEL: define {{.*}} @_Z20unroll_and_jam_count
+#pragma unroll_and_jam(4)
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_2:.*]]
+      List[i * Length + j] = Value;
+    }
+  }
+}
+
+void nounroll_and_jam(int *List, int Length, int Value) {
+  // CHECK-LABEL: define {{.*}} @_Z16nounroll_and_jam
+#pragma nounroll_and_jam
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_3:.*]]
+      List[i * Length + j] = Value;
+    }
+  }
+}
+
+void clang_unroll_plus_nounroll_and_jam(int *List, int Length, int Value) {
+  // CHECK-LABEL: define {{.*}} @_Z34clang_unroll_plus_nounroll_and_jam
+#pragma nounroll_and_jam
+#pragma unroll(4)
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      // CHECK: br label {{.*}}, !llvm.loop ![[LOOP_7:.*]]
+      List[i * Length + j] = Value;
+    }
+  }
+}
+
+// CHECK: ![[LOOP_1]] = distinct !{![[LOOP_1]], ![[UNJ_ENABLE:.*]]}
+// CHECK: ![[UNJ_ENABLE]] = !{!"llvm.loop.unroll_and_jam.enable"}
+// CHECK: ![[LOOP_2]] = distinct !{![[LOOP_2]], ![[UNJ_4:.*]]}
+// CHECK: ![[UNJ_4]] = !{!"llvm.loop.unroll_and_jam.count", i32 4}
+// CHECK: ![[LOOP_3]] = distinct !{![[LOOP_3]], ![[UNJ_DISABLE:.*]]}
+// CHECK: ![[UNJ_DISABLE]] = !{!"llvm.loop.unroll_and_jam.disable"}
+// CHECK: ![[LOOP_7]] = distinct !{![[LOOP_7]], ![[UNROLL_4:.*]], ![[UNJ_DISABLE:.*]]}
+// CHECK: ![[UNROLL_4]] = !{!"llvm.loop.unroll.count", i32 4}

Added: cfe/trunk/test/Parser/pragma-unroll-and-jam.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/pragma-unroll-and-jam.cpp?rev=338566&view=auto
==============================================================================
--- cfe/trunk/test/Parser/pragma-unroll-and-jam.cpp (added)
+++ cfe/trunk/test/Parser/pragma-unroll-and-jam.cpp Wed Aug  1 07:36:12 2018
@@ -0,0 +1,78 @@
+// 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 Value) {
+  int i = 0;
+
+#pragma unroll_and_jam
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+#pragma nounroll_and_jam
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+#pragma unroll_and_jam 4
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+/* expected-error {{expected ')'}} */ #pragma unroll_and_jam(4
+/* expected-error {{missing argument; expected an integer value}} */ #pragma unroll_and_jam()
+/* expected-warning {{extra tokens at end of '#pragma unroll_and_jam'}} */ #pragma unroll_and_jam 1 2
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+/* expected-warning {{extra tokens at end of '#pragma nounroll_and_jam'}} */ #pragma nounroll_and_jam 1
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+#pragma unroll_and_jam
+/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll_and_jam'}} */ int j = Length;
+#pragma unroll_and_jam 4
+/* expected-error {{expected a for, while, or do-while loop to follow '#pragma unroll_and_jam'}} */ int k = Length;
+#pragma nounroll_and_jam
+/* expected-error {{expected a for, while, or do-while loop to follow '#pragma nounroll_and_jam'}} */ int l = Length;
+
+/* expected-error {{incompatible directives '#pragma nounroll_and_jam' and '#pragma unroll_and_jam(4)'}} */ #pragma unroll_and_jam 4
+#pragma nounroll_and_jam
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+#pragma nounroll_and_jam
+#pragma unroll(4)
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+// pragma clang unroll_and_jam is disabled for the moment
+/* expected-error {{invalid option 'unroll_and_jam'; expected vectorize, vectorize_width, interleave, interleave_count, unroll, unroll_count, or distribute}} */ #pragma clang loop unroll_and_jam(4)
+  for (int i = 0; i < Length; i++) {
+    for (int j = 0; j < Length; j++) {
+      List[i * Length + j] = Value;
+    }
+  }
+
+#pragma unroll_and_jam
+/* expected-error {{expected statement}} */ }




More information about the cfe-commits mailing list