[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



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@338566 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Green 2018-08-01 14:36:12 +00:00
parent d6aa2b1c1a
commit 2f6d0b8d50
8 changed files with 292 additions and 33 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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(); }

View File

@ -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

View File

@ -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,18 +184,20 @@ 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}};
@ -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

View File

@ -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}

View File

@ -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}} */ }