summaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorDavid Green <david.green@arm.com>2018-08-01 14:36:12 +0000
committerDavid Green <david.green@arm.com>2018-08-01 14:36:12 +0000
commit68db10fded893cab159ac55a43b162f4c6d8d1c6 (patch)
tree991f41f0e590bba2f2588fcaecc6bdeeaa2851d8 /clang
parent71f322bfc276432e37004ad9f629c9a4a6a260f4 (diff)
[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
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/Attr.td22
-rw-r--r--clang/include/clang/Parse/Parser.h2
-rw-r--r--clang/lib/CodeGen/CGLoopInfo.cpp54
-rw-r--r--clang/lib/CodeGen/CGLoopInfo.h14
-rw-r--r--clang/lib/Parse/ParsePragma.cpp53
-rw-r--r--clang/lib/Sema/SemaStmtAttr.cpp47
-rw-r--r--clang/test/CodeGenCXX/pragma-unroll-and-jam.cpp55
-rw-r--r--clang/test/Parser/pragma-unroll-and-jam.cpp78
8 files changed, 292 insertions, 33 deletions
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index fea8e129d7d..3b40ddb61e3 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -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);
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 69bf88a371d..1d6849cd5b4 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -185,6 +185,8 @@ class Parser : public CodeCompletionHandler {
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;
diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp
index 21e2b8dd8c3..09089bf8160 100644
--- a/clang/lib/CodeGen/CGLoopInfo.cpp
+++ b/clang/lib/CodeGen/CGLoopInfo.cpp
@@ -25,10 +25,12 @@ static MDNode *createMetadata(LLVMContext &Ctx, const LoopAttributes &Attrs,
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(LLVMContext &Ctx, const LoopAttributes &Attrs,
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(LLVMContext &Ctx, const LoopAttributes &Attrs,
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(LLVMContext &Ctx, const LoopAttributes &Attrs,
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(LLVMContext &Ctx, const LoopAttributes &Attrs,
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 *Header, clang::ASTContext &Ctx,
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 *Header, clang::ASTContext &Ctx,
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 *Header, clang::ASTContext &Ctx,
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 *Header, clang::ASTContext &Ctx,
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 *Header, clang::ASTContext &Ctx,
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:
diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h
index 9d5f23ff9a2..466fdc9fedd 100644
--- a/clang/lib/CodeGen/CGLoopInfo.h
+++ b/clang/lib/CodeGen/CGLoopInfo.h
@@ -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(); }
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 07f48e0779d..fb862c706f9 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -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(Token PragmaName, Token Option) {
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(LoopHint &Hint) {
// 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(LoopHint &Hint) {
// 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(LoopHint &Hint) {
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(Preprocessor &PP,
/// #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::HandlePragma(Preprocessor &PP,
// 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
diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp
index e39a65c6ce0..6eb9b286280 100644
--- a/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/clang/lib/Sema/SemaStmtAttr.cpp
@@ -87,6 +87,9 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A,
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, Stmt *St, const ParsedAttr &A,
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, Stmt *St, const ParsedAttr &A,
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, Stmt *St, const ParsedAttr &A,
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
diff --git a/clang/test/CodeGenCXX/pragma-unroll-and-jam.cpp b/clang/test/CodeGenCXX/pragma-unroll-and-jam.cpp
new file mode 100644
index 00000000000..98421260345
--- /dev/null
+++ b/clang/test/CodeGenCXX/pragma-unroll-and-jam.cpp
@@ -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}
diff --git a/clang/test/Parser/pragma-unroll-and-jam.cpp b/clang/test/Parser/pragma-unroll-and-jam.cpp
new file mode 100644
index 00000000000..391d6b23ead
--- /dev/null
+++ b/clang/test/Parser/pragma-unroll-and-jam.cpp
@@ -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}} */ }